linux: improve logging when both backends fail

This commit is contained in:
Joshua Holmes 2025-01-07 03:47:44 +00:00 committed by Emi Gutekanst
parent 377842aef8
commit ab143504ab
3 changed files with 186 additions and 145 deletions

View file

@ -25,11 +25,11 @@ pub const c = @cImport({
// This needs to be declared here so it can be used in the exported functions below,
// but doesn't need to be defined until run time (and can't be defined until run time).
var libwaylandclient: LibWaylandClient = undefined;
pub var libwaylandclient: ?LibWaylandClient = null;
// This does not need to be declared here, but we are declaring it here to be consistent
// with `libwaylandclient`.
var libxkbcommon: LibXkbCommon = undefined;
pub var libxkbcommon: ?LibXkbCommon = null;
var core_ptr: *Core = undefined;
@ -38,19 +38,19 @@ var core_ptr: *Core = undefined;
// compile time, but since they are not run until run time, after `libwaylandclient` is
// defined, an error never occurs.
export fn wl_proxy_add_listener(proxy: ?*c.struct_wl_proxy, implementation: [*c]?*const fn () callconv(.C) void, data: ?*anyopaque) c_int {
return @call(.always_tail, libwaylandclient.wl_proxy_add_listener, .{ proxy, implementation, data });
return @call(.always_tail, libwaylandclient.?.wl_proxy_add_listener, .{ proxy, implementation, data });
}
export fn wl_proxy_get_version(proxy: ?*c.struct_wl_proxy) u32 {
return @call(.always_tail, libwaylandclient.wl_proxy_get_version, .{proxy});
return @call(.always_tail, libwaylandclient.?.wl_proxy_get_version, .{proxy});
}
export fn wl_proxy_marshal_flags(proxy: ?*c.struct_wl_proxy, opcode: u32, interface: [*c]const c.struct_wl_interface, version: u32, flags: u32, ...) ?*c.struct_wl_proxy {
var arg_list: std.builtin.VaList = @cVaStart();
defer @cVaEnd(&arg_list);
return @call(.always_tail, libwaylandclient.wl_proxy_marshal_flags, .{ proxy, opcode, interface, version, flags, arg_list });
return @call(.always_tail, libwaylandclient.?.wl_proxy_marshal_flags, .{ proxy, opcode, interface, version, flags, arg_list });
}
export fn wl_proxy_destroy(proxy: ?*c.struct_wl_proxy) void {
return @call(.always_tail, libwaylandclient.wl_proxy_destroy, .{proxy});
return @call(.always_tail, libwaylandclient.?.wl_proxy_destroy, .{proxy});
}
pub const Native = struct {
@ -87,7 +87,7 @@ pub fn initWindow(
core_window.native = .{
.wayland = .{
.interfaces = Interfaces{},
.display = libwaylandclient.wl_display_connect(null) orelse return error.FailedToConnectToDisplay,
.display = libwaylandclient.?.wl_display_connect(null) orelse return error.FailedToConnectToDisplay,
.modifiers = .{
.alt = false,
.caps_lock = false,
@ -108,7 +108,7 @@ pub fn initWindow(
.surface_descriptor = undefined,
.surface = undefined,
.toplevel = undefined,
.xkb_context = libxkbcommon.xkb_context_new(0) orelse return error.FailedToGetXkbContext,
.xkb_context = libxkbcommon.?.xkb_context_new(0) orelse return error.FailedToGetXkbContext,
},
};
@ -124,10 +124,10 @@ pub fn initWindow(
// TODO: Look at replacing these 2 calls to wl_display_roundtrip with wl_display::sync
// Round trip to get all the registry objects
_ = libwaylandclient.wl_display_roundtrip(wl.display);
_ = libwaylandclient.?.wl_display_roundtrip(wl.display);
// Round trip to get all initial output events
_ = libwaylandclient.wl_display_roundtrip(wl.display);
_ = libwaylandclient.?.wl_display_roundtrip(wl.display);
// Update `core_window` since registry listener and seat listener changed values in it
core_window = core.windows.getValue(window_id);
@ -174,7 +174,7 @@ pub fn initWindow(
}
// Wait for events to get pushed
_ = libwaylandclient.wl_display_roundtrip(wl.display);
_ = libwaylandclient.?.wl_display_roundtrip(wl.display);
core_window = core.windows.getValue(window_id);
wl = &core_window.native.?.wayland;
@ -183,7 +183,7 @@ pub fn initWindow(
c.wl_surface_commit(wl.surface);
while (true) {
const result = libwaylandclient.wl_display_dispatch(wl.display);
const result = libwaylandclient.?.wl_display_dispatch(wl.display);
core_window = core.windows.getValue(window_id);
wl = &core_window.native.?.wayland;
@ -203,7 +203,7 @@ pub fn initWindow(
// Commit changes to surface
c.wl_surface_commit(wl.surface);
_ = libwaylandclient.wl_display_roundtrip(wl.display);
_ = libwaylandclient.?.wl_display_roundtrip(wl.display);
core.windows.setValue(window_id, core_window);
try core.initWindow(window_id);
@ -212,14 +212,14 @@ pub fn initWindow(
pub fn tick(window_id: mach.ObjectID) !void {
const wl = &core_ptr.windows.getValue(window_id).native.?.wayland;
while (libwaylandclient.wl_display_flush(wl.display) == -1) {
while (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 = libwaylandclient.wl_display_get_fd(wl.display),
.fd = libwaylandclient.?.wl_display_get_fd(wl.display),
.events = std.posix.POLL.OUT,
.revents = 0,
},
@ -233,7 +233,7 @@ pub fn tick(window_id: mach.ObjectID) !void {
}
}
_ = libwaylandclient.wl_display_roundtrip(wl.display);
_ = libwaylandclient.?.wl_display_roundtrip(wl.display);
}
pub fn setTitle(wl: *const Native, title: [:0]const u8) void {
@ -245,7 +245,7 @@ pub fn setDisplayMode(wl: *Wayland, display_mode: DisplayMode) void {
_ = display_mode;
}
const LibXkbCommon = struct {
pub const LibXkbCommon = struct {
handle: std.DynLib,
xkb_context_new: *const @TypeOf(c.xkb_context_new),
@ -265,9 +265,11 @@ const LibXkbCommon = struct {
xkb_compose_state_get_one_sym: *const @TypeOf(c.xkb_compose_state_get_one_sym),
xkb_keysym_to_utf32: *const @TypeOf(c.xkb_keysym_to_utf32),
pub const lib_name = "libxkbcommon.so.0";
pub fn load() !LibXkbCommon {
var lib: LibXkbCommon = undefined;
lib.handle = try mach.dynLibOpen("libxkbcommon.so.0");
lib.handle = std.DynLib.open(lib_name) catch return error.LibraryNotFound;
inline for (@typeInfo(LibXkbCommon).@"struct".fields[1..]) |field| {
const name = std.fmt.comptimePrint("{s}\x00", .{field.name});
const name_z: [:0]const u8 = @ptrCast(name[0 .. name.len - 1]);
@ -280,7 +282,7 @@ const LibXkbCommon = struct {
}
};
const LibWaylandClient = struct {
pub const LibWaylandClient = struct {
handle: std.DynLib,
wl_display_connect: *const @TypeOf(c.wl_display_connect),
@ -318,9 +320,11 @@ const LibWaylandClient = struct {
wl_surface_interface: *@TypeOf(c.wl_surface_interface),
wl_touch_interface: *@TypeOf(c.wl_touch_interface),
pub const lib_name = "libwayland-client.so.0";
pub fn load() !LibWaylandClient {
var lib: LibWaylandClient = undefined;
lib.handle = try mach.dynLibOpen("libwayland-client.so.0");
lib.handle = std.DynLib.open(lib_name) catch return error.LibraryNotFound;
inline for (@typeInfo(LibWaylandClient).@"struct".fields[1..]) |field| {
const name = std.fmt.comptimePrint("{s}\x00", .{field.name});
const name_z: [:0]const u8 = @ptrCast(name[0 .. name.len - 1]);
@ -363,7 +367,7 @@ const registry_listener = struct {
wl.interfaces.wl_compositor = @ptrCast(c.wl_registry_bind(
registry,
name,
libwaylandclient.wl_compositor_interface,
libwaylandclient.?.wl_compositor_interface,
@min(3, version),
) orelse @panic("uh idk how to proceed"));
} else if (std.mem.eql(u8, "wl_subcompositor", interface)) {
@ -371,7 +375,7 @@ const registry_listener = struct {
wl.interfaces.wl_subcompositor = @ptrCast(c.wl_registry_bind(
registry,
name,
libwaylandclient.wl_subcompositor_interface,
libwaylandclient.?.wl_subcompositor_interface,
@min(3, version),
) orelse @panic("uh idk how to proceed"));
} else if (std.mem.eql(u8, "wl_shm", interface)) {
@ -379,7 +383,7 @@ const registry_listener = struct {
wl.interfaces.wl_shm = @ptrCast(c.wl_registry_bind(
registry,
name,
libwaylandclient.wl_shm_interface,
libwaylandclient.?.wl_shm_interface,
@min(3, version),
) orelse @panic("uh idk how to proceed"));
} else if (std.mem.eql(u8, "wl_output", interface)) {
@ -387,14 +391,14 @@ const registry_listener = struct {
wl.interfaces.wl_output = @ptrCast(c.wl_registry_bind(
registry,
name,
libwaylandclient.wl_output_interface,
libwaylandclient.?.wl_output_interface,
@min(3, version),
) orelse @panic("uh idk how to proceed"));
// } else if (std.mem.eql(u8, "wl_data_device_manager", interface)) {
// wl.interfaces.wl_data_device_manager = @ptrCast(c.wl_registry_bind(
// registry,
// name,
// libwaylandclient.wl_data_device_manager_interface,
// libwaylandclient.?.wl_data_device_manager_interface,
// @min(3, version),
// ) orelse @panic("uh idk how to proceed"));
} else if (std.mem.eql(u8, "xdg_wm_base", interface)) {
@ -418,7 +422,7 @@ const registry_listener = struct {
wl.interfaces.wl_seat = @ptrCast(c.wl_registry_bind(
registry,
name,
libwaylandclient.wl_seat_interface,
libwaylandclient.?.wl_seat_interface,
@min(3, version),
) orelse @panic("uh idk how to proceed"));
@ -457,7 +461,7 @@ const keyboard_listener = struct {
const map_str = std.posix.mmap(null, keymap_size, std.posix.PROT.READ, .{ .TYPE = .SHARED }, fd, 0) catch unreachable;
const keymap = libxkbcommon.xkb_keymap_new_from_string(
const keymap = libxkbcommon.?.xkb_keymap_new_from_string(
wl.xkb_context,
@alignCast(map_str), //align cast happening here, im sure its fine? TODO: figure out if this okay
c.XKB_KEYMAP_FORMAT_TEXT_V1,
@ -470,13 +474,13 @@ const keyboard_listener = struct {
std.posix.close(fd);
//Release reference to old state and create new state
libxkbcommon.xkb_state_unref(wl.xkb_state);
const state = libxkbcommon.xkb_state_new(keymap).?;
libxkbcommon.?.xkb_state_unref(wl.xkb_state);
const state = libxkbcommon.?.xkb_state_new(keymap).?;
//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";
var compose_table = libxkbcommon.xkb_compose_table_new_from_locale(
var compose_table = libxkbcommon.?.xkb_compose_table_new_from_locale(
wl.xkb_context,
locale,
c.XKB_COMPOSE_COMPILE_NO_FLAGS,
@ -484,24 +488,24 @@ const keyboard_listener = struct {
//If creation failed, lets try the C locale
if (compose_table == null)
compose_table = libxkbcommon.xkb_compose_table_new_from_locale(
compose_table = libxkbcommon.?.xkb_compose_table_new_from_locale(
wl.xkb_context,
"C",
c.XKB_COMPOSE_COMPILE_NO_FLAGS,
).?;
defer libxkbcommon.xkb_compose_table_unref(compose_table);
defer libxkbcommon.?.xkb_compose_table_unref(compose_table);
wl.keymap = keymap;
wl.xkb_state = state;
wl.compose_state = libxkbcommon.xkb_compose_state_new(compose_table, c.XKB_COMPOSE_STATE_NO_FLAGS).?;
wl.compose_state = libxkbcommon.?.xkb_compose_state_new(compose_table, c.XKB_COMPOSE_STATE_NO_FLAGS).?;
wl.modifier_indices.control_index = libxkbcommon.xkb_keymap_mod_get_index(keymap, "Control");
wl.modifier_indices.alt_index = libxkbcommon.xkb_keymap_mod_get_index(keymap, "Mod1");
wl.modifier_indices.shift_index = libxkbcommon.xkb_keymap_mod_get_index(keymap, "Shift");
wl.modifier_indices.super_index = libxkbcommon.xkb_keymap_mod_get_index(keymap, "Mod4");
wl.modifier_indices.caps_lock_index = libxkbcommon.xkb_keymap_mod_get_index(keymap, "Lock");
wl.modifier_indices.num_lock_index = libxkbcommon.xkb_keymap_mod_get_index(keymap, "Mod2");
wl.modifier_indices.control_index = libxkbcommon.?.xkb_keymap_mod_get_index(keymap, "Control");
wl.modifier_indices.alt_index = libxkbcommon.?.xkb_keymap_mod_get_index(keymap, "Mod1");
wl.modifier_indices.shift_index = libxkbcommon.?.xkb_keymap_mod_get_index(keymap, "Shift");
wl.modifier_indices.super_index = libxkbcommon.?.xkb_keymap_mod_get_index(keymap, "Mod4");
wl.modifier_indices.caps_lock_index = libxkbcommon.?.xkb_keymap_mod_get_index(keymap, "Lock");
wl.modifier_indices.num_lock_index = libxkbcommon.?.xkb_keymap_mod_get_index(keymap, "Mod2");
core_ptr.windows.setValue(window_id, core_window);
}
@ -538,12 +542,12 @@ const keyboard_listener = struct {
var keysyms: ?[*]const c.xkb_keysym_t = undefined;
//Get the keysym from the keycode (scancode + 8)
if (libxkbcommon.xkb_state_key_get_syms(wl.xkb_state, scancode + 8, &keysyms) == 1) {
if (libxkbcommon.?.xkb_state_key_get_syms(wl.xkb_state, scancode + 8, &keysyms) == 1) {
//Compose the keysym
const keysym: c.xkb_keysym_t = composeSymbol(wl, keysyms.?[0]);
//Try to convert that keysym to a unicode codepoint
const codepoint = libxkbcommon.xkb_keysym_to_utf32(keysym);
const codepoint = libxkbcommon.?.xkb_keysym_to_utf32(keysym);
if (codepoint != 0) {
core_ptr.pushEvent(.{ .char_input = .{ .codepoint = @truncate(codepoint), .window_id = window_id } });
}
@ -563,7 +567,7 @@ const keyboard_listener = struct {
return;
// TODO: handle this return value
_ = libxkbcommon.xkb_state_update_mask(
_ = libxkbcommon.?.xkb_state_update_mask(
wl.xkb_state.?,
mods_depressed,
mods_latched,
@ -582,7 +586,7 @@ const keyboard_listener = struct {
.{ wl.modifier_indices.num_lock_index, "num_lock" },
.{ wl.modifier_indices.caps_lock_index, "caps_lock" },
}) |key| {
@field(wl.modifiers, key[1]) = libxkbcommon.xkb_state_mod_index_is_active(
@field(wl.modifiers, key[1]) = libxkbcommon.?.xkb_state_mod_index_is_active(
wl.xkb_state,
key[0],
c.XKB_STATE_MODS_EFFECTIVE,
@ -844,11 +848,11 @@ fn composeSymbol(wl: *const Native, sym: c.xkb_keysym_t) c.xkb_keysym_t {
if (sym == c.XKB_KEY_NoSymbol or wl.compose_state == null)
return sym;
if (libxkbcommon.xkb_compose_state_feed(wl.compose_state, sym) != c.XKB_COMPOSE_FEED_ACCEPTED)
if (libxkbcommon.?.xkb_compose_state_feed(wl.compose_state, sym) != c.XKB_COMPOSE_FEED_ACCEPTED)
return sym;
return switch (libxkbcommon.xkb_compose_state_get_status(wl.compose_state)) {
c.XKB_COMPOSE_COMPOSED => libxkbcommon.xkb_compose_state_get_one_sym(wl.compose_state),
return switch (libxkbcommon.?.xkb_compose_state_get_status(wl.compose_state)) {
c.XKB_COMPOSE_COMPOSED => libxkbcommon.?.xkb_compose_state_get_one_sym(wl.compose_state),
c.XKB_COMPOSE_COMPOSING, c.XKB_COMPOSE_CANCELLED => c.XKB_KEY_NoSymbol,
else => sym,
};