diff --git a/src/core/Linux.zig b/src/core/Linux.zig index 87bfb16e61..fde006f241 100644 --- a/src/core/Linux.zig +++ b/src/core/Linux.zig @@ -49,7 +49,7 @@ backend: Backend, // 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 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( 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 switch (desired_backend) { - .x11 => blk: { - const x11 = X11.init(linux, core, options) catch |err| { + .x11 => { + X11.init(linux, core, options) catch |err| { const err_msg = switch (err) { error.LibraryNotFound => "Missing X11 library", error.FailedToConnectToDisplay => "Failed to connect to X11 display", else => "An unknown error occured while trying to connect to X11", }; log.err("{s}\n\nFalling back to Wayland\n", .{err_msg}); - linux.backend = .{ .wayland = try Wayland.init(linux, core, options) }; - break :blk; + try Wayland.init(linux, core, options); }; - linux.backend = .{ .x11 = x11 }; }, - .wayland => blk: { - const wayland = Wayland.init(linux, core, options) catch |err| { + .wayland => { + Wayland.init(linux, core, options) catch |err| { const err_msg = switch (err) { error.NoServerSideDecorationSupport => "Server Side Decorations aren't supported", error.LibraryNotFound => "Missing Wayland library", @@ -109,10 +107,8 @@ pub fn init( else => "An unknown error occured while trying to connect to Wayland", }; log.err("{s}\n\nFalling back to X11\n", .{err_msg}); - linux.backend = .{ .x11 = try X11.init(linux, core, options) }; - break :blk; + try X11.init(linux, core, options); }; - linux.backend = .{ .wayland = wayland }; }, } @@ -144,7 +140,7 @@ pub fn deinit(linux: *Linux) void { pub fn update(linux: *Linux) !void { switch (linux.backend) { - .wayland => {}, + .wayland => try linux.backend.wayland.update(), .x11 => try linux.backend.x11.update(), } return; diff --git a/src/core/linux/Wayland.zig b/src/core/linux/Wayland.zig index 87ccb83f19..e8ecc6f7fb 100644 --- a/src/core/linux/Wayland.zig +++ b/src/core/linux/Wayland.zig @@ -75,42 +75,45 @@ pub fn init( linux: *Linux, core: *Core.Mod, options: InitOptions, -) !Wayland { +) !void { libwaylandclient_global = try LibWaylandClient.load(); - var wl = Wayland{ - .core = @fieldParentPtr("platform", linux), - .state = core.state(), - .libxkbcommon = try LibXkbCommon.load(), - .libwaylandclient = libwaylandclient_global, - .interfaces = Interfaces{}, - .display = libwaylandclient_global.wl_display_connect(null) orelse return error.FailedToConnectToDisplay, - .title = try options.allocator.dupeZ(u8, options.title), - .size = &linux.size, - .modifiers = .{ - .alt = false, - .caps_lock = false, - .control = false, - .num_lock = false, - .shift = false, - .super = false, + linux.backend = .{ + .wayland = Wayland{ + .core = @fieldParentPtr("platform", linux), + .state = core.state(), + .libxkbcommon = try LibXkbCommon.load(), + .libwaylandclient = libwaylandclient_global, + .interfaces = Interfaces{}, + .display = libwaylandclient_global.wl_display_connect(null) orelse return error.FailedToConnectToDisplay, + .title = try options.allocator.dupeZ(u8, options.title), + .size = &linux.size, + .modifiers = .{ + .alt = false, + .caps_lock = false, + .control = false, + .num_lock = 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; const registry = c.wl_display_get_registry(wl.display) orelse return error.FailedToGetDisplayRegistry; // TODO: handle error return value here - _ = c.wl_registry_add_listener(registry, ®istry_listener.listener, &wl); + _ = c.wl_registry_add_listener(registry, ®istry_listener.listener, wl); //Round trip to get all the registry objects _ = 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; // 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 - _ = 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 c.wl_surface_commit(wl.surface); @@ -170,8 +173,6 @@ pub fn init( c.wl_surface_commit(wl.surface); // TODO: handle return value _ = wl.libwaylandclient.wl_display_roundtrip(wl.display); - - return wl; } pub fn deinit( @@ -182,6 +183,27 @@ pub fn deinit( } 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.core.input.tick(); @@ -399,8 +421,9 @@ const keyboard_listener = struct { //Close the 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).?; - defer wl.libxkbcommon.xkb_state_unref(state); //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"; diff --git a/src/core/linux/X11.zig b/src/core/linux/X11.zig index 8c22340d09..ef15e4c24c 100644 --- a/src/core/linux/X11.zig +++ b/src/core/linux/X11.zig @@ -83,7 +83,7 @@ pub fn init( linux: *Linux, core: *Core.Mod, options: InitOptions, -) !X11 { +) !void { // TODO(core): return errors.NotSupported if not supported const libx11 = try LibX11.load(); @@ -152,7 +152,7 @@ pub fn init( .display = display, .window = @intCast(window), }; - var x11 = X11{ + linux.backend = .{ .x11 = X11{ .core = @fieldParentPtr("platform", linux), .state = core.state(), .allocator = options.allocator, @@ -188,7 +188,8 @@ pub fn init( .cursors = std.mem.zeroes([@typeInfo(CursorShape).@"enum".fields.len]?c.Cursor), .surface_descriptor = surface_descriptor, .libxkbcommon = try LibXkbCommon.load(), - }; + } }; + var x11 = &linux.backend.x11; _ = libx11.XrmInitialize(); defer _ = libx11.XFreeColormap(display, colormap); for (0..2) |i| { @@ -239,7 +240,6 @@ pub fn init( } // TODO: remove allocation x11.cursors[@intFromEnum(CursorShape.arrow)] = try x11.createStandardCursor(.arrow); - return x11; } pub fn deinit(