x11: get x11 to build and run
This commit is contained in:
parent
d6c387613d
commit
27aee7c036
2 changed files with 179 additions and 152 deletions
|
|
@ -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);
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
|
||||||
libxrr: ?LibXRR,
|
|
||||||
libgl: ?LibGL,
|
|
||||||
libxcursor: ?LibXCursor,
|
|
||||||
libxkbcommon: LibXkbCommon,
|
|
||||||
gl_ctx: ?*LibGL.Context,
|
|
||||||
display: *c.Display,
|
display: *c.Display,
|
||||||
empty_event_pipe: [2]std.c.fd_t,
|
empty_event_pipe: [2]std.c.fd_t,
|
||||||
wm_protocols: c.Atom,
|
gl_ctx: ?*LibGL.Context,
|
||||||
wm_delete_window: c.Atom,
|
hidden_cursor: c.Cursor,
|
||||||
net_wm_ping: c.Atom,
|
libgl: ?LibGL,
|
||||||
net_wm_bypass_compositor: c.Atom,
|
libx11: LibX11,
|
||||||
|
libxcursor: ?LibXCursor,
|
||||||
|
libxkbcommon: LibXkbCommon,
|
||||||
|
libxrr: ?LibXRR,
|
||||||
motif_wm_hints: c.Atom,
|
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: 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 => {},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue