mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
apprt/gtk: use some comptime to load X11 functions
This commit is contained in:
@ -5,13 +5,6 @@ const input = @import("../../input.zig");
|
|||||||
|
|
||||||
const log = std.log.scoped(.gtk_x11);
|
const log = std.log.scoped(.gtk_x11);
|
||||||
|
|
||||||
// X11 Function types. We load these dynamically at runtime to avoid having to
|
|
||||||
// link against X11.
|
|
||||||
const XkbQueryExtensionType = *const fn (?*c.struct__XDisplay, [*c]c_int, [*c]c_int, [*c]c_int, [*c]c_int, [*c]c_int) callconv(.C) c_int;
|
|
||||||
const XkbSelectEventDetailsType = *const fn (?*c.struct__XDisplay, c_uint, c_uint, c_ulong, c_ulong) callconv(.C) c_int;
|
|
||||||
const XEventsQueuedType = *const fn (?*c.struct__XDisplay, c_int) callconv(.C) c_int;
|
|
||||||
const XPeekEventType = *const fn (?*c.struct__XDisplay, [*c]c.union__XEvent) callconv(.C) c_int;
|
|
||||||
|
|
||||||
/// Returns true if the passed in display is an X11 display.
|
/// Returns true if the passed in display is an X11 display.
|
||||||
pub fn x11_is_display(display: ?*c.GdkDisplay) bool {
|
pub fn x11_is_display(display: ?*c.GdkDisplay) bool {
|
||||||
return c.g_type_check_instance_is_a(
|
return c.g_type_check_instance_is_a(
|
||||||
@ -24,12 +17,7 @@ pub const X11Xkb = struct {
|
|||||||
opcode: c_int,
|
opcode: c_int,
|
||||||
base_event_code: c_int,
|
base_event_code: c_int,
|
||||||
base_error_code: c_int,
|
base_error_code: c_int,
|
||||||
|
funcs: Funcs,
|
||||||
// Dynamic functions
|
|
||||||
XkbQueryExtension: XkbQueryExtensionType = undefined,
|
|
||||||
XkbSelectEventDetails: XkbSelectEventDetailsType = undefined,
|
|
||||||
XEventsQueued: XEventsQueuedType = undefined,
|
|
||||||
XPeekEvent: XPeekEventType = undefined,
|
|
||||||
|
|
||||||
/// Initialize an X11Xkb struct, for the given GDK display. If the display
|
/// Initialize an X11Xkb struct, for the given GDK display. If the display
|
||||||
/// isn't backed by X then this will return null.
|
/// isn't backed by X then this will return null.
|
||||||
@ -43,48 +31,17 @@ pub const X11Xkb = struct {
|
|||||||
|
|
||||||
log.debug("X11Xkb.init: initializing Xkb", .{});
|
log.debug("X11Xkb.init: initializing Xkb", .{});
|
||||||
const xdisplay = c.gdk_x11_display_get_xdisplay(display);
|
const xdisplay = c.gdk_x11_display_get_xdisplay(display);
|
||||||
var result: X11Xkb = .{ .opcode = 0, .base_event_code = 0, .base_error_code = 0 };
|
var result: X11Xkb = .{
|
||||||
|
.opcode = 0,
|
||||||
// Load in the X11 calls we need.
|
.base_event_code = 0,
|
||||||
log.debug(" X11Xkb.init: loading libX11.so dynamically", .{});
|
.base_error_code = 0,
|
||||||
var libX11 = try std.DynLib.open("libX11.so");
|
.funcs = try Funcs.init(),
|
||||||
defer libX11.close();
|
|
||||||
result.XkbQueryExtension = libX11.lookup(
|
|
||||||
XkbQueryExtensionType,
|
|
||||||
"XkbQueryExtension",
|
|
||||||
) orelse {
|
|
||||||
log.err("Fatal: error dynamic loading libX11: missing symbol XkbQueryExtension", .{});
|
|
||||||
return error.XkbInitializationError;
|
|
||||||
};
|
|
||||||
|
|
||||||
result.XkbSelectEventDetails = libX11.lookup(
|
|
||||||
XkbSelectEventDetailsType,
|
|
||||||
"XkbSelectEventDetails",
|
|
||||||
) orelse {
|
|
||||||
log.err("Fatal: error dynamic loading libX11: missing symbol XkbSelectEventDetails", .{});
|
|
||||||
return error.XkbInitializationError;
|
|
||||||
};
|
|
||||||
|
|
||||||
result.XEventsQueued = libX11.lookup(
|
|
||||||
XEventsQueuedType,
|
|
||||||
"XEventsQueued",
|
|
||||||
) orelse {
|
|
||||||
log.err("Fatal: error dynamic loading libX11: missing symbol XEventsQueued", .{});
|
|
||||||
return error.XkbInitializationError;
|
|
||||||
};
|
|
||||||
|
|
||||||
result.XPeekEvent = libX11.lookup(
|
|
||||||
XPeekEventType,
|
|
||||||
"XPeekEvent",
|
|
||||||
) orelse {
|
|
||||||
log.err("Fatal: error dynamic loading libX11: missing symbol XPeekEvent", .{});
|
|
||||||
return error.XkbInitializationError;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
log.debug("X11Xkb.init: running XkbQueryExtension", .{});
|
log.debug("X11Xkb.init: running XkbQueryExtension", .{});
|
||||||
var major = c.XkbMajorVersion;
|
var major = c.XkbMajorVersion;
|
||||||
var minor = c.XkbMinorVersion;
|
var minor = c.XkbMinorVersion;
|
||||||
if (result.XkbQueryExtension(
|
if (result.funcs.XkbQueryExtension(
|
||||||
xdisplay,
|
xdisplay,
|
||||||
&result.opcode,
|
&result.opcode,
|
||||||
&result.base_event_code,
|
&result.base_event_code,
|
||||||
@ -97,7 +54,7 @@ pub const X11Xkb = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.debug("X11Xkb.init: running XkbSelectEventDetails", .{});
|
log.debug("X11Xkb.init: running XkbSelectEventDetails", .{});
|
||||||
if (result.XkbSelectEventDetails(
|
if (result.funcs.XkbSelectEventDetails(
|
||||||
xdisplay,
|
xdisplay,
|
||||||
c.XkbUseCoreKbd,
|
c.XkbUseCoreKbd,
|
||||||
c.XkbStateNotify,
|
c.XkbStateNotify,
|
||||||
@ -127,10 +84,10 @@ pub const X11Xkb = struct {
|
|||||||
// Shoutout to Mozilla for figuring out a clean way to do this, this is
|
// Shoutout to Mozilla for figuring out a clean way to do this, this is
|
||||||
// paraphrased from Firefox/Gecko in widget/gtk/nsGtkKeyUtils.cpp.
|
// paraphrased from Firefox/Gecko in widget/gtk/nsGtkKeyUtils.cpp.
|
||||||
const xdisplay = c.gdk_x11_display_get_xdisplay(display);
|
const xdisplay = c.gdk_x11_display_get_xdisplay(display);
|
||||||
if (self.XEventsQueued(xdisplay, c.QueuedAfterReading) == 0) return null;
|
if (self.funcs.XEventsQueued(xdisplay, c.QueuedAfterReading) == 0) return null;
|
||||||
|
|
||||||
var nextEvent: c.XEvent = undefined;
|
var nextEvent: c.XEvent = undefined;
|
||||||
_ = self.XPeekEvent(xdisplay, &nextEvent);
|
_ = self.funcs.XPeekEvent(xdisplay, &nextEvent);
|
||||||
if (nextEvent.type != self.base_event_code) return null;
|
if (nextEvent.type != self.base_event_code) return null;
|
||||||
|
|
||||||
const xkb_event: *c.XkbEvent = @ptrCast(&nextEvent);
|
const xkb_event: *c.XkbEvent = @ptrCast(&nextEvent);
|
||||||
@ -151,3 +108,41 @@ pub const X11Xkb = struct {
|
|||||||
return mods;
|
return mods;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The functions that we load dynamically from libX11.so.
|
||||||
|
const Funcs = struct {
|
||||||
|
XkbQueryExtension: XkbQueryExtensionType,
|
||||||
|
XkbSelectEventDetails: XkbSelectEventDetailsType,
|
||||||
|
XEventsQueued: XEventsQueuedType,
|
||||||
|
XPeekEvent: XPeekEventType,
|
||||||
|
|
||||||
|
// X11 Function types. We load these dynamically at runtime to avoid having to
|
||||||
|
// link against X11.
|
||||||
|
const XkbQueryExtensionType = *const fn (?*c.struct__XDisplay, [*c]c_int, [*c]c_int, [*c]c_int, [*c]c_int, [*c]c_int) callconv(.C) c_int;
|
||||||
|
const XkbSelectEventDetailsType = *const fn (?*c.struct__XDisplay, c_uint, c_uint, c_ulong, c_ulong) callconv(.C) c_int;
|
||||||
|
const XEventsQueuedType = *const fn (?*c.struct__XDisplay, c_int) callconv(.C) c_int;
|
||||||
|
const XPeekEventType = *const fn (?*c.struct__XDisplay, [*c]c.union__XEvent) callconv(.C) c_int;
|
||||||
|
|
||||||
|
pub fn init() !Funcs {
|
||||||
|
var libX11 = try std.DynLib.open("libX11.so");
|
||||||
|
defer libX11.close();
|
||||||
|
|
||||||
|
var result: Funcs = undefined;
|
||||||
|
inline for (@typeInfo(Funcs).Struct.fields) |field| {
|
||||||
|
const name = comptime name: {
|
||||||
|
const null_term = field.name ++ .{0};
|
||||||
|
break :name null_term[0..field.name.len :0];
|
||||||
|
};
|
||||||
|
|
||||||
|
@field(result, field.name) = libX11.lookup(
|
||||||
|
field.type,
|
||||||
|
name,
|
||||||
|
) orelse {
|
||||||
|
log.err(" error dynamic loading libX11: missing symbol {s}", .{field.name});
|
||||||
|
return error.XkbInitializationError;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Reference in New Issue
Block a user