wayland: setup with new object system
This commit is contained in:
parent
b3a5186f3a
commit
fdc3666a95
2 changed files with 269 additions and 220 deletions
|
|
@ -59,32 +59,27 @@ const MISSING_FEATURES_X11 = [_][]const u8{ "Resizing window", "Changing display
|
||||||
const MISSING_FEATURES_WAYLAND = [_][]const u8{ "Changing display mode", "VSync", "Setting window border/cursor" };
|
const MISSING_FEATURES_WAYLAND = [_][]const u8{ "Changing display mode", "VSync", "Setting window border/cursor" };
|
||||||
|
|
||||||
pub fn tick(core: *Core) !void {
|
pub fn tick(core: *Core) !void {
|
||||||
_ = core;
|
var windows = core.windows.slice();
|
||||||
|
while (windows.next()) |window_id| {
|
||||||
|
const native_opt: ?Native = core.windows.get(window_id, .native);
|
||||||
|
if (native_opt) |native| {
|
||||||
|
switch (native) {
|
||||||
|
.x11 => {}, // X11.tick(window_id),
|
||||||
|
.wayland => try Wayland.tick(window_id),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try initWindow(core, window_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(
|
pub fn initWindow(
|
||||||
linux: *Linux,
|
|
||||||
core: *Core,
|
core: *Core,
|
||||||
options: InitOptions,
|
window_id: mach.ObjectID,
|
||||||
) !void {
|
) !void {
|
||||||
linux.allocator = options.allocator;
|
|
||||||
|
|
||||||
if (!options.is_app and try wantGamemode(linux.allocator)) linux.gamemode = initLinuxGamemode();
|
|
||||||
linux.headless = options.headless;
|
|
||||||
linux.refresh_rate = 60; // TODO: set to something meaningful
|
|
||||||
linux.vsync_mode = .triple;
|
|
||||||
linux.size = options.size;
|
|
||||||
linux.title = try options.allocator.dupeZ(u8, options.title);
|
|
||||||
linux.border = options.border;
|
|
||||||
linux.cursor_mode = .normal;
|
|
||||||
linux.cursor_shape = .arrow;
|
|
||||||
if (!options.headless) {
|
|
||||||
linux.display_mode = options.display_mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
const desired_backend: BackendEnum = blk: {
|
const desired_backend: BackendEnum = blk: {
|
||||||
const backend = std.process.getEnvVarOwned(
|
const backend = std.process.getEnvVarOwned(
|
||||||
linux.allocator,
|
core.allocator,
|
||||||
"MACH_BACKEND",
|
"MACH_BACKEND",
|
||||||
) catch |err| switch (err) {
|
) catch |err| switch (err) {
|
||||||
error.EnvironmentVariableNotFound => {
|
error.EnvironmentVariableNotFound => {
|
||||||
|
|
@ -92,7 +87,7 @@ pub fn init(
|
||||||
},
|
},
|
||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
defer linux.allocator.free(backend);
|
defer core.allocator.free(backend);
|
||||||
|
|
||||||
if (std.ascii.eqlIgnoreCase(backend, "x11")) break :blk .x11;
|
if (std.ascii.eqlIgnoreCase(backend, "x11")) break :blk .x11;
|
||||||
if (std.ascii.eqlIgnoreCase(backend, "wayland")) break :blk .wayland;
|
if (std.ascii.eqlIgnoreCase(backend, "wayland")) break :blk .wayland;
|
||||||
|
|
@ -102,18 +97,19 @@ pub fn init(
|
||||||
// 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 => {
|
||||||
X11.init(linux, core, options) catch |err| {
|
return;
|
||||||
const err_msg = switch (err) {
|
// X11.initWindow(core, window_id) catch |err| {
|
||||||
error.LibraryNotFound => "Missing X11 library",
|
// const err_msg = switch (err) {
|
||||||
error.FailedToConnectToDisplay => "Failed to connect to X11 display",
|
// error.LibraryNotFound => "Missing X11 library",
|
||||||
else => "An unknown error occured while trying to connect to X11",
|
// 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.init(linux, core, options);
|
// log.err("{s}\n\nFalling back to Wayland\n", .{err_msg});
|
||||||
};
|
// try Wayland.initWindow(core, window_id);
|
||||||
|
// };
|
||||||
},
|
},
|
||||||
.wayland => {
|
.wayland => {
|
||||||
Wayland.init(linux, core, options) catch |err| {
|
Wayland.initWindow(core, window_id) catch |err| {
|
||||||
const err_msg = switch (err) {
|
const err_msg = switch (err) {
|
||||||
error.NoServerSideDecorationSupport => "Server Side Decorations aren't supported",
|
error.NoServerSideDecorationSupport => "Server Side Decorations aren't supported",
|
||||||
error.LibraryNotFound => "Missing Wayland library",
|
error.LibraryNotFound => "Missing Wayland library",
|
||||||
|
|
@ -121,35 +117,26 @@ pub fn init(
|
||||||
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.init(linux, core, options);
|
// try X11.initWindow(core, window_id);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (linux.backend) {
|
|
||||||
.wayland => |be| {
|
|
||||||
linux.surface_descriptor = .{ .next_in_chain = .{ .from_wayland_surface = be.surface_descriptor } };
|
|
||||||
},
|
|
||||||
.x11 => |be| {
|
|
||||||
linux.surface_descriptor = .{ .next_in_chain = .{ .from_xlib_window = be.surface_descriptor } };
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// warn about incomplete features
|
// warn about incomplete features
|
||||||
// TODO: remove this when linux is not missing major features
|
// TODO: remove this when linux is not missing major features
|
||||||
try warnAboutIncompleteFeatures(linux.backend, &MISSING_FEATURES_X11, &MISSING_FEATURES_WAYLAND, options.allocator);
|
try warnAboutIncompleteFeatures(desired_backend, &MISSING_FEATURES_X11, &MISSING_FEATURES_WAYLAND, core.allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(linux: *Linux) void {
|
// pub fn deinit(linux: *Linux) void {
|
||||||
if (linux.gamemode != null and linux.gamemode.?) deinitLinuxGamemode();
|
// if (linux.gamemode != null and linux.gamemode.?) deinitLinuxGamemode();
|
||||||
|
//
|
||||||
linux.allocator.free(linux.title);
|
// linux.allocator.free(linux.title);
|
||||||
|
//
|
||||||
switch (linux.backend) {
|
// switch (linux.backend) {
|
||||||
.wayland => linux.backend.wayland.deinit(linux),
|
// .wayland => linux.backend.wayland.deinit(linux),
|
||||||
.x11 => linux.backend.x11.deinit(linux),
|
// .x11 => linux.backend.x11.deinit(linux),
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub fn update(linux: *Linux) !void {
|
pub fn update(linux: *Linux) !void {
|
||||||
switch (linux.backend) {
|
switch (linux.backend) {
|
||||||
|
|
|
||||||
|
|
@ -25,66 +25,69 @@ 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_global: LibWaylandClient = undefined;
|
var libwaylandclient: LibWaylandClient = undefined;
|
||||||
|
|
||||||
|
// This does not need to be declared here, but we are declaring it here to be consistent
|
||||||
|
// with `libwaylandclient`.
|
||||||
|
var libxkbcommon: LibXkbCommon = undefined;
|
||||||
|
|
||||||
|
var core_ptr: *Core = undefined;
|
||||||
|
|
||||||
// These exported functions are defined because the wayland headers don't define them,
|
// These exported functions are defined because the wayland headers don't define them,
|
||||||
// and then the linker gets confused. They reference undefined `libwaylandclient_global` at
|
// and then the linker gets confused. They reference undefined `libwaylandclient` at
|
||||||
// compile time, but since they are not run until run time, after `libwaylandclient_global` 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_global.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_global.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_global.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_global.wl_proxy_destroy, .{proxy});
|
return @call(.always_tail, libwaylandclient.wl_proxy_destroy, .{proxy});
|
||||||
}
|
}
|
||||||
|
|
||||||
core: *Core,
|
pub const Native = struct {
|
||||||
surface_descriptor: *gpu.Surface.DescriptorFromWaylandSurface,
|
surface_descriptor: gpu.Surface.DescriptorFromWaylandSurface,
|
||||||
configured: bool = false,
|
configured: bool = false,
|
||||||
|
|
||||||
display: *c.wl_display,
|
display: *c.wl_display,
|
||||||
surface: *c.wl_surface,
|
surface: *c.wl_surface,
|
||||||
toplevel: *c.xdg_toplevel,
|
toplevel: *c.xdg_toplevel,
|
||||||
interfaces: Interfaces,
|
interfaces: Interfaces,
|
||||||
libwaylandclient: LibWaylandClient,
|
|
||||||
|
|
||||||
// input stuff
|
// input stuff
|
||||||
keyboard: ?*c.wl_keyboard = null,
|
keyboard: ?*c.wl_keyboard = null,
|
||||||
pointer: ?*c.wl_pointer = null,
|
pointer: ?*c.wl_pointer = null,
|
||||||
|
|
||||||
// keyboard stuff
|
// keyboard stuff
|
||||||
xkb_context: ?*c.xkb_context = null,
|
xkb_context: *c.xkb_context,
|
||||||
xkb_state: ?*c.xkb_state = null,
|
xkb_state: ?*c.xkb_state = null,
|
||||||
compose_state: ?*c.xkb_compose_state = null,
|
compose_state: ?*c.xkb_compose_state = null,
|
||||||
keymap: ?*c.xkb_keymap = null,
|
keymap: ?*c.xkb_keymap = null,
|
||||||
libxkbcommon: LibXkbCommon,
|
modifiers: Core.KeyMods,
|
||||||
modifiers: Core.KeyMods,
|
modifier_indices: KeyModInd,
|
||||||
modifier_indices: KeyModInd,
|
};
|
||||||
|
|
||||||
pub const Native = struct {};
|
pub fn initWindow(
|
||||||
|
|
||||||
pub fn init(
|
|
||||||
linux: *Linux,
|
|
||||||
core: *Core,
|
core: *Core,
|
||||||
options: InitOptions,
|
window_id: mach.ObjectID,
|
||||||
) !void {
|
) !void {
|
||||||
libwaylandclient_global = try LibWaylandClient.load();
|
core_ptr = core;
|
||||||
linux.backend = .{
|
var core_window = core.windows.getValue(window_id);
|
||||||
.wayland = Wayland{
|
libwaylandclient = try LibWaylandClient.load();
|
||||||
.core = core,
|
libxkbcommon = try LibXkbCommon.load();
|
||||||
.libxkbcommon = try LibXkbCommon.load(),
|
|
||||||
.libwaylandclient = libwaylandclient_global,
|
core_window.native = .{
|
||||||
|
.wayland = .{
|
||||||
.interfaces = Interfaces{},
|
.interfaces = Interfaces{},
|
||||||
.display = libwaylandclient_global.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,
|
||||||
|
|
@ -101,33 +104,44 @@ pub fn init(
|
||||||
.caps_lock_index = undefined,
|
.caps_lock_index = undefined,
|
||||||
.num_lock_index = undefined,
|
.num_lock_index = undefined,
|
||||||
},
|
},
|
||||||
|
// These undefined values require the initialization of `.interfaces` which happens in the registry listener
|
||||||
.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,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
var wl = &linux.backend.wayland;
|
|
||||||
wl.xkb_context = wl.libxkbcommon.xkb_context_new(0) orelse return error.FailedToGetXkbContext;
|
// Save so that the new `.native` value is accessible from the registry listener
|
||||||
|
core.windows.setValue(window_id, core_window);
|
||||||
|
var wl = &core_window.native.?.wayland;
|
||||||
|
|
||||||
const registry = c.wl_display_get_registry(wl.display) orelse return error.FailedToGetDisplayRegistry;
|
const registry = c.wl_display_get_registry(wl.display) orelse return error.FailedToGetDisplayRegistry;
|
||||||
|
|
||||||
// TODO: handle error return value here
|
if (c.wl_registry_add_listener(registry, ®istry_listener.listener, @ptrFromInt(window_id)) != 0) {
|
||||||
_ = c.wl_registry_add_listener(registry, ®istry_listener.listener, linux);
|
return error.ListenerHasAlreadyBeenSet;
|
||||||
|
}
|
||||||
|
|
||||||
//Round trip to get all the registry objects
|
// TODO: Look at replacing these 2 calls to wl_display_roundtrip with wl_display::sync
|
||||||
_ = wl.libwaylandclient.wl_display_roundtrip(wl.display);
|
// Round trip to get all the registry objects
|
||||||
|
_ = libwaylandclient.wl_display_roundtrip(wl.display);
|
||||||
|
|
||||||
//Round trip to get all initial output events
|
// Round trip to get all initial output events
|
||||||
_ = wl.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);
|
||||||
|
wl = &core_window.native.?.wayland;
|
||||||
|
|
||||||
if (wl.interfaces.zxdg_decoration_manager_v1 == null) {
|
if (wl.interfaces.zxdg_decoration_manager_v1 == null) {
|
||||||
return error.NoServerSideDecorationSupport;
|
return error.NoServerSideDecorationSupport;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Setup surface
|
// Setup surface
|
||||||
wl.surface = c.wl_compositor_create_surface(wl.interfaces.wl_compositor) orelse return error.UnableToCreateSurface;
|
wl.surface = c.wl_compositor_create_surface(wl.interfaces.wl_compositor) orelse return error.UnableToCreateSurface;
|
||||||
wl.surface_descriptor = try options.allocator.create(gpu.Surface.DescriptorFromWaylandSurface);
|
wl.surface_descriptor = .{ .display = wl.display, .surface = wl.surface };
|
||||||
wl.surface_descriptor.* = .{ .display = wl.display, .surface = wl.surface };
|
|
||||||
|
|
||||||
|
// Setup opaque region
|
||||||
{
|
{
|
||||||
const region = c.wl_compositor_create_region(wl.interfaces.wl_compositor) orelse return error.CouldntCreateWaylandRegtion;
|
const region = c.wl_compositor_create_region(wl.interfaces.wl_compositor) orelse return error.CouldntCreateWaylandRegtion;
|
||||||
|
|
||||||
|
|
@ -135,8 +149,8 @@ pub fn init(
|
||||||
region,
|
region,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@intCast(linux.size.width),
|
@intCast(core_window.width),
|
||||||
@intCast(linux.size.height),
|
@intCast(core_window.height),
|
||||||
);
|
);
|
||||||
c.wl_surface_set_opaque_region(wl.surface, region);
|
c.wl_surface_set_opaque_region(wl.surface, region);
|
||||||
c.wl_region_destroy(region);
|
c.wl_region_destroy(region);
|
||||||
|
|
@ -145,20 +159,36 @@ pub fn init(
|
||||||
const xdg_surface = c.xdg_wm_base_get_xdg_surface(wl.interfaces.xdg_wm_base, wl.surface) orelse return error.UnableToCreateXdgSurface;
|
const xdg_surface = c.xdg_wm_base_get_xdg_surface(wl.interfaces.xdg_wm_base, wl.surface) orelse return error.UnableToCreateXdgSurface;
|
||||||
wl.toplevel = c.xdg_surface_get_toplevel(xdg_surface) orelse return error.UnableToGetXdgTopLevel;
|
wl.toplevel = c.xdg_surface_get_toplevel(xdg_surface) orelse return error.UnableToGetXdgTopLevel;
|
||||||
|
|
||||||
// TODO: handle this return value
|
// Save so that xdg listeners can use the `wl.surface`
|
||||||
_ = c.xdg_surface_add_listener(xdg_surface, &xdg_surface_listener.listener, linux);
|
core_ptr.windows.setValue(window_id, core_window);
|
||||||
|
|
||||||
// TODO: handle this return value
|
if (c.xdg_surface_add_listener(xdg_surface, &xdg_surface_listener.listener, @ptrFromInt(window_id)) != 0) {
|
||||||
_ = c.xdg_toplevel_add_listener(wl.toplevel, &xdg_toplevel_listener.listener, linux);
|
return error.ListenerHasAlreadyBeenSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.xdg_toplevel_add_listener(wl.toplevel, &xdg_toplevel_listener.listener, @ptrFromInt(window_id)) != 0) {
|
||||||
|
return error.ListenerHasAlreadyBeenSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for events to get pushed
|
||||||
|
_ = libwaylandclient.wl_display_roundtrip(wl.display);
|
||||||
|
|
||||||
|
core_window = core.windows.getValue(window_id);
|
||||||
|
wl = &core_window.native.?.wayland;
|
||||||
|
|
||||||
// Commit changes to surface
|
// Commit changes to surface
|
||||||
c.wl_surface_commit(wl.surface);
|
c.wl_surface_commit(wl.surface);
|
||||||
|
|
||||||
while (wl.libwaylandclient.wl_display_dispatch(wl.display) != -1 and !wl.configured) {
|
while (true) {
|
||||||
// This space intentionally left blank
|
const result = libwaylandclient.wl_display_dispatch(wl.display);
|
||||||
|
|
||||||
|
core_window = core.windows.getValue(window_id);
|
||||||
|
wl = &core_window.native.?.wayland;
|
||||||
|
|
||||||
|
if (result != -1 and wl.configured) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
c.xdg_toplevel_set_title(wl.toplevel, options.title);
|
c.xdg_toplevel_set_title(wl.toplevel, @ptrCast(core_window.title));
|
||||||
|
|
||||||
const decoration = c.zxdg_decoration_manager_v1_get_toplevel_decoration(
|
const decoration = c.zxdg_decoration_manager_v1_get_toplevel_decoration(
|
||||||
wl.interfaces.zxdg_decoration_manager_v1,
|
wl.interfaces.zxdg_decoration_manager_v1,
|
||||||
|
|
@ -169,28 +199,30 @@ pub fn init(
|
||||||
|
|
||||||
// Commit changes to surface
|
// Commit changes to surface
|
||||||
c.wl_surface_commit(wl.surface);
|
c.wl_surface_commit(wl.surface);
|
||||||
// TODO: handle return value
|
|
||||||
_ = wl.libwaylandclient.wl_display_roundtrip(wl.display);
|
_ = libwaylandclient.wl_display_roundtrip(wl.display);
|
||||||
|
|
||||||
|
core.windows.setValue(window_id, core_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(
|
// pub fn deinit(
|
||||||
wl: *Wayland,
|
// wl: *Wayland,
|
||||||
linux: *Linux,
|
// linux: *Linux,
|
||||||
) void {
|
// ) void {
|
||||||
linux.allocator.destroy(wl.surface_descriptor);
|
// linux.allocator.destroy(wl.surface_descriptor);
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub fn update(wl: *Wayland, linux: *Linux) !void {
|
pub fn tick(window_id: mach.ObjectID) !void {
|
||||||
_ = linux;
|
const wl = &core_ptr.windows.getValue(window_id).native.?.wayland;
|
||||||
|
|
||||||
while (wl.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 = wl.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,
|
||||||
},
|
},
|
||||||
|
|
@ -204,9 +236,7 @@ pub fn update(wl: *Wayland, linux: *Linux) !void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = wl.libwaylandclient.wl_display_roundtrip(wl.display);
|
_ = libwaylandclient.wl_display_roundtrip(wl.display);
|
||||||
|
|
||||||
wl.core.input.tick();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setTitle(wl: *Wayland, title: [:0]const u8) void {
|
pub fn setTitle(wl: *Wayland, title: [:0]const u8) void {
|
||||||
|
|
@ -259,6 +289,7 @@ const LibWaylandClient = struct {
|
||||||
wl_display_connect: *const @TypeOf(c.wl_display_connect),
|
wl_display_connect: *const @TypeOf(c.wl_display_connect),
|
||||||
wl_display_roundtrip: *const @TypeOf(c.wl_display_roundtrip),
|
wl_display_roundtrip: *const @TypeOf(c.wl_display_roundtrip),
|
||||||
wl_display_dispatch: *const @TypeOf(c.wl_display_dispatch),
|
wl_display_dispatch: *const @TypeOf(c.wl_display_dispatch),
|
||||||
|
wl_display_dispatch_pending: *const @TypeOf(c.wl_display_dispatch_pending),
|
||||||
wl_display_flush: *const @TypeOf(c.wl_display_flush),
|
wl_display_flush: *const @TypeOf(c.wl_display_flush),
|
||||||
wl_display_get_fd: *const @TypeOf(c.wl_display_get_fd),
|
wl_display_get_fd: *const @TypeOf(c.wl_display_get_fd),
|
||||||
wl_proxy_add_listener: *const @TypeOf(c.wl_proxy_add_listener),
|
wl_proxy_add_listener: *const @TypeOf(c.wl_proxy_add_listener),
|
||||||
|
|
@ -326,43 +357,47 @@ const KeyModInd = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
const registry_listener = struct {
|
const registry_listener = struct {
|
||||||
fn registryHandleGlobal(linux: *Linux, registry: ?*c.struct_wl_registry, name: u32, interface_ptr: [*:0]const u8, version: u32) callconv(.C) void {
|
fn registryHandleGlobal(window_id: mach.ObjectID, registry: ?*c.struct_wl_registry, name: u32, interface_ptr: [*:0]const u8, version: u32) callconv(.C) void {
|
||||||
const interface = std.mem.span(interface_ptr);
|
const interface = std.mem.span(interface_ptr);
|
||||||
const wl = &linux.backend.wayland;
|
var core_window = core_ptr.windows.getValue(window_id);
|
||||||
|
const wl = &core_window.native.?.wayland;
|
||||||
|
|
||||||
if (std.mem.eql(u8, "wl_compositor", interface)) {
|
if (std.mem.eql(u8, "wl_compositor", interface)) {
|
||||||
wl.interfaces.wl_compositor = @ptrCast(c.wl_registry_bind(
|
wl.interfaces.wl_compositor = @ptrCast(c.wl_registry_bind(
|
||||||
registry,
|
registry,
|
||||||
name,
|
name,
|
||||||
wl.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)) {
|
||||||
|
// TODO: Remove this binding because we aren't using wl_shm
|
||||||
wl.interfaces.wl_subcompositor = @ptrCast(c.wl_registry_bind(
|
wl.interfaces.wl_subcompositor = @ptrCast(c.wl_registry_bind(
|
||||||
registry,
|
registry,
|
||||||
name,
|
name,
|
||||||
wl.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)) {
|
||||||
|
// TODO: Remove this binding because we aren't using wl_shm
|
||||||
wl.interfaces.wl_shm = @ptrCast(c.wl_registry_bind(
|
wl.interfaces.wl_shm = @ptrCast(c.wl_registry_bind(
|
||||||
registry,
|
registry,
|
||||||
name,
|
name,
|
||||||
wl.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)) {
|
||||||
|
// TODO: Determine if this is being used. If it is, make a comment here
|
||||||
wl.interfaces.wl_output = @ptrCast(c.wl_registry_bind(
|
wl.interfaces.wl_output = @ptrCast(c.wl_registry_bind(
|
||||||
registry,
|
registry,
|
||||||
name,
|
name,
|
||||||
wl.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,
|
||||||
// wl.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)) {
|
||||||
|
|
@ -374,7 +409,7 @@ const registry_listener = struct {
|
||||||
) orelse @panic("uh idk how to proceed"));
|
) orelse @panic("uh idk how to proceed"));
|
||||||
|
|
||||||
// TODO: handle return value
|
// TODO: handle return value
|
||||||
_ = c.xdg_wm_base_add_listener(wl.interfaces.xdg_wm_base, &xdg_wm_base_listener.listener, linux);
|
_ = c.xdg_wm_base_add_listener(wl.interfaces.xdg_wm_base, &xdg_wm_base_listener.listener, @ptrFromInt(window_id));
|
||||||
} else if (std.mem.eql(u8, "zxdg_decoration_manager_v1", interface)) {
|
} else if (std.mem.eql(u8, "zxdg_decoration_manager_v1", interface)) {
|
||||||
wl.interfaces.zxdg_decoration_manager_v1 = @ptrCast(c.wl_registry_bind(
|
wl.interfaces.zxdg_decoration_manager_v1 = @ptrCast(c.wl_registry_bind(
|
||||||
registry,
|
registry,
|
||||||
|
|
@ -386,17 +421,21 @@ 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,
|
||||||
wl.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"));
|
||||||
|
|
||||||
// TODO: handle return value
|
// TODO: handle return value
|
||||||
_ = c.wl_seat_add_listener(wl.interfaces.wl_seat, &seat_listener.listener, linux);
|
_ = c.wl_seat_add_listener(wl.interfaces.wl_seat, &seat_listener.listener, @ptrFromInt(window_id));
|
||||||
|
} else {
|
||||||
|
// No changes made to `wl`, so exit function
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
core_ptr.windows.setValue(window_id, core_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn registryHandleGlobalRemove(linux: *Linux, registry: ?*c.struct_wl_registry, name: u32) callconv(.C) void {
|
fn registryHandleGlobalRemove(window_id: mach.ObjectID, registry: ?*c.struct_wl_registry, name: u32) callconv(.C) void {
|
||||||
_ = linux;
|
_ = window_id;
|
||||||
_ = registry;
|
_ = registry;
|
||||||
_ = name;
|
_ = name;
|
||||||
}
|
}
|
||||||
|
|
@ -410,9 +449,10 @@ const registry_listener = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
const keyboard_listener = struct {
|
const keyboard_listener = struct {
|
||||||
fn keyboardHandleKeymap(linux: *Linux, keyboard: ?*c.struct_wl_keyboard, format: u32, fd: i32, keymap_size: u32) callconv(.C) void {
|
fn keyboardHandleKeymap(window_id: mach.ObjectID, keyboard: ?*c.struct_wl_keyboard, format: u32, fd: i32, keymap_size: u32) callconv(.C) void {
|
||||||
_ = keyboard;
|
_ = keyboard;
|
||||||
const wl = &linux.backend.wayland;
|
var core_window = core_ptr.windows.getValue(window_id);
|
||||||
|
const wl = &core_window.native.?.wayland;
|
||||||
|
|
||||||
if (format != c.WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
|
if (format != c.WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
|
||||||
@panic("TODO");
|
@panic("TODO");
|
||||||
|
|
@ -420,7 +460,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 = wl.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,
|
||||||
|
|
@ -433,13 +473,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
|
||||||
wl.libxkbcommon.xkb_state_unref(wl.xkb_state);
|
libxkbcommon.xkb_state_unref(wl.xkb_state);
|
||||||
const state = wl.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 = wl.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,
|
||||||
|
|
@ -447,85 +487,86 @@ 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 = wl.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 wl.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 = wl.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 = wl.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 = wl.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 = wl.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 = wl.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 = wl.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 = wl.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);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keyboardHandleEnter(linux: *Linux, keyboard: ?*c.struct_wl_keyboard, serial: u32, surface: ?*c.struct_wl_surface, keys: [*c]c.struct_wl_array) callconv(.C) void {
|
fn keyboardHandleEnter(window_id: mach.ObjectID, keyboard: ?*c.struct_wl_keyboard, serial: u32, surface: ?*c.struct_wl_surface, keys: [*c]c.struct_wl_array) callconv(.C) void {
|
||||||
_ = keyboard;
|
_ = keyboard;
|
||||||
_ = serial;
|
_ = serial;
|
||||||
_ = surface;
|
_ = surface;
|
||||||
_ = keys;
|
_ = keys;
|
||||||
const wl = &linux.backend.wayland;
|
|
||||||
|
|
||||||
wl.core.pushEvent(.focus_gained);
|
core_ptr.pushEvent(.{ .focus_gained = .{ .window_id = window_id } });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keyboardHandleLeave(linux: *Linux, keyboard: ?*c.struct_wl_keyboard, serial: u32, surface: ?*c.struct_wl_surface) callconv(.C) void {
|
fn keyboardHandleLeave(window_id: mach.ObjectID, keyboard: ?*c.struct_wl_keyboard, serial: u32, surface: ?*c.struct_wl_surface) callconv(.C) void {
|
||||||
_ = keyboard;
|
_ = keyboard;
|
||||||
_ = serial;
|
_ = serial;
|
||||||
_ = surface;
|
_ = surface;
|
||||||
const wl = &linux.backend.wayland;
|
|
||||||
|
|
||||||
wl.core.pushEvent(.focus_lost);
|
core_ptr.pushEvent(.{ .focus_lost = .{ .window_id = window_id } });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keyboardHandleKey(linux: *Linux, keyboard: ?*c.struct_wl_keyboard, serial: u32, time: u32, scancode: u32, state: u32) callconv(.C) void {
|
fn keyboardHandleKey(window_id: mach.ObjectID, keyboard: ?*c.struct_wl_keyboard, serial: u32, time: u32, scancode: u32, state: u32) callconv(.C) void {
|
||||||
_ = keyboard;
|
_ = keyboard;
|
||||||
_ = serial;
|
_ = serial;
|
||||||
_ = time;
|
_ = time;
|
||||||
var wl = &linux.backend.wayland;
|
const wl = &core_ptr.windows.getValue(window_id).native.?.wayland;
|
||||||
|
|
||||||
const pressed = state == 1;
|
const pressed = state == 1;
|
||||||
|
|
||||||
const key_event = KeyEvent{ .key = toMachKey(scancode), .mods = wl.modifiers };
|
const key_event = KeyEvent{ .key = toMachKey(scancode), .mods = wl.modifiers, .window_id = window_id };
|
||||||
|
|
||||||
if (pressed) {
|
if (pressed) {
|
||||||
wl.core.pushEvent(.{ .key_press = key_event });
|
core_ptr.pushEvent(.{ .key_press = key_event });
|
||||||
|
|
||||||
var keysyms: ?[*]c.xkb_keysym_t = undefined;
|
var keysyms: ?[*]c.xkb_keysym_t = undefined;
|
||||||
//Get the keysym from the keycode (scancode + 8)
|
//Get the keysym from the keycode (scancode + 8)
|
||||||
if (wl.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 = wl.libxkbcommon.xkb_keysym_to_utf32(keysym);
|
const codepoint = libxkbcommon.xkb_keysym_to_utf32(keysym);
|
||||||
if (codepoint != 0) {
|
if (codepoint != 0) {
|
||||||
wl.core.pushEvent(Core.Event{ .char_input = .{ .codepoint = @truncate(codepoint) } });
|
core_ptr.pushEvent(.{ .char_input = .{ .codepoint = @truncate(codepoint), .window_id = window_id } });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
wl.core.pushEvent(.{ .key_release = key_event });
|
core_ptr.pushEvent(.{ .key_release = key_event });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keyboardHandleModifiers(linux: *Linux, keyboard: ?*c.struct_wl_keyboard, serial: u32, mods_depressed: u32, mods_latched: u32, mods_locked: u32, group: u32) callconv(.C) void {
|
fn keyboardHandleModifiers(window_id: mach.ObjectID, keyboard: ?*c.struct_wl_keyboard, serial: u32, mods_depressed: u32, mods_latched: u32, mods_locked: u32, group: u32) callconv(.C) void {
|
||||||
_ = keyboard;
|
_ = keyboard;
|
||||||
_ = serial;
|
_ = serial;
|
||||||
var wl = &linux.backend.wayland;
|
var core_window = core_ptr.windows.getValue(window_id);
|
||||||
|
const wl = &core_window.native.?.wayland;
|
||||||
|
|
||||||
if (wl.keymap == null)
|
if (wl.keymap == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// TODO: handle this return value
|
// TODO: handle this return value
|
||||||
_ = wl.libxkbcommon.xkb_state_update_mask(
|
_ = libxkbcommon.xkb_state_update_mask(
|
||||||
wl.xkb_state.?,
|
wl.xkb_state.?,
|
||||||
mods_depressed,
|
mods_depressed,
|
||||||
mods_latched,
|
mods_latched,
|
||||||
|
|
@ -544,16 +585,18 @@ 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]) = wl.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,
|
||||||
) == 1;
|
) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
core_ptr.windows.setValue(window_id, core_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keyboardHandleRepeatInfo(linux: *Linux, keyboard: ?*c.struct_wl_keyboard, rate: i32, delay: i32) callconv(.C) void {
|
fn keyboardHandleRepeatInfo(window_id: mach.ObjectID, keyboard: ?*c.struct_wl_keyboard, rate: i32, delay: i32) callconv(.C) void {
|
||||||
_ = linux;
|
_ = window_id;
|
||||||
_ = keyboard;
|
_ = keyboard;
|
||||||
_ = rate;
|
_ = rate;
|
||||||
_ = delay;
|
_ = delay;
|
||||||
|
|
@ -570,102 +613,103 @@ const keyboard_listener = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
const pointer_listener = struct {
|
const pointer_listener = struct {
|
||||||
fn handlePointerAxis(linux: *Linux, pointer: ?*c.struct_wl_pointer, time: u32, axis: u32, value: c.wl_fixed_t) callconv(.C) void {
|
fn handlePointerAxis(window_id: mach.ObjectID, pointer: ?*c.struct_wl_pointer, time: u32, axis: u32, value: c.wl_fixed_t) callconv(.C) void {
|
||||||
_ = linux;
|
_ = window_id;
|
||||||
_ = pointer;
|
_ = pointer;
|
||||||
_ = time;
|
_ = time;
|
||||||
_ = axis;
|
_ = axis;
|
||||||
_ = value;
|
_ = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handlePointerFrame(linux: *Linux, pointer: ?*c.struct_wl_pointer) callconv(.C) void {
|
fn handlePointerFrame(window_id: mach.ObjectID, pointer: ?*c.struct_wl_pointer) callconv(.C) void {
|
||||||
_ = linux;
|
_ = window_id;
|
||||||
_ = pointer;
|
_ = pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handlePointerAxisSource(linux: *Linux, pointer: ?*c.struct_wl_pointer, axis_source: u32) callconv(.C) void {
|
fn handlePointerAxisSource(window_id: mach.ObjectID, pointer: ?*c.struct_wl_pointer, axis_source: u32) callconv(.C) void {
|
||||||
_ = linux;
|
_ = window_id;
|
||||||
_ = pointer;
|
_ = pointer;
|
||||||
_ = axis_source;
|
_ = axis_source;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handlePointerAxisStop(linux: *Linux, pointer: ?*c.struct_wl_pointer, time: u32, axis: u32) callconv(.C) void {
|
fn handlePointerAxisStop(window_id: mach.ObjectID, pointer: ?*c.struct_wl_pointer, time: u32, axis: u32) callconv(.C) void {
|
||||||
_ = linux;
|
_ = window_id;
|
||||||
_ = pointer;
|
_ = pointer;
|
||||||
_ = time;
|
_ = time;
|
||||||
_ = axis;
|
_ = axis;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handlePointerAxisDiscrete(linux: *Linux, pointer: ?*c.struct_wl_pointer, axis: u32, discrete: i32) callconv(.C) void {
|
fn handlePointerAxisDiscrete(window_id: mach.ObjectID, pointer: ?*c.struct_wl_pointer, axis: u32, discrete: i32) callconv(.C) void {
|
||||||
_ = linux;
|
_ = window_id;
|
||||||
_ = pointer;
|
_ = pointer;
|
||||||
_ = axis;
|
_ = axis;
|
||||||
_ = discrete;
|
_ = discrete;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handlePointerAxisValue120(linux: *Linux, pointer: ?*c.struct_wl_pointer, axis: u32, value_120: i32) callconv(.C) void {
|
fn handlePointerAxisValue120(window_id: mach.ObjectID, pointer: ?*c.struct_wl_pointer, axis: u32, value_120: i32) callconv(.C) void {
|
||||||
_ = linux;
|
_ = window_id;
|
||||||
_ = pointer;
|
_ = pointer;
|
||||||
_ = axis;
|
_ = axis;
|
||||||
_ = value_120;
|
_ = value_120;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handlePointerAxisRelativeDirection(linux: *Linux, pointer: ?*c.struct_wl_pointer, axis: u32, direction: u32) callconv(.C) void {
|
fn handlePointerAxisRelativeDirection(window_id: mach.ObjectID, pointer: ?*c.struct_wl_pointer, axis: u32, direction: u32) callconv(.C) void {
|
||||||
_ = linux;
|
_ = window_id;
|
||||||
_ = pointer;
|
_ = pointer;
|
||||||
_ = axis;
|
_ = axis;
|
||||||
_ = direction;
|
_ = direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handlePointerEnter(linux: *Linux, pointer: ?*c.struct_wl_pointer, serial: u32, surface: ?*c.struct_wl_surface, fixed_x: c.wl_fixed_t, fixed_y: c.wl_fixed_t) callconv(.C) void {
|
fn handlePointerEnter(window_id: mach.ObjectID, pointer: ?*c.struct_wl_pointer, serial: u32, surface: ?*c.struct_wl_surface, fixed_x: c.wl_fixed_t, fixed_y: c.wl_fixed_t) callconv(.C) void {
|
||||||
_ = fixed_x;
|
_ = fixed_x;
|
||||||
_ = fixed_y;
|
_ = fixed_y;
|
||||||
_ = linux;
|
_ = window_id;
|
||||||
_ = pointer;
|
_ = pointer;
|
||||||
_ = serial;
|
_ = serial;
|
||||||
_ = surface;
|
_ = surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handlePointerLeave(linux: *Linux, pointer: ?*c.struct_wl_pointer, serial: u32, surface: ?*c.struct_wl_surface) callconv(.C) void {
|
fn handlePointerLeave(window_id: mach.ObjectID, pointer: ?*c.struct_wl_pointer, serial: u32, surface: ?*c.struct_wl_surface) callconv(.C) void {
|
||||||
_ = linux;
|
_ = window_id;
|
||||||
_ = pointer;
|
_ = pointer;
|
||||||
_ = serial;
|
_ = serial;
|
||||||
_ = surface;
|
_ = surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handlePointerMotion(linux: *Linux, pointer: ?*c.struct_wl_pointer, serial: u32, fixed_x: c.wl_fixed_t, fixed_y: c.wl_fixed_t) callconv(.C) void {
|
fn handlePointerMotion(window_id: mach.ObjectID, pointer: ?*c.struct_wl_pointer, serial: u32, fixed_x: c.wl_fixed_t, fixed_y: c.wl_fixed_t) callconv(.C) void {
|
||||||
_ = pointer;
|
_ = pointer;
|
||||||
_ = serial;
|
_ = serial;
|
||||||
var wl = &linux.backend.wayland;
|
|
||||||
|
|
||||||
const x = c.wl_fixed_to_double(fixed_x);
|
const x = c.wl_fixed_to_double(fixed_x);
|
||||||
const y = c.wl_fixed_to_double(fixed_y);
|
const y = c.wl_fixed_to_double(fixed_y);
|
||||||
|
|
||||||
wl.core.pushEvent(.{ .mouse_motion = .{ .pos = .{ .x = x, .y = y } } });
|
core_ptr.pushEvent(.{ .mouse_motion = .{ .pos = .{ .x = x, .y = y }, .window_id = window_id } });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handlePointerButton(linux: *Linux, pointer: ?*c.struct_wl_pointer, serial: u32, time: u32, button: u32, state: u32) callconv(.C) void {
|
fn handlePointerButton(window_id: mach.ObjectID, pointer: ?*c.struct_wl_pointer, serial: u32, time: u32, button: u32, state: u32) callconv(.C) void {
|
||||||
_ = pointer;
|
_ = pointer;
|
||||||
_ = serial;
|
_ = serial;
|
||||||
_ = time;
|
_ = time;
|
||||||
var wl = &linux.backend.wayland;
|
const wl = &core_ptr.windows.getValue(window_id).native.?.wayland;
|
||||||
|
|
||||||
const mouse_button: Core.MouseButton = @enumFromInt(button - c.BTN_LEFT);
|
const mouse_button: Core.MouseButton = @enumFromInt(button - c.BTN_LEFT);
|
||||||
const pressed = state == c.WL_POINTER_BUTTON_STATE_PRESSED;
|
const pressed = state == c.WL_POINTER_BUTTON_STATE_PRESSED;
|
||||||
const x = wl.core.input_state.mouse_position.x;
|
const x = core_ptr.input_state.mouse_position.x;
|
||||||
const y = wl.core.input_state.mouse_position.y;
|
const y = core_ptr.input_state.mouse_position.y;
|
||||||
|
|
||||||
if (pressed) {
|
if (pressed) {
|
||||||
wl.core.pushEvent(Core.Event{ .mouse_press = .{
|
core_ptr.pushEvent(Core.Event{ .mouse_press = .{
|
||||||
.button = mouse_button,
|
.button = mouse_button,
|
||||||
.mods = wl.modifiers,
|
.mods = wl.modifiers,
|
||||||
.pos = .{ .x = x, .y = y },
|
.pos = .{ .x = x, .y = y },
|
||||||
|
.window_id = window_id,
|
||||||
} });
|
} });
|
||||||
} else {
|
} else {
|
||||||
wl.core.pushEvent(Core.Event{ .mouse_release = .{
|
core_ptr.pushEvent(Core.Event{ .mouse_release = .{
|
||||||
.button = mouse_button,
|
.button = mouse_button,
|
||||||
.mods = wl.modifiers,
|
.mods = wl.modifiers,
|
||||||
.pos = .{ .x = x, .y = y },
|
.pos = .{ .x = x, .y = y },
|
||||||
|
.window_id = window_id,
|
||||||
} });
|
} });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -686,20 +730,23 @@ const pointer_listener = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
const seat_listener = struct {
|
const seat_listener = struct {
|
||||||
fn seatHandleName(linux: *Linux, seat: ?*c.struct_wl_seat, name_ptr: [*:0]const u8) callconv(.C) void {
|
fn seatHandleName(window_id: mach.ObjectID, seat: ?*c.struct_wl_seat, name_ptr: [*:0]const u8) callconv(.C) void {
|
||||||
_ = linux;
|
_ = window_id;
|
||||||
_ = seat;
|
_ = seat;
|
||||||
_ = name_ptr;
|
_ = name_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn seatHandleCapabilities(linux: *Linux, seat: ?*c.struct_wl_seat, caps: c.wl_seat_capability) callconv(.C) void {
|
fn seatHandleCapabilities(window_id: mach.ObjectID, seat: ?*c.struct_wl_seat, caps: c.wl_seat_capability) callconv(.C) void {
|
||||||
const wl = &linux.backend.wayland;
|
var core_window = core_ptr.windows.getValue(window_id);
|
||||||
|
const wl = &core_window.native.?.wayland;
|
||||||
|
var changed = false;
|
||||||
|
|
||||||
if ((caps & c.WL_SEAT_CAPABILITY_KEYBOARD) != 0) {
|
if ((caps & c.WL_SEAT_CAPABILITY_KEYBOARD) != 0) {
|
||||||
|
changed = true;
|
||||||
wl.keyboard = c.wl_seat_get_keyboard(seat);
|
wl.keyboard = c.wl_seat_get_keyboard(seat);
|
||||||
|
|
||||||
// TODO: handle return value
|
// TODO: handle return value
|
||||||
_ = c.wl_keyboard_add_listener(wl.keyboard, &keyboard_listener.listener, linux);
|
_ = c.wl_keyboard_add_listener(wl.keyboard, &keyboard_listener.listener, @ptrFromInt(window_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((caps & c.WL_SEAT_CAPABILITY_TOUCH) != 0) {
|
if ((caps & c.WL_SEAT_CAPABILITY_TOUCH) != 0) {
|
||||||
|
|
@ -707,15 +754,17 @@ const seat_listener = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((caps & c.WL_SEAT_CAPABILITY_POINTER) != 0) {
|
if ((caps & c.WL_SEAT_CAPABILITY_POINTER) != 0) {
|
||||||
|
changed = true;
|
||||||
wl.pointer = c.wl_seat_get_pointer(seat);
|
wl.pointer = c.wl_seat_get_pointer(seat);
|
||||||
|
|
||||||
// TODO: handle return value
|
// TODO: handle return value
|
||||||
_ = c.wl_pointer_add_listener(wl.pointer, &pointer_listener.listener, linux);
|
_ = c.wl_pointer_add_listener(wl.pointer, &pointer_listener.listener, @ptrFromInt(window_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete keyboard if its no longer in the seat
|
// Delete keyboard if its no longer in the seat
|
||||||
if (wl.keyboard) |keyboard| {
|
if (wl.keyboard) |keyboard| {
|
||||||
if ((caps & c.WL_SEAT_CAPABILITY_KEYBOARD) == 0) {
|
if ((caps & c.WL_SEAT_CAPABILITY_KEYBOARD) == 0) {
|
||||||
|
changed = true;
|
||||||
c.wl_keyboard_destroy(keyboard);
|
c.wl_keyboard_destroy(keyboard);
|
||||||
wl.keyboard = null;
|
wl.keyboard = null;
|
||||||
}
|
}
|
||||||
|
|
@ -723,10 +772,15 @@ const seat_listener = struct {
|
||||||
|
|
||||||
if (wl.pointer) |pointer| {
|
if (wl.pointer) |pointer| {
|
||||||
if ((caps & c.WL_SEAT_CAPABILITY_POINTER) == 0) {
|
if ((caps & c.WL_SEAT_CAPABILITY_POINTER) == 0) {
|
||||||
|
changed = true;
|
||||||
c.wl_pointer_destroy(pointer);
|
c.wl_pointer_destroy(pointer);
|
||||||
wl.pointer = null;
|
wl.pointer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
core_ptr.windows.setValue(window_id, core_window);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const listener = c.wl_seat_listener{
|
const listener = c.wl_seat_listener{
|
||||||
|
|
@ -736,8 +790,8 @@ const seat_listener = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
const xdg_wm_base_listener = struct {
|
const xdg_wm_base_listener = struct {
|
||||||
fn wmBaseHandlePing(linux: *Linux, wm_base: ?*c.struct_xdg_wm_base, serial: u32) callconv(.C) void {
|
fn wmBaseHandlePing(window_id: mach.ObjectID, wm_base: ?*c.struct_xdg_wm_base, serial: u32) callconv(.C) void {
|
||||||
_ = linux;
|
_ = window_id;
|
||||||
c.xdg_wm_base_pong(wm_base, serial);
|
c.xdg_wm_base_pong(wm_base, serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -745,34 +799,41 @@ const xdg_wm_base_listener = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
const xdg_surface_listener = struct {
|
const xdg_surface_listener = struct {
|
||||||
fn xdgSurfaceHandleConfigure(linux: *Linux, xdg_surface: ?*c.struct_xdg_surface, serial: u32) callconv(.C) void {
|
fn xdgSurfaceHandleConfigure(window_id: mach.ObjectID, xdg_surface: ?*c.struct_xdg_surface, serial: u32) callconv(.C) void {
|
||||||
c.xdg_surface_ack_configure(xdg_surface, serial);
|
c.xdg_surface_ack_configure(xdg_surface, serial);
|
||||||
var wl = &linux.backend.wayland;
|
var core_window = core_ptr.windows.getValue(window_id);
|
||||||
|
const wl = &core_window.native.?.wayland;
|
||||||
|
|
||||||
if (wl.configured) {
|
if (wl.configured) {
|
||||||
c.wl_surface_commit(wl.surface);
|
c.wl_surface_commit(wl.surface);
|
||||||
} else {
|
} else {
|
||||||
wl.configured = true;
|
wl.configured = true;
|
||||||
|
core_ptr.windows.setValue(window_id, core_window);
|
||||||
|
core_window = core_ptr.windows.getValue(window_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
setContentAreaOpaque(wl, linux.size);
|
setContentAreaOpaque(wl, Core.Size{ .width = core_window.width, .height = core_window.height });
|
||||||
}
|
}
|
||||||
|
|
||||||
const listener = c.xdg_surface_listener{ .configure = @ptrCast(&xdgSurfaceHandleConfigure) };
|
const listener = c.xdg_surface_listener{ .configure = @ptrCast(&xdgSurfaceHandleConfigure) };
|
||||||
};
|
};
|
||||||
|
|
||||||
const xdg_toplevel_listener = struct {
|
const xdg_toplevel_listener = struct {
|
||||||
fn xdgToplevelHandleClose(linux: *Linux, toplevel: ?*c.struct_xdg_toplevel) callconv(.C) void {
|
fn xdgToplevelHandleClose(window_id: mach.ObjectID, toplevel: ?*c.struct_xdg_toplevel) callconv(.C) void {
|
||||||
_ = linux;
|
// TODO: implement this
|
||||||
|
_ = window_id;
|
||||||
_ = toplevel;
|
_ = toplevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xdgToplevelHandleConfigure(linux: *Linux, toplevel: ?*c.struct_xdg_toplevel, width: i32, height: i32, states: [*c]c.struct_wl_array) callconv(.C) void {
|
fn xdgToplevelHandleConfigure(window_id: mach.ObjectID, toplevel: ?*c.struct_xdg_toplevel, width: i32, height: i32, states: [*c]c.struct_wl_array) callconv(.C) void {
|
||||||
|
var core_window = core_ptr.windows.getValue(window_id);
|
||||||
_ = toplevel;
|
_ = toplevel;
|
||||||
_ = states;
|
_ = states;
|
||||||
|
|
||||||
if (width > 0 and height > 0) {
|
if (width > 0 and height > 0) {
|
||||||
linux.size = .{ .width = @intCast(width), .height = @intCast(height) };
|
core_window.width = @intCast(width);
|
||||||
|
core_window.height = @intCast(height);
|
||||||
|
core_ptr.windows.setValue(window_id, core_window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -782,15 +843,15 @@ const xdg_toplevel_listener = struct {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
fn composeSymbol(wl: *Wayland, sym: c.xkb_keysym_t) c.xkb_keysym_t {
|
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 (wl.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 (wl.libxkbcommon.xkb_compose_state_get_status(wl.compose_state)) {
|
return switch (libxkbcommon.xkb_compose_state_get_status(wl.compose_state)) {
|
||||||
c.XKB_COMPOSE_COMPOSED => wl.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,
|
||||||
};
|
};
|
||||||
|
|
@ -918,12 +979,13 @@ fn toMachKey(key: u32) Core.Key {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setContentAreaOpaque(wl: *Wayland, new_size: Core.Size) void {
|
fn setContentAreaOpaque(wl: *const Native, new_size: Core.Size) void {
|
||||||
const region = c.wl_compositor_create_region(wl.interfaces.wl_compositor) orelse return;
|
const region = c.wl_compositor_create_region(wl.interfaces.wl_compositor) orelse return;
|
||||||
|
|
||||||
c.wl_region_add(region, 0, 0, @intCast(new_size.width), @intCast(new_size.height));
|
c.wl_region_add(region, 0, 0, @intCast(new_size.width), @intCast(new_size.height));
|
||||||
c.wl_surface_set_opaque_region(wl.surface, region);
|
c.wl_surface_set_opaque_region(wl.surface, region);
|
||||||
c.wl_region_destroy(region);
|
c.wl_region_destroy(region);
|
||||||
|
|
||||||
wl.core.swap_chain_update.set();
|
// FIX: What is the Mach Object System way of doing this?
|
||||||
|
// core_ptr.swap_chain_update.set();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue