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| { while (windows.next()) |window_id| {
const native_opt: ?Native = core.windows.get(window_id, .native); const native_opt: ?Native = core.windows.get(window_id, .native);
if (native_opt) |native| { if (native_opt) |native| {
// check for display server events
switch (native) { switch (native) {
.x11 => {}, // X11.tick(window_id), .x11 => try X11.tick(window_id),
.wayland => try Wayland.tick(window_id), .wayland => try Wayland.tick(window_id),
} }
} else { } else {
@ -83,6 +84,7 @@ pub fn initWindow(
"MACH_BACKEND", "MACH_BACKEND",
) catch |err| switch (err) { ) catch |err| switch (err) {
error.EnvironmentVariableNotFound => { error.EnvironmentVariableNotFound => {
// default backend
break :blk .wayland; break :blk .wayland;
}, },
else => return err, 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 // Try to initialize the desired backend, falling back to the other if that one is not supported
switch (desired_backend) { switch (desired_backend) {
.x11 => { .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); 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 => {
Wayland.initWindow(core, window_id) catch |err| { Wayland.initWindow(core, window_id) catch |err| {
@ -117,10 +117,8 @@ pub fn initWindow(
error.FailedToConnectToDisplay => "Failed to connect to Wayland display", error.FailedToConnectToDisplay => "Failed to connect to Wayland display",
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\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}); log.err("{s}\n\nFalling back to X11\n", .{err_msg});
return error.X11NotImplemented; 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 defaultLog = std.log.defaultLog;
pub const defaultPanic = std.debug.panicImpl; 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, pub const Native = struct {
core: *Core, backend_type: gpu.BackendType,
cursors: [@typeInfo(CursorShape).@"enum".fields.len]?c.Cursor,
libx11: LibX11, display: *c.Display,
libxrr: ?LibXRR, empty_event_pipe: [2]std.c.fd_t,
libgl: ?LibGL, gl_ctx: ?*LibGL.Context,
libxcursor: ?LibXCursor, hidden_cursor: c.Cursor,
libxkbcommon: LibXkbCommon, libgl: ?LibGL,
gl_ctx: ?*LibGL.Context, libx11: LibX11,
display: *c.Display, libxcursor: ?LibXCursor,
empty_event_pipe: [2]std.c.fd_t, libxkbcommon: LibXkbCommon,
wm_protocols: c.Atom, libxrr: ?LibXRR,
wm_delete_window: c.Atom, motif_wm_hints: c.Atom,
net_wm_ping: c.Atom, net_wm_bypass_compositor: c.Atom,
net_wm_bypass_compositor: c.Atom, net_wm_ping: c.Atom,
motif_wm_hints: c.Atom, net_wm_window_type: c.Atom,
net_wm_window_type: c.Atom, net_wm_window_type_dock: c.Atom,
net_wm_window_type_dock: c.Atom, root_window: c.Window,
root_window: c.Window, surface_descriptor: gpu.Surface.DescriptorFromXlibWindow,
window: c.Window, window: c.Window,
backend_type: gpu.BackendType, wm_delete_window: c.Atom,
hidden_cursor: c.Cursor, wm_protocols: c.Atom,
};
// Mutable fields only used by main thread // Mutable fields only used by main thread
cursors: [@typeInfo(CursorShape).@"enum".fields.len]?c.Cursor,
// Mutable state fields; read/write by any thread // Mutable state fields; read/write by any thread
surface_descriptor: *gpu.Surface.DescriptorFromXlibWindow,
pub const Native = struct {}; pub fn initWindow(
pub fn init(
linux: *Linux,
core: *Core, core: *Core,
options: InitOptions, window_id: mach.ObjectID,
) !void { ) !void {
core_ptr = core;
var core_window = core.windows.getValue(window_id);
// 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();
@ -95,7 +94,10 @@ pub fn init(
const screen = c.DefaultScreen(display); const screen = c.DefaultScreen(display);
const visual = c.DefaultVisual(display, screen); const visual = c.DefaultVisual(display, screen);
const root_window = c.RootWindow(display, screen); const root_window = c.RootWindow(display, screen);
const colormap = libx11.XCreateColormap(display, root_window, visual, c.AllocNone); const colormap = libx11.XCreateColormap(display, root_window, visual, c.AllocNone);
defer _ = libx11.XFreeColormap(display, colormap);
var set_window_attrs = c.XSetWindowAttributes{ var set_window_attrs = c.XSetWindowAttributes{
.colormap = colormap, .colormap = colormap,
// TODO: reduce // TODO: reduce
@ -104,13 +106,15 @@ pub fn init(
c.ExposureMask | c.FocusChangeMask | c.VisibilityChangeMask | c.ExposureMask | c.FocusChangeMask | c.VisibilityChangeMask |
c.EnterWindowMask | c.LeaveWindowMask | c.PropertyChangeMask, 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, display,
root_window, root_window,
@divFloor(libx11.XDisplayWidth(display, screen), 2), // TODO: add window width? @divFloor(libx11.XDisplayWidth(display, screen), 2), // TODO: add window width?
@divFloor(libx11.XDisplayHeight(display, screen), 2), // TODO: add window height? @divFloor(libx11.XDisplayHeight(display, screen), 2), // TODO: add window height?
linux.size.width, core_window.width,
linux.size.height, core_window.height,
0, 0,
c.DefaultDepth(display, screen), c.DefaultDepth(display, screen),
c.InputOutput, c.InputOutput,
@ -118,54 +122,47 @@ pub fn init(
c.CWColormap | c.CWEventMask, c.CWColormap | c.CWEventMask,
&set_window_attrs, &set_window_attrs,
); );
var window_attrs: c.XWindowAttributes = undefined;
_ = libx11.XGetWindowAttributes(display, window, &window_attrs); const blank_pixmap = libx11.XCreatePixmap(display, x_window_id, 1, 1, 1);
linux.size = Core.Size{
.width = @intCast(window_attrs.width),
.height = @intCast(window_attrs.height),
};
const blank_pixmap = libx11.XCreatePixmap(display, window, 1, 1, 1);
var color = c.XColor{}; var color = c.XColor{};
linux.refresh_rate = blk: { core_window.refresh_rate = blk: {
if (libxrr != null) { if (libxrr != null) {
const conf = libxrr.?.XRRGetScreenInfo(display, root_window); const conf = libxrr.?.XRRGetScreenInfo(display, root_window);
break :blk @intCast(libxrr.?.XRRConfigCurrentRate(conf)); break :blk @intCast(libxrr.?.XRRConfigCurrentRate(conf));
} }
break :blk 60; 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, .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(), .empty_event_pipe = try std.posix.pipe(),
.gl_ctx = null, .gl_ctx = null,
.wm_protocols = libx11.XInternAtom(display, "WM_PROTOCOLS", c.False), .hidden_cursor = libx11.XCreatePixmapCursor(display, blank_pixmap, blank_pixmap, &color, &color, 0, 0),
.wm_delete_window = libx11.XInternAtom(display, "WM_DELETE_WINDOW", c.False), .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_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 = 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_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, .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, .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; var x11 = &core_window.native.?.x11;
_ = libx11.XrmInitialize();
defer _ = libx11.XFreeColormap(display, colormap);
for (0..2) |i| { for (0..2) |i| {
const sf = try std.posix.fcntl(x11.empty_event_pipe[i], std.posix.F.GETFL, 0); 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); 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 }; var protocols = [_]c.Atom{ x11.wm_delete_window, x11.net_wm_ping };
_ = libx11.XSetWMProtocols(x11.display, x11.window, &protocols, protocols.len); _ = 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.XSelectInput(x11.display, x11.window, set_window_attrs.event_mask);
_ = libx11.XMapWindow(x11.display, x11.window); _ = 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) { switch (backend_type) {
.opengl, .opengles => { .opengl, .opengles => {
if (libgl != null) { if (libgl != null) {
@ -206,66 +204,73 @@ pub fn init(
}, },
else => {}, else => {},
} }
// Create hidden cursor // Create hidden cursor
const gc = libx11.XCreateGC(x11.display, blank_pixmap, 0, null); const gc = libx11.XCreateGC(x11.display, blank_pixmap, 0, null);
if (gc != null) { if (gc != null) {
_ = libx11.XDrawPoint(x11.display, blank_pixmap, gc, 0, 0); _ = libx11.XDrawPoint(x11.display, blank_pixmap, gc, 0, 0);
_ = libx11.XFreeGC(x11.display, gc); _ = libx11.XFreeGC(x11.display, gc);
} }
// TODO: remove allocation x11.cursors[@intFromEnum(CursorShape.arrow)] = try createStandardCursor(x11, .arrow);
x11.cursors[@intFromEnum(CursorShape.arrow)] = try x11.createStandardCursor(.arrow);
core.windows.setValue(window_id, core_window);
try core.initWindow(window_id);
} }
pub fn deinit( // pub fn deinit(
x11: *X11, // x11: *X11,
linux: *Linux, // linux: *Linux,
) void { // ) void {
linux.allocator.destroy(x11.surface_descriptor); // linux.allocator.destroy(x11.surface_descriptor);
for (x11.cursors) |cur| { // for (x11.cursors) |cur| {
if (cur) |_| { // if (cur) |_| {
// _ = x11.libx11.XFreeCursor(x11.display, cur.?); // // _ = x11.libx11.XFreeCursor(x11.display, cur.?);
} // }
} // }
if (x11.libxcursor) |*libxcursor| { // if (x11.libxcursor) |*libxcursor| {
libxcursor.handle.close(); // libxcursor.handle.close();
} // }
if (x11.libxrr) |*libxrr| { // if (x11.libxrr) |*libxrr| {
libxrr.handle.close(); // libxrr.handle.close();
} // }
if (x11.libgl) |*libgl| { // if (x11.libgl) |*libgl| {
if (x11.gl_ctx) |gl_ctx| { // if (x11.gl_ctx) |gl_ctx| {
libgl.glXDestroyContext(x11.display, gl_ctx); // libgl.glXDestroyContext(x11.display, gl_ctx);
} // }
libgl.handle.close(); // libgl.handle.close();
} // }
_ = x11.libx11.XUnmapWindow(x11.display, x11.window); // _ = x11.libx11.XUnmapWindow(x11.display, x11.window);
_ = x11.libx11.XDestroyWindow(x11.display, x11.window); // _ = x11.libx11.XDestroyWindow(x11.display, x11.window);
_ = x11.libx11.XCloseDisplay(x11.display); // _ = x11.libx11.XCloseDisplay(x11.display);
x11.libx11.handle.close(); // x11.libx11.handle.close();
std.posix.close(x11.empty_event_pipe[0]); // std.posix.close(x11.empty_event_pipe[0]);
std.posix.close(x11.empty_event_pipe[1]); // std.posix.close(x11.empty_event_pipe[1]);
} // }
// Called on the main thread // 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) { while (c.QLength(x11.display) != 0) {
var event: c.XEvent = undefined; var event: c.XEvent = undefined;
_ = x11.libx11.XNextEvent(x11.display, &event); _ = 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); _ = x11.libx11.XFlush(x11.display);
// const frequency_delay = @as(f32, @floatFromInt(x11.input.delay_ns)) / @as(f32, @floatFromInt(std.time.ns_per_s)); // const frequency_delay = @as(f32, @floatFromInt(x11.input.delay_ns)) / @as(f32, @floatFromInt(std.time.ns_per_s));
// TODO: glfw.waitEventsTimeout(frequency_delay); // 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); _ = 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_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); const wm_fullscreen = x11.libx11.XInternAtom(x11.display, "_NET_WM_STATE_FULLSCREEN", c.False);
switch (display_mode) { switch (display_mode) {
@ -290,7 +295,7 @@ pub fn setDisplayMode(x11: *X11, linux: *Linux, display_mode: DisplayMode) void
@intCast(atoms.len), @intCast(atoms.len),
); );
x11.setFullscreen(false); x11.setFullscreen(false);
x11.setDecorated(linux.border); x11.setDecorated(border);
x11.setFloating(false); x11.setFloating(false);
_ = x11.libx11.XMapWindow(x11.display, x11.window); _ = x11.libx11.XMapWindow(x11.display, x11.window);
_ = x11.libx11.XFlush(x11.display); _ = 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_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); 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 }); 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_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 wm_above = x11.libx11.XInternAtom(x11.display, "_NET_WM_STATE_ABOVE", c.False);
const net_wm_state_remove = 0; 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 }); 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); var ev = std.mem.zeroes(c.XEvent);
ev.type = c.ClientMessage; ev.type = c.ClientMessage;
ev.xclient.window = x11.window; 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); _ = x11.libx11.XFlush(x11.display);
} }
fn setDecorated(x11: *X11, enabled: bool) void { fn setDecorated(x11: *const Native, enabled: bool) void {
const MWMHints = struct { const MWMHints = struct {
flags: u32, flags: u32,
functions: 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| { if (x11.libxcursor) |libxcursor| {
const theme = libxcursor.XcursorGetTheme(x11.display); const theme = libxcursor.XcursorGetTheme(x11.display);
if (theme != null) { if (theme != null) {
@ -587,7 +592,7 @@ fn createStandardCursor(x11: *X11, shape: CursorShape) !c.Cursor {
return cursor; return cursor;
} }
fn getCursorPos(x11: *X11) Position { fn getCursorPos(x11: *const Native) Position {
var root_window: c.Window = undefined; var root_window: c.Window = undefined;
var child_window: c.Window = undefined; var child_window: c.Window = undefined;
var root_cursor_x: c_int = 0; 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) }; 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) { switch (event.type) {
c.KeyPress, c.KeyRelease => { c.KeyPress, c.KeyRelease => {
// TODO: key repeat event // TODO: key repeat event
@ -618,19 +626,23 @@ fn processEvent(x11: *X11, linux: *Linux, event: *c.XEvent) void {
var keysym: c.KeySym = undefined; var keysym: c.KeySym = undefined;
_ = x11.libx11.XLookupString(&event.xkey, null, 0, &keysym, null); _ = 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) { switch (event.type) {
c.KeyPress => { 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)); const codepoint = x11.libxkbcommon.xkb_keysym_to_utf32(@truncate(keysym));
if (codepoint != 0) { 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 => { c.KeyRelease => {
x11.core.pushEvent(.{ .key_release = key_event }); core_ptr.pushEvent(.{ .key_release = key_event });
}, },
else => unreachable, else => unreachable,
} }
@ -645,28 +657,30 @@ fn processEvent(x11: *X11, linux: *Linux, event: *c.XEvent) void {
7 => .{ -1.0, 0.0 }, 7 => .{ -1.0, 0.0 },
else => unreachable, 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; return;
}; };
const cursor_pos = x11.getCursorPos(); const cursor_pos = getCursorPos(x11);
const mouse_button = MouseButtonEvent{ const mouse_button = MouseButtonEvent{
.button = button, .button = button,
.pos = cursor_pos, .pos = cursor_pos,
.mods = toMachMods(event.xbutton.state), .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 => { c.ButtonRelease => {
const button = toMachButton(event.xbutton.button) orelse return; const button = toMachButton(event.xbutton.button) orelse return;
const cursor_pos = x11.getCursorPos(); const cursor_pos = getCursorPos(x11);
const mouse_button = MouseButtonEvent{ const mouse_button = MouseButtonEvent{
.button = button, .button = button,
.pos = cursor_pos, .pos = cursor_pos,
.mods = toMachMods(event.xbutton.state), .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 => { c.ClientMessage => {
if (event.xclient.message_type == c.None) return; 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 == c.None) return;
if (protocol == x11.wm_delete_window) { 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) { } else if (protocol == x11.net_wm_ping) {
// The window manager is pinging the application to ensure // The window manager is pinging the application to ensure
// it's still responding to events // it's still responding to events
@ -695,26 +709,33 @@ fn processEvent(x11: *X11, linux: *Linux, event: *c.XEvent) void {
c.EnterNotify => { c.EnterNotify => {
const x: f32 = @floatFromInt(event.xcrossing.x); const x: f32 = @floatFromInt(event.xcrossing.x);
const y: f32 = @floatFromInt(event.xcrossing.y); 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 => { c.MotionNotify => {
const x: f32 = @floatFromInt(event.xmotion.x); const x: f32 = @floatFromInt(event.xmotion.x);
const y: f32 = @floatFromInt(event.xmotion.y); 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 => { c.ConfigureNotify => {
if (event.xconfigure.width != linux.size.width or if (event.xconfigure.width != core_window.width or
event.xconfigure.height != linux.size.height) event.xconfigure.height != core_window.height)
{ {
linux.size.width = @intCast(event.xconfigure.width); core_window.width = @intCast(event.xconfigure.width);
linux.size.height = @intCast(event.xconfigure.height); core_window.height = @intCast(event.xconfigure.height);
x11.core.swap_chain_update.set();
x11.core.pushEvent(.{ // FIX: What is the Mach Object System way of doing this?
.framebuffer_resize = .{ // core_ptr.swap_chain_update.set();
.width = linux.size.width,
.height = linux.size.height, 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 => { c.FocusIn => {
@ -726,7 +747,7 @@ fn processEvent(x11: *X11, linux: *Linux, event: *c.XEvent) void {
return; return;
} }
x11.core.pushEvent(.focus_gained); core_ptr.pushEvent(.{ .focus_gained = .{ .window_id = window_id } });
}, },
c.FocusOut => { c.FocusOut => {
if (event.xfocus.mode == c.NotifyGrab or if (event.xfocus.mode == c.NotifyGrab or
@ -737,7 +758,15 @@ fn processEvent(x11: *X11, linux: *Linux, event: *c.XEvent) void {
return; 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 => {}, else => {},
} }