linux: improve logging when both backends fail
This commit is contained in:
parent
377842aef8
commit
ab143504ab
3 changed files with 186 additions and 145 deletions
|
|
@ -115,7 +115,22 @@ pub fn initWindow(
|
||||||
else => "An unknown error occured while trying to connect to X11",
|
else => "An unknown error occured while trying to connect to X11",
|
||||||
};
|
};
|
||||||
log.err("{s}\n\nFalling back to Wayland\n", .{err_msg});
|
log.err("{s}\n\nFalling back to Wayland\n", .{err_msg});
|
||||||
try Wayland.initWindow(core, window_id);
|
Wayland.initWindow(core, window_id) catch |e| {
|
||||||
|
log.err("Failed to connect to fallback display server, Wayland.\n", .{});
|
||||||
|
var libs = std.ArrayList(u8).init(core.allocator);
|
||||||
|
defer libs.deinit();
|
||||||
|
if (X11.libx11 == null) {
|
||||||
|
try libs.appendSlice("\t* " ++ X11.LibX11.lib_name ++ "\n");
|
||||||
|
}
|
||||||
|
if (X11.libxkbcommon == null) {
|
||||||
|
try libs.appendSlice("\t* " ++ X11.LibXkbCommon.lib_name ++ "\n");
|
||||||
|
}
|
||||||
|
if (X11.libgl == null) {
|
||||||
|
try libs.appendSlice("\t* " ++ X11.LibGL.lib_name ++ "\n");
|
||||||
|
}
|
||||||
|
log.err("The following X11 libraries were not available:\n{s}", .{libs.items});
|
||||||
|
return e;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
.wayland => {
|
.wayland => {
|
||||||
|
|
@ -127,7 +142,19 @@ pub fn initWindow(
|
||||||
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\nFalling back to X11\n", .{err_msg});
|
log.err("{s}\n\nFalling back to X11\n", .{err_msg});
|
||||||
try X11.initWindow(core, window_id);
|
X11.initWindow(core, window_id) catch |e| {
|
||||||
|
log.err("Failed to connect to fallback display server, X11.\n", .{});
|
||||||
|
var libs = std.ArrayList(u8).init(core.allocator);
|
||||||
|
defer libs.deinit();
|
||||||
|
if (Wayland.libwaylandclient == null) {
|
||||||
|
try libs.appendSlice("\t* " ++ Wayland.LibWaylandClient.lib_name ++ "\n");
|
||||||
|
}
|
||||||
|
if (Wayland.libxkbcommon == null) {
|
||||||
|
try libs.appendSlice("\t* " ++ Wayland.LibXkbCommon.lib_name ++ "\n");
|
||||||
|
}
|
||||||
|
log.err("The following Wayland libraries were not available:\n{s}", .{libs.items});
|
||||||
|
return e;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,11 @@ pub const c = @cImport({
|
||||||
|
|
||||||
// This needs to be declared here so it can be used in the exported functions below,
|
// 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).
|
// 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
|
// This does not need to be declared here, but we are declaring it here to be consistent
|
||||||
// with `libwaylandclient`.
|
// with `libwaylandclient`.
|
||||||
var libxkbcommon: LibXkbCommon = undefined;
|
pub var libxkbcommon: ?LibXkbCommon = null;
|
||||||
|
|
||||||
var core_ptr: *Core = undefined;
|
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
|
// compile time, but since they are not run until run time, after `libwaylandclient` is
|
||||||
// defined, an error never occurs.
|
// 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 {
|
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 {
|
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 {
|
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();
|
var arg_list: std.builtin.VaList = @cVaStart();
|
||||||
defer @cVaEnd(&arg_list);
|
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 {
|
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 {
|
pub const Native = struct {
|
||||||
|
|
@ -87,7 +87,7 @@ pub fn initWindow(
|
||||||
core_window.native = .{
|
core_window.native = .{
|
||||||
.wayland = .{
|
.wayland = .{
|
||||||
.interfaces = Interfaces{},
|
.interfaces = Interfaces{},
|
||||||
.display = libwaylandclient.wl_display_connect(null) orelse return error.FailedToConnectToDisplay,
|
.display = libwaylandclient.?.wl_display_connect(null) orelse return error.FailedToConnectToDisplay,
|
||||||
.modifiers = .{
|
.modifiers = .{
|
||||||
.alt = false,
|
.alt = false,
|
||||||
.caps_lock = false,
|
.caps_lock = false,
|
||||||
|
|
@ -108,7 +108,7 @@ pub fn initWindow(
|
||||||
.surface_descriptor = undefined,
|
.surface_descriptor = undefined,
|
||||||
.surface = undefined,
|
.surface = undefined,
|
||||||
.toplevel = 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
|
// TODO: Look at replacing these 2 calls to wl_display_roundtrip with wl_display::sync
|
||||||
// Round trip to get all the registry objects
|
// 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
|
// 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
|
// Update `core_window` since registry listener and seat listener changed values in it
|
||||||
core_window = core.windows.getValue(window_id);
|
core_window = core.windows.getValue(window_id);
|
||||||
|
|
@ -174,7 +174,7 @@ pub fn initWindow(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for events to get pushed
|
// 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);
|
core_window = core.windows.getValue(window_id);
|
||||||
wl = &core_window.native.?.wayland;
|
wl = &core_window.native.?.wayland;
|
||||||
|
|
@ -183,7 +183,7 @@ pub fn initWindow(
|
||||||
c.wl_surface_commit(wl.surface);
|
c.wl_surface_commit(wl.surface);
|
||||||
|
|
||||||
while (true) {
|
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);
|
core_window = core.windows.getValue(window_id);
|
||||||
wl = &core_window.native.?.wayland;
|
wl = &core_window.native.?.wayland;
|
||||||
|
|
@ -203,7 +203,7 @@ pub fn initWindow(
|
||||||
// Commit changes to surface
|
// Commit changes to surface
|
||||||
c.wl_surface_commit(wl.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);
|
core.windows.setValue(window_id, core_window);
|
||||||
try core.initWindow(window_id);
|
try core.initWindow(window_id);
|
||||||
|
|
@ -212,14 +212,14 @@ pub fn initWindow(
|
||||||
pub fn tick(window_id: mach.ObjectID) !void {
|
pub fn tick(window_id: mach.ObjectID) !void {
|
||||||
const wl = &core_ptr.windows.getValue(window_id).native.?.wayland;
|
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) {
|
if (std.posix.errno(-1) == std.posix.E.AGAIN) {
|
||||||
log.err("flush error", .{});
|
log.err("flush error", .{});
|
||||||
return error.FlushError;
|
return error.FlushError;
|
||||||
}
|
}
|
||||||
var pollfd = [_]std.posix.pollfd{
|
var pollfd = [_]std.posix.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,
|
.events = std.posix.POLL.OUT,
|
||||||
.revents = 0,
|
.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 {
|
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;
|
_ = display_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const LibXkbCommon = struct {
|
pub const LibXkbCommon = struct {
|
||||||
handle: std.DynLib,
|
handle: std.DynLib,
|
||||||
|
|
||||||
xkb_context_new: *const @TypeOf(c.xkb_context_new),
|
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_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),
|
xkb_keysym_to_utf32: *const @TypeOf(c.xkb_keysym_to_utf32),
|
||||||
|
|
||||||
|
pub const lib_name = "libxkbcommon.so.0";
|
||||||
|
|
||||||
pub fn load() !LibXkbCommon {
|
pub fn load() !LibXkbCommon {
|
||||||
var lib: LibXkbCommon = undefined;
|
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| {
|
inline for (@typeInfo(LibXkbCommon).@"struct".fields[1..]) |field| {
|
||||||
const name = std.fmt.comptimePrint("{s}\x00", .{field.name});
|
const name = std.fmt.comptimePrint("{s}\x00", .{field.name});
|
||||||
const name_z: [:0]const u8 = @ptrCast(name[0 .. name.len - 1]);
|
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,
|
handle: std.DynLib,
|
||||||
|
|
||||||
wl_display_connect: *const @TypeOf(c.wl_display_connect),
|
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_surface_interface: *@TypeOf(c.wl_surface_interface),
|
||||||
wl_touch_interface: *@TypeOf(c.wl_touch_interface),
|
wl_touch_interface: *@TypeOf(c.wl_touch_interface),
|
||||||
|
|
||||||
|
pub const lib_name = "libwayland-client.so.0";
|
||||||
|
|
||||||
pub fn load() !LibWaylandClient {
|
pub fn load() !LibWaylandClient {
|
||||||
var lib: LibWaylandClient = undefined;
|
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| {
|
inline for (@typeInfo(LibWaylandClient).@"struct".fields[1..]) |field| {
|
||||||
const name = std.fmt.comptimePrint("{s}\x00", .{field.name});
|
const name = std.fmt.comptimePrint("{s}\x00", .{field.name});
|
||||||
const name_z: [:0]const u8 = @ptrCast(name[0 .. name.len - 1]);
|
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(
|
wl.interfaces.wl_compositor = @ptrCast(c.wl_registry_bind(
|
||||||
registry,
|
registry,
|
||||||
name,
|
name,
|
||||||
libwaylandclient.wl_compositor_interface,
|
libwaylandclient.?.wl_compositor_interface,
|
||||||
@min(3, version),
|
@min(3, version),
|
||||||
) orelse @panic("uh idk how to proceed"));
|
) orelse @panic("uh idk how to proceed"));
|
||||||
} else if (std.mem.eql(u8, "wl_subcompositor", interface)) {
|
} 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(
|
wl.interfaces.wl_subcompositor = @ptrCast(c.wl_registry_bind(
|
||||||
registry,
|
registry,
|
||||||
name,
|
name,
|
||||||
libwaylandclient.wl_subcompositor_interface,
|
libwaylandclient.?.wl_subcompositor_interface,
|
||||||
@min(3, version),
|
@min(3, version),
|
||||||
) orelse @panic("uh idk how to proceed"));
|
) orelse @panic("uh idk how to proceed"));
|
||||||
} else if (std.mem.eql(u8, "wl_shm", interface)) {
|
} 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(
|
wl.interfaces.wl_shm = @ptrCast(c.wl_registry_bind(
|
||||||
registry,
|
registry,
|
||||||
name,
|
name,
|
||||||
libwaylandclient.wl_shm_interface,
|
libwaylandclient.?.wl_shm_interface,
|
||||||
@min(3, version),
|
@min(3, version),
|
||||||
) orelse @panic("uh idk how to proceed"));
|
) orelse @panic("uh idk how to proceed"));
|
||||||
} else if (std.mem.eql(u8, "wl_output", interface)) {
|
} 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(
|
wl.interfaces.wl_output = @ptrCast(c.wl_registry_bind(
|
||||||
registry,
|
registry,
|
||||||
name,
|
name,
|
||||||
libwaylandclient.wl_output_interface,
|
libwaylandclient.?.wl_output_interface,
|
||||||
@min(3, version),
|
@min(3, version),
|
||||||
) orelse @panic("uh idk how to proceed"));
|
) orelse @panic("uh idk how to proceed"));
|
||||||
// } else if (std.mem.eql(u8, "wl_data_device_manager", interface)) {
|
// } else if (std.mem.eql(u8, "wl_data_device_manager", interface)) {
|
||||||
// wl.interfaces.wl_data_device_manager = @ptrCast(c.wl_registry_bind(
|
// wl.interfaces.wl_data_device_manager = @ptrCast(c.wl_registry_bind(
|
||||||
// registry,
|
// registry,
|
||||||
// name,
|
// name,
|
||||||
// libwaylandclient.wl_data_device_manager_interface,
|
// libwaylandclient.?.wl_data_device_manager_interface,
|
||||||
// @min(3, version),
|
// @min(3, version),
|
||||||
// ) orelse @panic("uh idk how to proceed"));
|
// ) orelse @panic("uh idk how to proceed"));
|
||||||
} else if (std.mem.eql(u8, "xdg_wm_base", interface)) {
|
} 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(
|
wl.interfaces.wl_seat = @ptrCast(c.wl_registry_bind(
|
||||||
registry,
|
registry,
|
||||||
name,
|
name,
|
||||||
libwaylandclient.wl_seat_interface,
|
libwaylandclient.?.wl_seat_interface,
|
||||||
@min(3, version),
|
@min(3, version),
|
||||||
) orelse @panic("uh idk how to proceed"));
|
) 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 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,
|
wl.xkb_context,
|
||||||
@alignCast(map_str), //align cast happening here, im sure its fine? TODO: figure out if this okay
|
@alignCast(map_str), //align cast happening here, im sure its fine? TODO: figure out if this okay
|
||||||
c.XKB_KEYMAP_FORMAT_TEXT_V1,
|
c.XKB_KEYMAP_FORMAT_TEXT_V1,
|
||||||
|
|
@ -470,13 +474,13 @@ const keyboard_listener = struct {
|
||||||
std.posix.close(fd);
|
std.posix.close(fd);
|
||||||
|
|
||||||
//Release reference to old state and create new state
|
//Release reference to old state and create new state
|
||||||
libxkbcommon.xkb_state_unref(wl.xkb_state);
|
libxkbcommon.?.xkb_state_unref(wl.xkb_state);
|
||||||
const state = libxkbcommon.xkb_state_new(keymap).?;
|
const state = libxkbcommon.?.xkb_state_new(keymap).?;
|
||||||
|
|
||||||
//this chain hurts me. why must C be this way.
|
//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";
|
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,
|
wl.xkb_context,
|
||||||
locale,
|
locale,
|
||||||
c.XKB_COMPOSE_COMPILE_NO_FLAGS,
|
c.XKB_COMPOSE_COMPILE_NO_FLAGS,
|
||||||
|
|
@ -484,24 +488,24 @@ const keyboard_listener = struct {
|
||||||
|
|
||||||
//If creation failed, lets try the C locale
|
//If creation failed, lets try the C locale
|
||||||
if (compose_table == null)
|
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,
|
wl.xkb_context,
|
||||||
"C",
|
"C",
|
||||||
c.XKB_COMPOSE_COMPILE_NO_FLAGS,
|
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.keymap = keymap;
|
||||||
wl.xkb_state = state;
|
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.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.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.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.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.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.num_lock_index = libxkbcommon.?.xkb_keymap_mod_get_index(keymap, "Mod2");
|
||||||
|
|
||||||
core_ptr.windows.setValue(window_id, core_window);
|
core_ptr.windows.setValue(window_id, core_window);
|
||||||
}
|
}
|
||||||
|
|
@ -538,12 +542,12 @@ const keyboard_listener = struct {
|
||||||
|
|
||||||
var keysyms: ?[*]const c.xkb_keysym_t = undefined;
|
var keysyms: ?[*]const c.xkb_keysym_t = undefined;
|
||||||
//Get the keysym from the keycode (scancode + 8)
|
//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
|
//Compose the keysym
|
||||||
const keysym: c.xkb_keysym_t = composeSymbol(wl, keysyms.?[0]);
|
const keysym: c.xkb_keysym_t = composeSymbol(wl, keysyms.?[0]);
|
||||||
|
|
||||||
//Try to convert that keysym to a unicode codepoint
|
//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) {
|
if (codepoint != 0) {
|
||||||
core_ptr.pushEvent(.{ .char_input = .{ .codepoint = @truncate(codepoint), .window_id = window_id } });
|
core_ptr.pushEvent(.{ .char_input = .{ .codepoint = @truncate(codepoint), .window_id = window_id } });
|
||||||
}
|
}
|
||||||
|
|
@ -563,7 +567,7 @@ const keyboard_listener = struct {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// TODO: handle this return value
|
// TODO: handle this return value
|
||||||
_ = libxkbcommon.xkb_state_update_mask(
|
_ = libxkbcommon.?.xkb_state_update_mask(
|
||||||
wl.xkb_state.?,
|
wl.xkb_state.?,
|
||||||
mods_depressed,
|
mods_depressed,
|
||||||
mods_latched,
|
mods_latched,
|
||||||
|
|
@ -582,7 +586,7 @@ const keyboard_listener = struct {
|
||||||
.{ wl.modifier_indices.num_lock_index, "num_lock" },
|
.{ wl.modifier_indices.num_lock_index, "num_lock" },
|
||||||
.{ wl.modifier_indices.caps_lock_index, "caps_lock" },
|
.{ wl.modifier_indices.caps_lock_index, "caps_lock" },
|
||||||
}) |key| {
|
}) |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,
|
wl.xkb_state,
|
||||||
key[0],
|
key[0],
|
||||||
c.XKB_STATE_MODS_EFFECTIVE,
|
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)
|
if (sym == c.XKB_KEY_NoSymbol or wl.compose_state == null)
|
||||||
return sym;
|
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 sym;
|
||||||
|
|
||||||
return switch (libxkbcommon.xkb_compose_state_get_status(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_COMPOSED => libxkbcommon.?.xkb_compose_state_get_one_sym(wl.compose_state),
|
||||||
c.XKB_COMPOSE_COMPOSING, c.XKB_COMPOSE_CANCELLED => c.XKB_KEY_NoSymbol,
|
c.XKB_COMPOSE_COMPOSING, c.XKB_COMPOSE_CANCELLED => c.XKB_KEY_NoSymbol,
|
||||||
else => sym,
|
else => sym,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,10 @@ pub const defaultPanic = std.debug.panicImpl;
|
||||||
// TODO: determine if it's really needed to store global pointer
|
// TODO: determine if it's really needed to store global pointer
|
||||||
var core_ptr: *Core = undefined;
|
var core_ptr: *Core = undefined;
|
||||||
|
|
||||||
|
pub var libx11: ?LibX11 = null;
|
||||||
|
pub var libxkbcommon: ?LibXkbCommon = null;
|
||||||
|
pub var libgl: ?LibGL = null;
|
||||||
|
|
||||||
pub const Native = struct {
|
pub const Native = struct {
|
||||||
backend_type: gpu.BackendType,
|
backend_type: gpu.BackendType,
|
||||||
cursors: [@typeInfo(CursorShape).@"enum".fields.len]?c.Cursor,
|
cursors: [@typeInfo(CursorShape).@"enum".fields.len]?c.Cursor,
|
||||||
|
|
@ -40,11 +44,7 @@ pub const Native = struct {
|
||||||
empty_event_pipe: [2]std.c.fd_t,
|
empty_event_pipe: [2]std.c.fd_t,
|
||||||
gl_ctx: ?*LibGL.Context,
|
gl_ctx: ?*LibGL.Context,
|
||||||
hidden_cursor: c.Cursor,
|
hidden_cursor: c.Cursor,
|
||||||
libgl: ?LibGL,
|
|
||||||
libx11: LibX11,
|
|
||||||
libxcursor: ?LibXCursor,
|
libxcursor: ?LibXCursor,
|
||||||
libxkbcommon: LibXkbCommon,
|
|
||||||
libxrr: ?LibXRR,
|
|
||||||
motif_wm_hints: c.Atom,
|
motif_wm_hints: c.Atom,
|
||||||
net_wm_bypass_compositor: c.Atom,
|
net_wm_bypass_compositor: c.Atom,
|
||||||
net_wm_ping: c.Atom,
|
net_wm_ping: c.Atom,
|
||||||
|
|
@ -68,35 +68,45 @@ pub fn initWindow(
|
||||||
core_ptr = core;
|
core_ptr = core;
|
||||||
var core_window = core.windows.getValue(window_id);
|
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();
|
// Try to load both libs so either or both missing libs can be communicated, if necessary
|
||||||
|
libx11 = LibX11.load() catch |err| switch (err) {
|
||||||
|
error.LibraryNotFound => null,
|
||||||
|
else => return err,
|
||||||
|
};
|
||||||
|
libxkbcommon = LibXkbCommon.load() catch |err| switch (err) {
|
||||||
|
error.LibraryNotFound => null,
|
||||||
|
else => return err,
|
||||||
|
};
|
||||||
|
libgl = LibGL.load() catch |err| switch (err) {
|
||||||
|
error.LibraryNotFound => null,
|
||||||
|
else => return err,
|
||||||
|
};
|
||||||
|
if (libx11 == null or libxkbcommon == null or libgl == null) return error.LibraryNotFound;
|
||||||
|
|
||||||
// Note: X11 (at least, older versions of it definitely) have a race condition with frame submission
|
// Note: X11 (at least, older versions of it definitely) have a race condition with frame submission
|
||||||
// when the Vulkan presentation mode != .none; XInitThreads() resolves this. We use XInitThreads
|
// when the Vulkan presentation mode != .none; XInitThreads() resolves this. We use XInitThreads
|
||||||
// /solely/ to ensure we can use .double and .triple presentation modes, we do not use it for
|
// /solely/ to ensure we can use .double and .triple presentation modes, we do not use it for
|
||||||
// anything else and otherwise treat all X11 API calls as if they are not thread-safe as with all
|
// anything else and otherwise treat all X11 API calls as if they are not thread-safe as with all
|
||||||
// other native GUI APIs.
|
// other native GUI APIs.
|
||||||
_ = libx11.XInitThreads();
|
_ = libx11.?.XInitThreads();
|
||||||
const libgl: ?LibGL = LibGL.load() catch |err| switch (err) {
|
|
||||||
|
const libxcursor = LibXCursor.load() catch |err| switch (err) {
|
||||||
error.LibraryNotFound => null,
|
error.LibraryNotFound => null,
|
||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
const libxcursor: ?LibXCursor = LibXCursor.load() catch |err| switch (err) {
|
const libxrr = LibXRR.load() catch |err| switch (err) {
|
||||||
error.LibraryNotFound => null,
|
error.LibraryNotFound => null,
|
||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
const libxrr: ?LibXRR = LibXRR.load() catch |err| switch (err) {
|
const display = libx11.?.XOpenDisplay(null) orelse {
|
||||||
error.LibraryNotFound => null,
|
|
||||||
else => return err,
|
|
||||||
};
|
|
||||||
const display = libx11.XOpenDisplay(null) orelse {
|
|
||||||
return error.FailedToConnectToDisplay;
|
return error.FailedToConnectToDisplay;
|
||||||
};
|
};
|
||||||
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);
|
defer _ = libx11.?.XFreeColormap(display, colormap);
|
||||||
|
|
||||||
var set_window_attrs = c.XSetWindowAttributes{
|
var set_window_attrs = c.XSetWindowAttributes{
|
||||||
.colormap = colormap,
|
.colormap = colormap,
|
||||||
|
|
@ -108,11 +118,11 @@ pub fn initWindow(
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: read error after function call and handle
|
// TODO: read error after function call and handle
|
||||||
const x_window_id = libx11.XCreateWindow(
|
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?
|
||||||
core_window.width,
|
core_window.width,
|
||||||
core_window.height,
|
core_window.height,
|
||||||
0,
|
0,
|
||||||
|
|
@ -123,12 +133,12 @@ pub fn initWindow(
|
||||||
&set_window_attrs,
|
&set_window_attrs,
|
||||||
);
|
);
|
||||||
|
|
||||||
const blank_pixmap = libx11.XCreatePixmap(display, x_window_id, 1, 1, 1);
|
const blank_pixmap = libx11.?.XCreatePixmap(display, x_window_id, 1, 1, 1);
|
||||||
var color = c.XColor{};
|
var color = c.XColor{};
|
||||||
core_window.refresh_rate = blk: {
|
core_window.refresh_rate = blk: {
|
||||||
if (libxrr != null) {
|
if (libxrr) |_libxrr| {
|
||||||
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;
|
||||||
};
|
};
|
||||||
|
|
@ -144,22 +154,18 @@ pub fn initWindow(
|
||||||
.display = display,
|
.display = display,
|
||||||
.empty_event_pipe = try std.posix.pipe(),
|
.empty_event_pipe = try std.posix.pipe(),
|
||||||
.gl_ctx = null,
|
.gl_ctx = null,
|
||||||
.hidden_cursor = libx11.XCreatePixmapCursor(display, blank_pixmap, blank_pixmap, &color, &color, 0, 0),
|
.hidden_cursor = libx11.?.XCreatePixmapCursor(display, blank_pixmap, blank_pixmap, &color, &color, 0, 0),
|
||||||
.libgl = libgl,
|
|
||||||
.libx11 = libx11,
|
|
||||||
.libxcursor = libxcursor,
|
.libxcursor = libxcursor,
|
||||||
.libxkbcommon = try LibXkbCommon.load(),
|
.motif_wm_hints = libx11.?.XInternAtom(display, "_MOTIF_WM_HINTS", c.False),
|
||||||
.libxrr = libxrr,
|
.net_wm_bypass_compositor = libx11.?.XInternAtom(display, "_NET_WM_BYPASS_COMPOSITOR", c.False),
|
||||||
.motif_wm_hints = libx11.XInternAtom(display, "_MOTIF_WM_HINTS", c.False),
|
.net_wm_ping = libx11.?.XInternAtom(display, "NET_WM_PING", c.False),
|
||||||
.net_wm_bypass_compositor = libx11.XInternAtom(display, "_NET_WM_BYPASS_COMPOSITOR", c.False),
|
.net_wm_window_type = libx11.?.XInternAtom(display, "_NET_WM_WINDOW_TYPE", c.False),
|
||||||
.net_wm_ping = libx11.XInternAtom(display, "NET_WM_PING", c.False),
|
.net_wm_window_type_dock = libx11.?.XInternAtom(display, "_NET_WM_WINDOW_TYPE_DOCK", 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),
|
|
||||||
.root_window = root_window,
|
.root_window = root_window,
|
||||||
.surface_descriptor = surface_descriptor,
|
.surface_descriptor = surface_descriptor,
|
||||||
.window = x_window_id,
|
.window = x_window_id,
|
||||||
.wm_delete_window = libx11.XInternAtom(display, "WM_DELETE_WINDOW", c.False),
|
.wm_delete_window = libx11.?.XInternAtom(display, "WM_DELETE_WINDOW", c.False),
|
||||||
.wm_protocols = libx11.XInternAtom(display, "WM_PROTOCOLS", c.False),
|
.wm_protocols = libx11.?.XInternAtom(display, "WM_PROTOCOLS", c.False),
|
||||||
} };
|
} };
|
||||||
var x11 = &core_window.native.?.x11;
|
var x11 = &core_window.native.?.x11;
|
||||||
|
|
||||||
|
|
@ -170,46 +176,42 @@ pub fn initWindow(
|
||||||
_ = try std.posix.fcntl(x11.empty_event_pipe[i], std.posix.F.SETFD, df | std.posix.FD_CLOEXEC);
|
_ = try std.posix.fcntl(x11.empty_event_pipe[i], std.posix.F.SETFD, df | std.posix.FD_CLOEXEC);
|
||||||
}
|
}
|
||||||
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, core_window.title);
|
_ = 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);
|
||||||
|
|
||||||
// TODO: see if this can be removed
|
// TODO: see if this can be removed
|
||||||
const backend_type = try Core.detectBackendType(core.allocator);
|
const backend_type = try Core.detectBackendType(core.allocator);
|
||||||
switch (backend_type) {
|
switch (backend_type) {
|
||||||
.opengl, .opengles => {
|
.opengl, .opengles => {
|
||||||
if (libgl != null) {
|
// zig fmt: off
|
||||||
// zig fmt: off
|
const attrs = &[_]c_int{
|
||||||
const attrs = &[_]c_int{
|
LibGL.rgba,
|
||||||
LibGL.rgba,
|
LibGL.doublebuffer,
|
||||||
LibGL.doublebuffer,
|
LibGL.depth_size, 24,
|
||||||
LibGL.depth_size, 24,
|
LibGL.stencil_size, 8,
|
||||||
LibGL.stencil_size, 8,
|
LibGL.red_size, 8,
|
||||||
LibGL.red_size, 8,
|
LibGL.green_size, 8,
|
||||||
LibGL.green_size, 8,
|
LibGL.blue_size, 8,
|
||||||
LibGL.blue_size, 8,
|
LibGL.sample_buffers, 0,
|
||||||
LibGL.sample_buffers, 0,
|
LibGL.samples, 0,
|
||||||
LibGL.samples, 0,
|
c.None,
|
||||||
c.None,
|
};
|
||||||
};
|
// zig fmt: on
|
||||||
// zig fmt: on
|
const visual_info = libgl.?.glXChooseVisual(x11.display, screen, attrs.ptr);
|
||||||
const visual_info = libgl.?.glXChooseVisual(x11.display, screen, attrs.ptr);
|
defer _ = libx11.?.XFree(visual_info);
|
||||||
defer _ = libx11.XFree(visual_info);
|
x11.gl_ctx = libgl.?.glXCreateContext(x11.display, visual_info, null, true);
|
||||||
x11.gl_ctx = libgl.?.glXCreateContext(x11.display, visual_info, null, true);
|
_ = libgl.?.glXMakeCurrent(x11.display, x11.window, x11.gl_ctx);
|
||||||
_ = libgl.?.glXMakeCurrent(x11.display, x11.window, x11.gl_ctx);
|
|
||||||
} else {
|
|
||||||
return error.LibGLNotFound;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
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);
|
||||||
}
|
}
|
||||||
x11.cursors[@intFromEnum(CursorShape.arrow)] = try createStandardCursor(x11, .arrow);
|
x11.cursors[@intFromEnum(CursorShape.arrow)] = try createStandardCursor(x11, .arrow);
|
||||||
|
|
||||||
|
|
@ -223,26 +225,26 @@ pub fn tick(window_id: mach.ObjectID) !void {
|
||||||
var x11 = &core_window.native.?.x11;
|
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);
|
_ = libx11.?.XNextEvent(x11.display, &event);
|
||||||
processEvent(window_id, &event);
|
processEvent(window_id, &event);
|
||||||
// update in case core_window was changed
|
// update in case core_window was changed
|
||||||
core_window = core_ptr.windows.getValue(window_id);
|
core_window = core_ptr.windows.getValue(window_id);
|
||||||
x11 = &core_window.native.?.x11;
|
x11 = &core_window.native.?.x11;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = x11.libx11.XFlush(x11.display);
|
_ = 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setTitle(x11: *const Native, title: [:0]const u8) void {
|
pub fn setTitle(x11: *const Native, title: [:0]const u8) void {
|
||||||
_ = x11.libx11.XStoreName(x11.display, x11.window, title);
|
_ = libx11.?.XStoreName(x11.display, x11.window, title);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setDisplayMode(x11: *const Native, display_mode: DisplayMode, border: bool) 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 = 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 = libx11.?.XInternAtom(x11.display, "_NET_WM_STATE_FULLSCREEN", c.False);
|
||||||
switch (display_mode) {
|
switch (display_mode) {
|
||||||
.windowed => {
|
.windowed => {
|
||||||
var atoms = std.BoundedArray(c.Atom, 5){};
|
var atoms = std.BoundedArray(c.Atom, 5){};
|
||||||
|
|
@ -254,7 +256,7 @@ pub fn setDisplayMode(x11: *const Native, display_mode: DisplayMode, border: boo
|
||||||
// if (x11.floating) {
|
// if (x11.floating) {
|
||||||
// atoms.append(x11.net_wm_state_above) catch unreachable;
|
// atoms.append(x11.net_wm_state_above) catch unreachable;
|
||||||
// }
|
// }
|
||||||
_ = x11.libx11.XChangeProperty(
|
_ = libx11.?.XChangeProperty(
|
||||||
x11.display,
|
x11.display,
|
||||||
x11.window,
|
x11.window,
|
||||||
wm_state,
|
wm_state,
|
||||||
|
|
@ -267,37 +269,37 @@ pub fn setDisplayMode(x11: *const Native, display_mode: DisplayMode, border: boo
|
||||||
x11.setFullscreen(false);
|
x11.setFullscreen(false);
|
||||||
x11.setDecorated(border);
|
x11.setDecorated(border);
|
||||||
x11.setFloating(false);
|
x11.setFloating(false);
|
||||||
_ = x11.libx11.XMapWindow(x11.display, x11.window);
|
_ = libx11.?.XMapWindow(x11.display, x11.window);
|
||||||
_ = x11.libx11.XFlush(x11.display);
|
_ = libx11.?.XFlush(x11.display);
|
||||||
},
|
},
|
||||||
.fullscreen => {
|
.fullscreen => {
|
||||||
x11.setFullscreen(true);
|
x11.setFullscreen(true);
|
||||||
_ = x11.libx11.XFlush(x11.display);
|
_ = libx11.?.XFlush(x11.display);
|
||||||
},
|
},
|
||||||
.fullscreen_borderless => {
|
.fullscreen_borderless => {
|
||||||
x11.setDecorated(false);
|
x11.setDecorated(false);
|
||||||
x11.setFloating(true);
|
x11.setFloating(true);
|
||||||
x11.setFullscreen(false);
|
x11.setFullscreen(false);
|
||||||
_ = x11.libx11.XResizeWindow(
|
_ = libx11.?.XResizeWindow(
|
||||||
x11.display,
|
x11.display,
|
||||||
x11.window,
|
x11.window,
|
||||||
@intCast(c.DisplayWidth(x11.display, c.DefaultScreen(x11.display))),
|
@intCast(c.DisplayWidth(x11.display, c.DefaultScreen(x11.display))),
|
||||||
@intCast(c.DisplayHeight(x11.display, c.DefaultScreen(x11.display))),
|
@intCast(c.DisplayHeight(x11.display, c.DefaultScreen(x11.display))),
|
||||||
);
|
);
|
||||||
_ = x11.libx11.XFlush(x11.display);
|
_ = libx11.?.XFlush(x11.display);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setFullscreen(x11: *const Native, 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 = 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 = 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 });
|
||||||
// Force composition OFF to reduce overhead
|
// Force composition OFF to reduce overhead
|
||||||
const compositing_disable_on: c_long = @intFromBool(enabled);
|
const compositing_disable_on: c_long = @intFromBool(enabled);
|
||||||
const bypass_compositor = x11.libx11.XInternAtom(x11.display, "_NET_WM_BYPASS_COMPOSITOR", c.False);
|
const bypass_compositor = libx11.?.XInternAtom(x11.display, "_NET_WM_BYPASS_COMPOSITOR", c.False);
|
||||||
if (bypass_compositor != c.None) {
|
if (bypass_compositor != c.None) {
|
||||||
_ = x11.libx11.XChangeProperty(
|
_ = libx11.?.XChangeProperty(
|
||||||
x11.display,
|
x11.display,
|
||||||
x11.window,
|
x11.window,
|
||||||
bypass_compositor,
|
bypass_compositor,
|
||||||
|
|
@ -311,8 +313,8 @@ fn setFullscreen(x11: *const Native, enabled: bool) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setFloating(x11: *const Native, 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 = 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 = libx11.?.XInternAtom(x11.display, "_NET_WM_STATE_ABOVE", c.False);
|
||||||
const net_wm_state_remove = 0;
|
const net_wm_state_remove = 0;
|
||||||
const net_wm_state_add = 1;
|
const net_wm_state_add = 1;
|
||||||
const action: c_long = if (enabled) net_wm_state_add else net_wm_state_remove;
|
const action: c_long = if (enabled) net_wm_state_add else net_wm_state_remove;
|
||||||
|
|
@ -326,14 +328,14 @@ fn sendEventToWM(x11: *const Native, message_type: c.Atom, data: []const c_long)
|
||||||
ev.xclient.message_type = message_type;
|
ev.xclient.message_type = message_type;
|
||||||
ev.xclient.format = 32;
|
ev.xclient.format = 32;
|
||||||
@memcpy(ev.xclient.data.l[0..data.len], data);
|
@memcpy(ev.xclient.data.l[0..data.len], data);
|
||||||
_ = x11.libx11.XSendEvent(
|
_ = libx11.?.XSendEvent(
|
||||||
x11.display,
|
x11.display,
|
||||||
x11.root_window,
|
x11.root_window,
|
||||||
c.False,
|
c.False,
|
||||||
c.SubstructureNotifyMask | c.SubstructureRedirectMask,
|
c.SubstructureNotifyMask | c.SubstructureRedirectMask,
|
||||||
&ev,
|
&ev,
|
||||||
);
|
);
|
||||||
_ = x11.libx11.XFlush(x11.display);
|
_ = libx11.?.XFlush(x11.display);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setDecorated(x11: *const Native, enabled: bool) void {
|
fn setDecorated(x11: *const Native, enabled: bool) void {
|
||||||
|
|
@ -351,7 +353,7 @@ fn setDecorated(x11: *const Native, enabled: bool) void {
|
||||||
.input_mode = 0,
|
.input_mode = 0,
|
||||||
.status = 0,
|
.status = 0,
|
||||||
};
|
};
|
||||||
_ = x11.libx11.XChangeProperty(
|
_ = libx11.?.XChangeProperty(
|
||||||
x11.display,
|
x11.display,
|
||||||
x11.window,
|
x11.window,
|
||||||
x11.motif_wm_hints,
|
x11.motif_wm_hints,
|
||||||
|
|
@ -363,7 +365,7 @@ fn setDecorated(x11: *const Native, enabled: bool) void {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const LibX11 = struct {
|
pub const LibX11 = struct {
|
||||||
handle: std.DynLib,
|
handle: std.DynLib,
|
||||||
XInitThreads: *const @TypeOf(c.XInitThreads),
|
XInitThreads: *const @TypeOf(c.XInitThreads),
|
||||||
XrmInitialize: *const @TypeOf(c.XrmInitialize),
|
XrmInitialize: *const @TypeOf(c.XrmInitialize),
|
||||||
|
|
@ -407,9 +409,12 @@ const LibX11 = struct {
|
||||||
XAllocSizeHints: *const @TypeOf(c.XAllocSizeHints),
|
XAllocSizeHints: *const @TypeOf(c.XAllocSizeHints),
|
||||||
XSetWMNormalHints: *const @TypeOf(c.XSetWMNormalHints),
|
XSetWMNormalHints: *const @TypeOf(c.XSetWMNormalHints),
|
||||||
XFree: *const @TypeOf(c.XFree),
|
XFree: *const @TypeOf(c.XFree),
|
||||||
|
|
||||||
|
pub const lib_name = "libX11.so.6";
|
||||||
|
|
||||||
pub fn load() !LibX11 {
|
pub fn load() !LibX11 {
|
||||||
var lib: LibX11 = undefined;
|
var lib: LibX11 = undefined;
|
||||||
lib.handle = try mach.dynLibOpen("libX11.so.6");
|
lib.handle = std.DynLib.open(lib_name) catch return error.LibraryNotFound;
|
||||||
inline for (@typeInfo(LibX11).@"struct".fields[1..]) |field| {
|
inline for (@typeInfo(LibX11).@"struct".fields[1..]) |field| {
|
||||||
const name = std.fmt.comptimePrint("{s}\x00", .{field.name});
|
const name = std.fmt.comptimePrint("{s}\x00", .{field.name});
|
||||||
const name_z: [:0]const u8 = @ptrCast(name[0 .. name.len - 1]);
|
const name_z: [:0]const u8 = @ptrCast(name[0 .. name.len - 1]);
|
||||||
|
|
@ -429,7 +434,7 @@ const LibXCursor = struct {
|
||||||
XcursorLibraryLoadImage: *const @TypeOf(c.XcursorLibraryLoadImage),
|
XcursorLibraryLoadImage: *const @TypeOf(c.XcursorLibraryLoadImage),
|
||||||
pub fn load() !LibXCursor {
|
pub fn load() !LibXCursor {
|
||||||
var lib: LibXCursor = undefined;
|
var lib: LibXCursor = undefined;
|
||||||
lib.handle = try mach.dynLibOpen("libXcursor.so.1");
|
lib.handle = std.DynLib.open("libXcursor.so.1") catch return error.LibraryNotFound;
|
||||||
inline for (@typeInfo(LibXCursor).@"struct".fields[1..]) |field| {
|
inline for (@typeInfo(LibXCursor).@"struct".fields[1..]) |field| {
|
||||||
const name = std.fmt.comptimePrint("{s}\x00", .{field.name});
|
const name = std.fmt.comptimePrint("{s}\x00", .{field.name});
|
||||||
const name_z: [:0]const u8 = @ptrCast(name[0 .. name.len - 1]);
|
const name_z: [:0]const u8 = @ptrCast(name[0 .. name.len - 1]);
|
||||||
|
|
@ -445,7 +450,7 @@ const LibXRR = struct {
|
||||||
XRRConfigCurrentRate: *const @TypeOf(c.XRRConfigCurrentRate),
|
XRRConfigCurrentRate: *const @TypeOf(c.XRRConfigCurrentRate),
|
||||||
pub fn load() !LibXRR {
|
pub fn load() !LibXRR {
|
||||||
var lib: LibXRR = undefined;
|
var lib: LibXRR = undefined;
|
||||||
lib.handle = try mach.dynLibOpen("libXrandr.so.1");
|
lib.handle = std.DynLib.open("libXrandr.so.1") catch return error.LibraryNotFound;
|
||||||
inline for (@typeInfo(LibXRR).@"struct".fields[1..]) |field| {
|
inline for (@typeInfo(LibXRR).@"struct".fields[1..]) |field| {
|
||||||
const name = std.fmt.comptimePrint("{s}\x00", .{field.name});
|
const name = std.fmt.comptimePrint("{s}\x00", .{field.name});
|
||||||
const name_z: [:0]const u8 = @ptrCast(name[0 .. name.len - 1]);
|
const name_z: [:0]const u8 = @ptrCast(name[0 .. name.len - 1]);
|
||||||
|
|
@ -455,7 +460,7 @@ const LibXRR = struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const LibGL = struct {
|
pub const LibGL = struct {
|
||||||
const Drawable = c.XID;
|
const Drawable = c.XID;
|
||||||
const Context = opaque {};
|
const Context = opaque {};
|
||||||
const FBConfig = opaque {};
|
const FBConfig = opaque {};
|
||||||
|
|
@ -474,9 +479,12 @@ const LibGL = struct {
|
||||||
glXMakeCurrent: *const fn (*c.Display, Drawable, ?*Context) callconv(.C) bool,
|
glXMakeCurrent: *const fn (*c.Display, Drawable, ?*Context) callconv(.C) bool,
|
||||||
glXChooseVisual: *const fn (*c.Display, c_int, [*]const c_int) callconv(.C) *c.XVisualInfo,
|
glXChooseVisual: *const fn (*c.Display, c_int, [*]const c_int) callconv(.C) *c.XVisualInfo,
|
||||||
glXSwapBuffers: *const fn (*c.Display, Drawable) callconv(.C) bool,
|
glXSwapBuffers: *const fn (*c.Display, Drawable) callconv(.C) bool,
|
||||||
|
|
||||||
|
pub const lib_name = "libGL.so.1";
|
||||||
|
|
||||||
pub fn load() !LibGL {
|
pub fn load() !LibGL {
|
||||||
var lib: LibGL = undefined;
|
var lib: LibGL = undefined;
|
||||||
lib.handle = try mach.dynLibOpen("libGL.so.1");
|
lib.handle = std.DynLib.open(lib_name) catch return error.LibraryNotFound;
|
||||||
inline for (@typeInfo(LibGL).@"struct".fields[1..]) |field| {
|
inline for (@typeInfo(LibGL).@"struct".fields[1..]) |field| {
|
||||||
const name = std.fmt.comptimePrint("{s}\x00", .{field.name});
|
const name = std.fmt.comptimePrint("{s}\x00", .{field.name});
|
||||||
const name_z: [:0]const u8 = @ptrCast(name[0 .. name.len - 1]);
|
const name_z: [:0]const u8 = @ptrCast(name[0 .. name.len - 1]);
|
||||||
|
|
@ -486,7 +494,7 @@ const LibGL = struct {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const LibXkbCommon = struct {
|
pub const LibXkbCommon = struct {
|
||||||
handle: std.DynLib,
|
handle: std.DynLib,
|
||||||
|
|
||||||
// xkb_context_new: *const @TypeOf(c.xkb_context_new),
|
// xkb_context_new: *const @TypeOf(c.xkb_context_new),
|
||||||
|
|
@ -506,9 +514,11 @@ const LibXkbCommon = struct {
|
||||||
// xkb_compose_state_get_one_sym: *const @TypeOf(c.xkb_compose_state_get_one_sym),
|
// 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),
|
xkb_keysym_to_utf32: *const @TypeOf(c.xkb_keysym_to_utf32),
|
||||||
|
|
||||||
|
pub const lib_name = "libxkbcommon.so.0";
|
||||||
|
|
||||||
pub fn load() !LibXkbCommon {
|
pub fn load() !LibXkbCommon {
|
||||||
var lib: LibXkbCommon = undefined;
|
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| {
|
inline for (@typeInfo(LibXkbCommon).@"struct".fields[1..]) |field| {
|
||||||
const name = std.fmt.comptimePrint("{s}\x00", .{field.name});
|
const name = std.fmt.comptimePrint("{s}\x00", .{field.name});
|
||||||
const name_z: [:0]const u8 = @ptrCast(name[0 .. name.len - 1]);
|
const name_z: [:0]const u8 = @ptrCast(name[0 .. name.len - 1]);
|
||||||
|
|
@ -557,7 +567,7 @@ fn createStandardCursor(x11: *const Native, shape: CursorShape) !c.Cursor {
|
||||||
.resize_all => c.XC_fleur,
|
.resize_all => c.XC_fleur,
|
||||||
.not_allowed => c.XC_X_cursor,
|
.not_allowed => c.XC_X_cursor,
|
||||||
};
|
};
|
||||||
const cursor = x11.libx11.XCreateFontCursor(x11.display, xc);
|
const cursor = libx11.?.XCreateFontCursor(x11.display, xc);
|
||||||
if (cursor == 0) return error.FailedToCreateCursor;
|
if (cursor == 0) return error.FailedToCreateCursor;
|
||||||
return cursor;
|
return cursor;
|
||||||
}
|
}
|
||||||
|
|
@ -570,7 +580,7 @@ fn getCursorPos(x11: *const Native) Position {
|
||||||
var cursor_x: c_int = 0;
|
var cursor_x: c_int = 0;
|
||||||
var cursor_y: c_int = 0;
|
var cursor_y: c_int = 0;
|
||||||
var mask: c_uint = 0;
|
var mask: c_uint = 0;
|
||||||
_ = x11.libx11.XQueryPointer(
|
_ = libx11.?.XQueryPointer(
|
||||||
x11.display,
|
x11.display,
|
||||||
x11.window,
|
x11.window,
|
||||||
&root_window,
|
&root_window,
|
||||||
|
|
@ -594,7 +604,7 @@ fn processEvent(window_id: mach.ObjectID, event: *c.XEvent) void {
|
||||||
// TODO: key repeat event
|
// TODO: key repeat event
|
||||||
|
|
||||||
var keysym: c.KeySym = undefined;
|
var keysym: c.KeySym = undefined;
|
||||||
_ = x11.libx11.XLookupString(&event.xkey, null, 0, &keysym, null);
|
_ = libx11.?.XLookupString(&event.xkey, null, 0, &keysym, null);
|
||||||
|
|
||||||
const key_event = KeyEvent{
|
const key_event = KeyEvent{
|
||||||
.key = toMachKey(keysym),
|
.key = toMachKey(keysym),
|
||||||
|
|
@ -606,7 +616,7 @@ fn processEvent(window_id: mach.ObjectID, event: *c.XEvent) void {
|
||||||
c.KeyPress => {
|
c.KeyPress => {
|
||||||
core_ptr.pushEvent(.{ .key_press = key_event });
|
core_ptr.pushEvent(.{ .key_press = key_event });
|
||||||
|
|
||||||
const codepoint = x11.libxkbcommon.xkb_keysym_to_utf32(@truncate(keysym));
|
const codepoint = libxkbcommon.?.xkb_keysym_to_utf32(@truncate(keysym));
|
||||||
if (codepoint != 0) {
|
if (codepoint != 0) {
|
||||||
core_ptr.pushEvent(.{ .char_input = .{ .codepoint = @truncate(codepoint), .window_id = window_id } });
|
core_ptr.pushEvent(.{ .char_input = .{ .codepoint = @truncate(codepoint), .window_id = window_id } });
|
||||||
}
|
}
|
||||||
|
|
@ -666,7 +676,7 @@ fn processEvent(window_id: mach.ObjectID, event: *c.XEvent) void {
|
||||||
// it's still responding to events
|
// it's still responding to events
|
||||||
var reply = event.*;
|
var reply = event.*;
|
||||||
reply.xclient.window = x11.root_window;
|
reply.xclient.window = x11.root_window;
|
||||||
_ = x11.libx11.XSendEvent(
|
_ = libx11.?.XSendEvent(
|
||||||
x11.display,
|
x11.display,
|
||||||
x11.root_window,
|
x11.root_window,
|
||||||
c.False,
|
c.False,
|
||||||
|
|
@ -731,7 +741,7 @@ fn processEvent(window_id: mach.ObjectID, event: *c.XEvent) void {
|
||||||
core_ptr.pushEvent(.{ .focus_lost = .{ .window_id = window_id } });
|
core_ptr.pushEvent(.{ .focus_lost = .{ .window_id = window_id } });
|
||||||
},
|
},
|
||||||
c.ResizeRequest => {
|
c.ResizeRequest => {
|
||||||
_ = x11.libx11.XResizeWindow(
|
_ = libx11.?.XResizeWindow(
|
||||||
x11.display,
|
x11.display,
|
||||||
x11.window,
|
x11.window,
|
||||||
@intCast(c.DisplayWidth(x11.display, c.DefaultScreen(x11.display))),
|
@intCast(c.DisplayWidth(x11.display, c.DefaultScreen(x11.display))),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue