core: wayland: implement keyboard input & window resizing (#1293)

This commit is contained in:
Joshua Holmes 2024-11-09 10:33:42 -08:00 committed by GitHub
parent 51e6899505
commit 06f61044fb
Failed to generate hash of commit
3 changed files with 69 additions and 50 deletions

View file

@ -49,7 +49,7 @@ backend: Backend,
// these arrays are used as info messages to the user that some features are missing // these arrays are used as info messages to the user that some features are missing
// please keep these up to date until we can remove them // please keep these up to date until we can remove them
const MISSING_FEATURES_X11 = [_][]const u8{ "Resizing window", "Changing display mode", "VSync", "Setting window border/title/cursor" }; const MISSING_FEATURES_X11 = [_][]const u8{ "Resizing window", "Changing display mode", "VSync", "Setting window border/title/cursor" };
const MISSING_FEATURES_WAYLAND = [_][]const u8{ "Resizing window", "Keyboard input", "Changing display mode", "VSync", "Setting window border/title/cursor" }; const MISSING_FEATURES_WAYLAND = [_][]const u8{ "Changing display mode", "VSync", "Setting window border/title/cursor" };
pub fn init( pub fn init(
linux: *Linux, linux: *Linux,
@ -87,21 +87,19 @@ pub fn init(
// Try to initialize the desired backend, falling back to the other if that one is not supported // Try to initialize the desired backend, falling back to the other if that one is not supported
switch (desired_backend) { switch (desired_backend) {
.x11 => blk: { .x11 => {
const x11 = X11.init(linux, core, options) catch |err| { X11.init(linux, core, options) catch |err| {
const err_msg = switch (err) { const err_msg = switch (err) {
error.LibraryNotFound => "Missing X11 library", error.LibraryNotFound => "Missing X11 library",
error.FailedToConnectToDisplay => "Failed to connect to X11 display", error.FailedToConnectToDisplay => "Failed to connect to X11 display",
else => "An unknown error occured while trying to connect to X11", else => "An unknown error occured while trying to connect to X11",
}; };
log.err("{s}\n\nFalling back to Wayland\n", .{err_msg}); log.err("{s}\n\nFalling back to Wayland\n", .{err_msg});
linux.backend = .{ .wayland = try Wayland.init(linux, core, options) }; try Wayland.init(linux, core, options);
break :blk;
}; };
linux.backend = .{ .x11 = x11 };
}, },
.wayland => blk: { .wayland => {
const wayland = Wayland.init(linux, core, options) catch |err| { Wayland.init(linux, core, options) catch |err| {
const err_msg = switch (err) { const err_msg = switch (err) {
error.NoServerSideDecorationSupport => "Server Side Decorations aren't supported", error.NoServerSideDecorationSupport => "Server Side Decorations aren't supported",
error.LibraryNotFound => "Missing Wayland library", error.LibraryNotFound => "Missing Wayland library",
@ -109,10 +107,8 @@ pub fn init(
else => "An unknown error occured while trying to connect to Wayland", else => "An unknown error occured while trying to connect to Wayland",
}; };
log.err("{s}\n\nFalling back to X11\n", .{err_msg}); log.err("{s}\n\nFalling back to X11\n", .{err_msg});
linux.backend = .{ .x11 = try X11.init(linux, core, options) }; try X11.init(linux, core, options);
break :blk;
}; };
linux.backend = .{ .wayland = wayland };
}, },
} }
@ -144,7 +140,7 @@ pub fn deinit(linux: *Linux) void {
pub fn update(linux: *Linux) !void { pub fn update(linux: *Linux) !void {
switch (linux.backend) { switch (linux.backend) {
.wayland => {}, .wayland => try linux.backend.wayland.update(),
.x11 => try linux.backend.x11.update(), .x11 => try linux.backend.x11.update(),
} }
return; return;

View file

@ -75,42 +75,45 @@ pub fn init(
linux: *Linux, linux: *Linux,
core: *Core.Mod, core: *Core.Mod,
options: InitOptions, options: InitOptions,
) !Wayland { ) !void {
libwaylandclient_global = try LibWaylandClient.load(); libwaylandclient_global = try LibWaylandClient.load();
var wl = Wayland{ linux.backend = .{
.core = @fieldParentPtr("platform", linux), .wayland = Wayland{
.state = core.state(), .core = @fieldParentPtr("platform", linux),
.libxkbcommon = try LibXkbCommon.load(), .state = core.state(),
.libwaylandclient = libwaylandclient_global, .libxkbcommon = try LibXkbCommon.load(),
.interfaces = Interfaces{}, .libwaylandclient = libwaylandclient_global,
.display = libwaylandclient_global.wl_display_connect(null) orelse return error.FailedToConnectToDisplay, .interfaces = Interfaces{},
.title = try options.allocator.dupeZ(u8, options.title), .display = libwaylandclient_global.wl_display_connect(null) orelse return error.FailedToConnectToDisplay,
.size = &linux.size, .title = try options.allocator.dupeZ(u8, options.title),
.modifiers = .{ .size = &linux.size,
.alt = false, .modifiers = .{
.caps_lock = false, .alt = false,
.control = false, .caps_lock = false,
.num_lock = false, .control = false,
.shift = false, .num_lock = false,
.super = false, .shift = false,
.super = false,
},
.input_state = .{},
.modifier_indices = .{ // TODO: make sure these are always getting initialized, we don't want undefined behavior
.control_index = undefined,
.alt_index = undefined,
.shift_index = undefined,
.super_index = undefined,
.caps_lock_index = undefined,
.num_lock_index = undefined,
},
.surface_descriptor = undefined,
.surface = undefined,
}, },
.input_state = .{},
.modifier_indices = .{ // TODO: make sure these are always getting initialized, we don't want undefined behavior
.control_index = undefined,
.alt_index = undefined,
.shift_index = undefined,
.super_index = undefined,
.caps_lock_index = undefined,
.num_lock_index = undefined,
},
.surface_descriptor = undefined,
.surface = undefined,
}; };
var wl = &linux.backend.wayland;
wl.xkb_context = wl.libxkbcommon.xkb_context_new(0) orelse return error.FailedToGetXkbContext; wl.xkb_context = wl.libxkbcommon.xkb_context_new(0) orelse return error.FailedToGetXkbContext;
const registry = c.wl_display_get_registry(wl.display) orelse return error.FailedToGetDisplayRegistry; const registry = c.wl_display_get_registry(wl.display) orelse return error.FailedToGetDisplayRegistry;
// TODO: handle error return value here // TODO: handle error return value here
_ = c.wl_registry_add_listener(registry, &registry_listener.listener, &wl); _ = c.wl_registry_add_listener(registry, &registry_listener.listener, wl);
//Round trip to get all the registry objects //Round trip to get all the registry objects
_ = wl.libwaylandclient.wl_display_roundtrip(wl.display); _ = wl.libwaylandclient.wl_display_roundtrip(wl.display);
@ -145,10 +148,10 @@ pub fn init(
const toplevel = c.xdg_surface_get_toplevel(xdg_surface) orelse return error.UnableToGetXdgTopLevel; const toplevel = c.xdg_surface_get_toplevel(xdg_surface) orelse return error.UnableToGetXdgTopLevel;
// TODO: handle this return value // TODO: handle this return value
_ = c.xdg_surface_add_listener(xdg_surface, &xdg_surface_listener.listener, &wl); _ = c.xdg_surface_add_listener(xdg_surface, &xdg_surface_listener.listener, wl);
// TODO: handle this return value // TODO: handle this return value
_ = c.xdg_toplevel_add_listener(toplevel, &xdg_toplevel_listener.listener, &wl); _ = c.xdg_toplevel_add_listener(toplevel, &xdg_toplevel_listener.listener, wl);
// Commit changes to surface // Commit changes to surface
c.wl_surface_commit(wl.surface); c.wl_surface_commit(wl.surface);
@ -170,8 +173,6 @@ pub fn init(
c.wl_surface_commit(wl.surface); c.wl_surface_commit(wl.surface);
// TODO: handle return value // TODO: handle return value
_ = wl.libwaylandclient.wl_display_roundtrip(wl.display); _ = wl.libwaylandclient.wl_display_roundtrip(wl.display);
return wl;
} }
pub fn deinit( pub fn deinit(
@ -182,6 +183,27 @@ pub fn deinit(
} }
pub fn update(wl: *Wayland) !void { pub fn update(wl: *Wayland) !void {
while (wl.libwaylandclient.wl_display_flush(wl.display) == -1) {
if (std.posix.errno(-1) == std.posix.E.AGAIN) {
log.err("flush error", .{});
return error.FlushError;
}
var pollfd = [_]std.posix.pollfd{
std.posix.pollfd{
.fd = wl.libwaylandclient.wl_display_get_fd(wl.display),
.events = std.posix.POLL.OUT,
.revents = 0,
},
};
while (try std.posix.poll(&pollfd, 1) == -1) {
const errno = std.posix.errno(-1);
if (errno == std.posix.E.INTR or errno == std.posix.E.AGAIN) {
log.err("poll error", .{});
return error.PollError;
}
}
}
_ = wl.libwaylandclient.wl_display_roundtrip(wl.display); _ = wl.libwaylandclient.wl_display_roundtrip(wl.display);
wl.core.input.tick(); wl.core.input.tick();
@ -399,8 +421,9 @@ const keyboard_listener = struct {
//Close the fd //Close the fd
std.posix.close(fd); std.posix.close(fd);
//Release reference to old state and create new state
wl.libxkbcommon.xkb_state_unref(wl.xkb_state);
const state = wl.libxkbcommon.xkb_state_new(keymap).?; const state = wl.libxkbcommon.xkb_state_new(keymap).?;
defer wl.libxkbcommon.xkb_state_unref(state);
//this chain hurts me. why must C be this way. //this chain hurts me. why must C be this way.
const locale = std.posix.getenv("LC_ALL") orelse std.posix.getenv("LC_CTYPE") orelse std.posix.getenv("LANG") orelse "C"; const locale = std.posix.getenv("LC_ALL") orelse std.posix.getenv("LC_CTYPE") orelse std.posix.getenv("LANG") orelse "C";

View file

@ -83,7 +83,7 @@ pub fn init(
linux: *Linux, linux: *Linux,
core: *Core.Mod, core: *Core.Mod,
options: InitOptions, options: InitOptions,
) !X11 { ) !void {
// TODO(core): return errors.NotSupported if not supported // TODO(core): return errors.NotSupported if not supported
const libx11 = try LibX11.load(); const libx11 = try LibX11.load();
@ -152,7 +152,7 @@ pub fn init(
.display = display, .display = display,
.window = @intCast(window), .window = @intCast(window),
}; };
var x11 = X11{ linux.backend = .{ .x11 = X11{
.core = @fieldParentPtr("platform", linux), .core = @fieldParentPtr("platform", linux),
.state = core.state(), .state = core.state(),
.allocator = options.allocator, .allocator = options.allocator,
@ -188,7 +188,8 @@ pub fn init(
.cursors = std.mem.zeroes([@typeInfo(CursorShape).@"enum".fields.len]?c.Cursor), .cursors = std.mem.zeroes([@typeInfo(CursorShape).@"enum".fields.len]?c.Cursor),
.surface_descriptor = surface_descriptor, .surface_descriptor = surface_descriptor,
.libxkbcommon = try LibXkbCommon.load(), .libxkbcommon = try LibXkbCommon.load(),
}; } };
var x11 = &linux.backend.x11;
_ = libx11.XrmInitialize(); _ = libx11.XrmInitialize();
defer _ = libx11.XFreeColormap(display, colormap); defer _ = libx11.XFreeColormap(display, colormap);
for (0..2) |i| { for (0..2) |i| {
@ -239,7 +240,6 @@ pub fn init(
} }
// TODO: remove allocation // TODO: remove allocation
x11.cursors[@intFromEnum(CursorShape.arrow)] = try x11.createStandardCursor(.arrow); x11.cursors[@intFromEnum(CursorShape.arrow)] = try x11.createStandardCursor(.arrow);
return x11;
} }
pub fn deinit( pub fn deinit(