x11: get x11 to build and run

This commit is contained in:
Joshua Holmes 2024-12-20 06:30:48 +00:00 committed by Emi Gutekanst
parent d6c387613d
commit 27aee7c036
2 changed files with 179 additions and 152 deletions

View file

@ -63,8 +63,9 @@ pub fn tick(core: *Core) !void {
while (windows.next()) |window_id| {
const native_opt: ?Native = core.windows.get(window_id, .native);
if (native_opt) |native| {
// check for display server events
switch (native) {
.x11 => {}, // X11.tick(window_id),
.x11 => try X11.tick(window_id),
.wayland => try Wayland.tick(window_id),
}
} else {
@ -83,6 +84,7 @@ pub fn initWindow(
"MACH_BACKEND",
) catch |err| switch (err) {
error.EnvironmentVariableNotFound => {
// default backend
break :blk .wayland;
},
else => return err,
@ -97,17 +99,15 @@ pub fn initWindow(
// Try to initialize the desired backend, falling back to the other if that one is not supported
switch (desired_backend) {
.x11 => {
log.err("\nX11 needs to be setup to work with the new object system, so it is not working at the moment. Using Wayland.\n", .{});
X11.initWindow(core, window_id) 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});
try Wayland.initWindow(core, window_id);
// X11.initWindow(core, window_id) 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});
// try Wayland.initWindow(core, window_id);
// };
};
},
.wayland => {
Wayland.initWindow(core, window_id) catch |err| {
@ -117,10 +117,8 @@ pub fn initWindow(
error.FailedToConnectToDisplay => "Failed to connect to Wayland display",
else => "An unknown error occured while trying to connect to Wayland",
};
log.err("{s}\n\nCannot connect to Wayland. X11 is unavailable as a fallback while it is being reconfigured to work with the new object system. Failing...\n", .{err_msg});
return error.X11NotImplemented;
// log.err("{s}\n\nFalling back to X11\n", .{err_msg});
// try X11.initWindow(core, window_id);
log.err("{s}\n\nFalling back to X11\n", .{err_msg});
try X11.initWindow(core, window_id);
};
},
}

View file

@ -30,44 +30,43 @@ const log = std.log.scoped(.mach);
pub const defaultLog = std.log.defaultLog;
pub const defaultPanic = std.debug.panicImpl;
pub const X11 = @This();
// TODO: determine if it's really needed to store global pointer
var core_ptr: *Core = undefined;
allocator: std.mem.Allocator,
core: *Core,
libx11: LibX11,
libxrr: ?LibXRR,
libgl: ?LibGL,
libxcursor: ?LibXCursor,
libxkbcommon: LibXkbCommon,
gl_ctx: ?*LibGL.Context,
pub const Native = struct {
backend_type: gpu.BackendType,
cursors: [@typeInfo(CursorShape).@"enum".fields.len]?c.Cursor,
display: *c.Display,
empty_event_pipe: [2]std.c.fd_t,
wm_protocols: c.Atom,
wm_delete_window: c.Atom,
net_wm_ping: c.Atom,
net_wm_bypass_compositor: c.Atom,
gl_ctx: ?*LibGL.Context,
hidden_cursor: c.Cursor,
libgl: ?LibGL,
libx11: LibX11,
libxcursor: ?LibXCursor,
libxkbcommon: LibXkbCommon,
libxrr: ?LibXRR,
motif_wm_hints: c.Atom,
net_wm_bypass_compositor: c.Atom,
net_wm_ping: c.Atom,
net_wm_window_type: c.Atom,
net_wm_window_type_dock: c.Atom,
root_window: c.Window,
surface_descriptor: gpu.Surface.DescriptorFromXlibWindow,
window: c.Window,
backend_type: gpu.BackendType,
hidden_cursor: c.Cursor,
wm_delete_window: c.Atom,
wm_protocols: c.Atom,
};
// Mutable fields only used by main thread
cursors: [@typeInfo(CursorShape).@"enum".fields.len]?c.Cursor,
// Mutable state fields; read/write by any thread
surface_descriptor: *gpu.Surface.DescriptorFromXlibWindow,
pub const Native = struct {};
pub fn init(
linux: *Linux,
pub fn initWindow(
core: *Core,
options: InitOptions,
window_id: mach.ObjectID,
) !void {
core_ptr = core;
var core_window = core.windows.getValue(window_id);
// TODO(core): return errors.NotSupported if not supported
const libx11 = try LibX11.load();
@ -95,7 +94,10 @@ pub fn init(
const screen = c.DefaultScreen(display);
const visual = c.DefaultVisual(display, screen);
const root_window = c.RootWindow(display, screen);
const colormap = libx11.XCreateColormap(display, root_window, visual, c.AllocNone);
defer _ = libx11.XFreeColormap(display, colormap);
var set_window_attrs = c.XSetWindowAttributes{
.colormap = colormap,
// TODO: reduce
@ -104,13 +106,15 @@ pub fn init(
c.ExposureMask | c.FocusChangeMask | c.VisibilityChangeMask |
c.EnterWindowMask | c.LeaveWindowMask | c.PropertyChangeMask,
};
const window = libx11.XCreateWindow(
// TODO: read error after function call and handle
const x_window_id = libx11.XCreateWindow(
display,
root_window,
@divFloor(libx11.XDisplayWidth(display, screen), 2), // TODO: add window width?
@divFloor(libx11.XDisplayHeight(display, screen), 2), // TODO: add window height?
linux.size.width,
linux.size.height,
core_window.width,
core_window.height,
0,
c.DefaultDepth(display, screen),
c.InputOutput,
@ -118,54 +122,47 @@ pub fn init(
c.CWColormap | c.CWEventMask,
&set_window_attrs,
);
var window_attrs: c.XWindowAttributes = undefined;
_ = libx11.XGetWindowAttributes(display, window, &window_attrs);
linux.size = Core.Size{
.width = @intCast(window_attrs.width),
.height = @intCast(window_attrs.height),
};
const blank_pixmap = libx11.XCreatePixmap(display, window, 1, 1, 1);
const blank_pixmap = libx11.XCreatePixmap(display, x_window_id, 1, 1, 1);
var color = c.XColor{};
linux.refresh_rate = blk: {
core_window.refresh_rate = blk: {
if (libxrr != null) {
const conf = libxrr.?.XRRGetScreenInfo(display, root_window);
break :blk @intCast(libxrr.?.XRRConfigCurrentRate(conf));
}
break :blk 60;
};
const surface_descriptor = try options.allocator.create(gpu.Surface.DescriptorFromXlibWindow);
surface_descriptor.* = .{
const surface_descriptor = gpu.Surface.DescriptorFromXlibWindow{ .display = display, .window = @intCast(x_window_id) };
core_window.surface_descriptor = .{ .next_in_chain = .{
.from_xlib_window = &surface_descriptor,
} };
core_window.native = .{ .x11 = .{
.backend_type = try Core.detectBackendType(core.allocator),
.cursors = std.mem.zeroes([@typeInfo(CursorShape).@"enum".fields.len]?c.Cursor),
.display = display,
.window = @intCast(window),
};
linux.backend = .{ .x11 = X11{
.core = core,
.allocator = options.allocator,
.display = display,
.libx11 = libx11,
.libgl = libgl,
.libxcursor = libxcursor,
.libxrr = libxrr,
.empty_event_pipe = try std.posix.pipe(),
.gl_ctx = null,
.wm_protocols = libx11.XInternAtom(display, "WM_PROTOCOLS", c.False),
.wm_delete_window = libx11.XInternAtom(display, "WM_DELETE_WINDOW", c.False),
.hidden_cursor = libx11.XCreatePixmapCursor(display, blank_pixmap, blank_pixmap, &color, &color, 0, 0),
.libgl = libgl,
.libx11 = libx11,
.libxcursor = libxcursor,
.libxkbcommon = try LibXkbCommon.load(),
.libxrr = libxrr,
.motif_wm_hints = libx11.XInternAtom(display, "_MOTIF_WM_HINTS", c.False),
.net_wm_bypass_compositor = libx11.XInternAtom(display, "_NET_WM_BYPASS_COMPOSITOR", c.False),
.net_wm_ping = libx11.XInternAtom(display, "NET_WM_PING", c.False),
.net_wm_window_type = libx11.XInternAtom(display, "_NET_WM_WINDOW_TYPE", c.False),
.net_wm_window_type_dock = libx11.XInternAtom(display, "_NET_WM_WINDOW_TYPE_DOCK", c.False),
.net_wm_bypass_compositor = libx11.XInternAtom(display, "_NET_WM_BYPASS_COMPOSITOR", c.False),
.motif_wm_hints = libx11.XInternAtom(display, "_MOTIF_WM_HINTS", c.False),
.root_window = root_window,
.window = window,
.hidden_cursor = libx11.XCreatePixmapCursor(display, blank_pixmap, blank_pixmap, &color, &color, 0, 0),
.backend_type = try Core.detectBackendType(options.allocator),
.cursors = std.mem.zeroes([@typeInfo(CursorShape).@"enum".fields.len]?c.Cursor),
.surface_descriptor = surface_descriptor,
.libxkbcommon = try LibXkbCommon.load(),
.window = x_window_id,
.wm_delete_window = libx11.XInternAtom(display, "WM_DELETE_WINDOW", c.False),
.wm_protocols = libx11.XInternAtom(display, "WM_PROTOCOLS", c.False),
} };
var x11 = &linux.backend.x11;
_ = libx11.XrmInitialize();
defer _ = libx11.XFreeColormap(display, colormap);
var x11 = &core_window.native.?.x11;
for (0..2) |i| {
const sf = try std.posix.fcntl(x11.empty_event_pipe[i], std.posix.F.GETFL, 0);
const df = try std.posix.fcntl(x11.empty_event_pipe[i], std.posix.F.GETFD, 0);
@ -174,11 +171,12 @@ pub fn init(
}
var protocols = [_]c.Atom{ x11.wm_delete_window, x11.net_wm_ping };
_ = libx11.XSetWMProtocols(x11.display, x11.window, &protocols, protocols.len);
_ = libx11.XStoreName(x11.display, x11.window, options.title.ptr);
_ = libx11.XStoreName(x11.display, x11.window, core_window.title);
_ = libx11.XSelectInput(x11.display, x11.window, set_window_attrs.event_mask);
_ = libx11.XMapWindow(x11.display, x11.window);
_ = libx11.XGetWindowAttributes(x11.display, x11.window, &window_attrs);
const backend_type = try Core.detectBackendType(options.allocator);
// TODO: see if this can be removed
const backend_type = try Core.detectBackendType(core.allocator);
switch (backend_type) {
.opengl, .opengles => {
if (libgl != null) {
@ -206,66 +204,73 @@ pub fn init(
},
else => {},
}
// Create hidden cursor
const gc = libx11.XCreateGC(x11.display, blank_pixmap, 0, null);
if (gc != null) {
_ = libx11.XDrawPoint(x11.display, blank_pixmap, gc, 0, 0);
_ = libx11.XFreeGC(x11.display, gc);
}
// TODO: remove allocation
x11.cursors[@intFromEnum(CursorShape.arrow)] = try x11.createStandardCursor(.arrow);
x11.cursors[@intFromEnum(CursorShape.arrow)] = try createStandardCursor(x11, .arrow);
core.windows.setValue(window_id, core_window);
try core.initWindow(window_id);
}
pub fn deinit(
x11: *X11,
linux: *Linux,
) void {
linux.allocator.destroy(x11.surface_descriptor);
for (x11.cursors) |cur| {
if (cur) |_| {
// _ = x11.libx11.XFreeCursor(x11.display, cur.?);
}
}
if (x11.libxcursor) |*libxcursor| {
libxcursor.handle.close();
}
if (x11.libxrr) |*libxrr| {
libxrr.handle.close();
}
if (x11.libgl) |*libgl| {
if (x11.gl_ctx) |gl_ctx| {
libgl.glXDestroyContext(x11.display, gl_ctx);
}
libgl.handle.close();
}
_ = x11.libx11.XUnmapWindow(x11.display, x11.window);
_ = x11.libx11.XDestroyWindow(x11.display, x11.window);
_ = x11.libx11.XCloseDisplay(x11.display);
x11.libx11.handle.close();
std.posix.close(x11.empty_event_pipe[0]);
std.posix.close(x11.empty_event_pipe[1]);
}
// pub fn deinit(
// x11: *X11,
// linux: *Linux,
// ) void {
// linux.allocator.destroy(x11.surface_descriptor);
// for (x11.cursors) |cur| {
// if (cur) |_| {
// // _ = x11.libx11.XFreeCursor(x11.display, cur.?);
// }
// }
// if (x11.libxcursor) |*libxcursor| {
// libxcursor.handle.close();
// }
// if (x11.libxrr) |*libxrr| {
// libxrr.handle.close();
// }
// if (x11.libgl) |*libgl| {
// if (x11.gl_ctx) |gl_ctx| {
// libgl.glXDestroyContext(x11.display, gl_ctx);
// }
// libgl.handle.close();
// }
// _ = x11.libx11.XUnmapWindow(x11.display, x11.window);
// _ = x11.libx11.XDestroyWindow(x11.display, x11.window);
// _ = x11.libx11.XCloseDisplay(x11.display);
// x11.libx11.handle.close();
// std.posix.close(x11.empty_event_pipe[0]);
// std.posix.close(x11.empty_event_pipe[1]);
// }
// Called on the main thread
pub fn update(x11: *X11, linux: *Linux) !void {
pub fn tick(window_id: mach.ObjectID) !void {
var core_window = core_ptr.windows.getValue(window_id);
var x11 = &core_window.native.?.x11;
while (c.QLength(x11.display) != 0) {
var event: c.XEvent = undefined;
_ = x11.libx11.XNextEvent(x11.display, &event);
x11.processEvent(linux, &event);
processEvent(window_id, &event);
// update in case core_window was changed
core_window = core_ptr.windows.getValue(window_id);
x11 = &core_window.native.?.x11;
}
_ = x11.libx11.XFlush(x11.display);
// const frequency_delay = @as(f32, @floatFromInt(x11.input.delay_ns)) / @as(f32, @floatFromInt(std.time.ns_per_s));
// TODO: glfw.waitEventsTimeout(frequency_delay);
x11.core.input.tick();
}
pub fn setTitle(x11: *X11, title: [:0]const u8) void {
pub fn setTitle(x11: *const Native, title: [:0]const u8) void {
_ = x11.libx11.XStoreName(x11.display, x11.window, title);
}
pub fn setDisplayMode(x11: *X11, linux: *Linux, display_mode: DisplayMode) void {
pub fn setDisplayMode(x11: *const Native, display_mode: DisplayMode, border: bool) void {
const wm_state = x11.libx11.XInternAtom(x11.display, "_NET_WM_STATE", c.False);
const wm_fullscreen = x11.libx11.XInternAtom(x11.display, "_NET_WM_STATE_FULLSCREEN", c.False);
switch (display_mode) {
@ -290,7 +295,7 @@ pub fn setDisplayMode(x11: *X11, linux: *Linux, display_mode: DisplayMode) void
@intCast(atoms.len),
);
x11.setFullscreen(false);
x11.setDecorated(linux.border);
x11.setDecorated(border);
x11.setFloating(false);
_ = x11.libx11.XMapWindow(x11.display, x11.window);
_ = x11.libx11.XFlush(x11.display);
@ -314,7 +319,7 @@ pub fn setDisplayMode(x11: *X11, linux: *Linux, display_mode: DisplayMode) void
}
}
fn setFullscreen(x11: *X11, enabled: bool) void {
fn setFullscreen(x11: *const Native, enabled: bool) void {
const wm_state = x11.libx11.XInternAtom(x11.display, "_NET_WM_STATE", c.False);
const wm_fullscreen = x11.libx11.XInternAtom(x11.display, "_NET_WM_STATE_FULLSCREEN", c.False);
x11.sendEventToWM(wm_state, &.{ @intFromBool(enabled), @intCast(wm_fullscreen), 0, 1 });
@ -335,7 +340,7 @@ fn setFullscreen(x11: *X11, enabled: bool) void {
}
}
fn setFloating(x11: *X11, enabled: bool) void {
fn setFloating(x11: *const Native, enabled: bool) void {
const wm_state = x11.libx11.XInternAtom(x11.display, "_NET_WM_STATE", c.False);
const wm_above = x11.libx11.XInternAtom(x11.display, "_NET_WM_STATE_ABOVE", c.False);
const net_wm_state_remove = 0;
@ -344,7 +349,7 @@ fn setFloating(x11: *X11, enabled: bool) void {
x11.sendEventToWM(wm_state, &.{ action, @intCast(wm_above), 0, 1 });
}
fn sendEventToWM(x11: *X11, message_type: c.Atom, data: []const c_long) void {
fn sendEventToWM(x11: *const Native, message_type: c.Atom, data: []const c_long) void {
var ev = std.mem.zeroes(c.XEvent);
ev.type = c.ClientMessage;
ev.xclient.window = x11.window;
@ -361,7 +366,7 @@ fn sendEventToWM(x11: *X11, message_type: c.Atom, data: []const c_long) void {
_ = x11.libx11.XFlush(x11.display);
}
fn setDecorated(x11: *X11, enabled: bool) void {
fn setDecorated(x11: *const Native, enabled: bool) void {
const MWMHints = struct {
flags: u32,
functions: u32,
@ -546,7 +551,7 @@ const LibXkbCommon = struct {
}
};
fn createStandardCursor(x11: *X11, shape: CursorShape) !c.Cursor {
fn createStandardCursor(x11: *const Native, shape: CursorShape) !c.Cursor {
if (x11.libxcursor) |libxcursor| {
const theme = libxcursor.XcursorGetTheme(x11.display);
if (theme != null) {
@ -587,7 +592,7 @@ fn createStandardCursor(x11: *X11, shape: CursorShape) !c.Cursor {
return cursor;
}
fn getCursorPos(x11: *X11) Position {
fn getCursorPos(x11: *const Native) Position {
var root_window: c.Window = undefined;
var child_window: c.Window = undefined;
var root_cursor_x: c_int = 0;
@ -610,7 +615,10 @@ fn getCursorPos(x11: *X11) Position {
return .{ .x = @floatFromInt(cursor_x), .y = @floatFromInt(cursor_y) };
}
fn processEvent(x11: *X11, linux: *Linux, event: *c.XEvent) void {
/// Handle XEvents. Window object can be modified.
fn processEvent(window_id: mach.ObjectID, event: *c.XEvent) void {
var core_window = core_ptr.windows.getValue(window_id);
const x11 = &core_window.native.?.x11;
switch (event.type) {
c.KeyPress, c.KeyRelease => {
// TODO: key repeat event
@ -618,19 +626,23 @@ fn processEvent(x11: *X11, linux: *Linux, event: *c.XEvent) void {
var keysym: c.KeySym = undefined;
_ = x11.libx11.XLookupString(&event.xkey, null, 0, &keysym, null);
const key_event = KeyEvent{ .key = toMachKey(keysym), .mods = toMachMods(event.xkey.state) };
const key_event = KeyEvent{
.key = toMachKey(keysym),
.mods = toMachMods(event.xkey.state),
.window_id = window_id,
};
switch (event.type) {
c.KeyPress => {
x11.core.pushEvent(.{ .key_press = key_event });
core_ptr.pushEvent(.{ .key_press = key_event });
const codepoint = x11.libxkbcommon.xkb_keysym_to_utf32(@truncate(keysym));
if (codepoint != 0) {
x11.core.pushEvent(.{ .char_input = .{ .codepoint = @truncate(codepoint) } });
core_ptr.pushEvent(.{ .char_input = .{ .codepoint = @truncate(codepoint), .window_id = window_id } });
}
},
c.KeyRelease => {
x11.core.pushEvent(.{ .key_release = key_event });
core_ptr.pushEvent(.{ .key_release = key_event });
},
else => unreachable,
}
@ -645,28 +657,30 @@ fn processEvent(x11: *X11, linux: *Linux, event: *c.XEvent) void {
7 => .{ -1.0, 0.0 },
else => unreachable,
};
x11.core.pushEvent(.{ .mouse_scroll = .{ .xoffset = scroll[0], .yoffset = scroll[1] } });
core_ptr.pushEvent(.{ .mouse_scroll = .{ .xoffset = scroll[0], .yoffset = scroll[1], .window_id = window_id } });
return;
};
const cursor_pos = x11.getCursorPos();
const cursor_pos = getCursorPos(x11);
const mouse_button = MouseButtonEvent{
.button = button,
.pos = cursor_pos,
.mods = toMachMods(event.xbutton.state),
.window_id = window_id,
};
x11.core.pushEvent(.{ .mouse_press = mouse_button });
core_ptr.pushEvent(.{ .mouse_press = mouse_button });
},
c.ButtonRelease => {
const button = toMachButton(event.xbutton.button) orelse return;
const cursor_pos = x11.getCursorPos();
const cursor_pos = getCursorPos(x11);
const mouse_button = MouseButtonEvent{
.button = button,
.pos = cursor_pos,
.mods = toMachMods(event.xbutton.state),
.window_id = window_id,
};
x11.core.pushEvent(.{ .mouse_release = mouse_button });
core_ptr.pushEvent(.{ .mouse_release = mouse_button });
},
c.ClientMessage => {
if (event.xclient.message_type == c.None) return;
@ -676,7 +690,7 @@ fn processEvent(x11: *X11, linux: *Linux, event: *c.XEvent) void {
if (protocol == c.None) return;
if (protocol == x11.wm_delete_window) {
x11.core.pushEvent(.close);
core_ptr.pushEvent(.{ .close = .{ .window_id = window_id } });
} else if (protocol == x11.net_wm_ping) {
// The window manager is pinging the application to ensure
// it's still responding to events
@ -695,26 +709,33 @@ fn processEvent(x11: *X11, linux: *Linux, event: *c.XEvent) void {
c.EnterNotify => {
const x: f32 = @floatFromInt(event.xcrossing.x);
const y: f32 = @floatFromInt(event.xcrossing.y);
x11.core.pushEvent(.{ .mouse_motion = .{ .pos = .{ .x = x, .y = y } } });
core_ptr.pushEvent(.{ .mouse_motion = .{ .pos = .{ .x = x, .y = y }, .window_id = window_id } });
},
c.MotionNotify => {
const x: f32 = @floatFromInt(event.xmotion.x);
const y: f32 = @floatFromInt(event.xmotion.y);
x11.core.pushEvent(.{ .mouse_motion = .{ .pos = .{ .x = x, .y = y } } });
core_ptr.pushEvent(.{ .mouse_motion = .{ .pos = .{ .x = x, .y = y }, .window_id = window_id } });
},
c.ConfigureNotify => {
if (event.xconfigure.width != linux.size.width or
event.xconfigure.height != linux.size.height)
if (event.xconfigure.width != core_window.width or
event.xconfigure.height != core_window.height)
{
linux.size.width = @intCast(event.xconfigure.width);
linux.size.height = @intCast(event.xconfigure.height);
x11.core.swap_chain_update.set();
x11.core.pushEvent(.{
.framebuffer_resize = .{
.width = linux.size.width,
.height = linux.size.height,
core_window.width = @intCast(event.xconfigure.width);
core_window.height = @intCast(event.xconfigure.height);
// FIX: What is the Mach Object System way of doing this?
// core_ptr.swap_chain_update.set();
core_ptr.pushEvent(.{
.window_resize = .{
.size = Core.Size{
.width = core_window.width,
.height = core_window.height,
},
.window_id = window_id,
},
});
core_ptr.windows.setValue(window_id, core_window);
}
},
c.FocusIn => {
@ -726,7 +747,7 @@ fn processEvent(x11: *X11, linux: *Linux, event: *c.XEvent) void {
return;
}
x11.core.pushEvent(.focus_gained);
core_ptr.pushEvent(.{ .focus_gained = .{ .window_id = window_id } });
},
c.FocusOut => {
if (event.xfocus.mode == c.NotifyGrab or
@ -737,7 +758,15 @@ fn processEvent(x11: *X11, linux: *Linux, event: *c.XEvent) void {
return;
}
x11.core.pushEvent(.focus_lost);
core_ptr.pushEvent(.{ .focus_lost = .{ .window_id = window_id } });
},
c.ResizeRequest => {
_ = x11.libx11.XResizeWindow(
x11.display,
x11.window,
@intCast(c.DisplayWidth(x11.display, c.DefaultScreen(x11.display))),
@intCast(c.DisplayHeight(x11.display, c.DefaultScreen(x11.display))),
);
},
else => {},
}