Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

linux: setup with new object system #1319

Merged
merged 6 commits into from
Dec 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 50 additions & 56 deletions src/core/Linux.zig
Original file line number Diff line number Diff line change
Expand Up @@ -56,43 +56,41 @@ backend: Backend,
// these arrays are used as info messages to the user that some features are missing
// please keep these up to date until we can remove them
const MISSING_FEATURES_X11 = [_][]const u8{ "Resizing window", "Changing display mode", "VSync", "Setting window border/cursor" };
const MISSING_FEATURES_WAYLAND = [_][]const u8{ "Changing display mode", "VSync", "Setting window border/cursor" };
const MISSING_FEATURES_WAYLAND = [_][]const u8{ "Resizing window", "Changing display mode", "VSync", "Setting window border/cursor" };

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| {
check_for_mach_updates(core, window_id);
// check for display server events
switch (native) {
.x11 => try X11.tick(window_id),
.wayland => try Wayland.tick(window_id),
}
} else {
try initWindow(core, window_id);
}
}
}

pub fn init(
linux: *Linux,
pub fn initWindow(
core: *Core,
options: InitOptions,
window_id: mach.ObjectID,
) !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 backend = std.process.getEnvVarOwned(
linux.allocator,
core.allocator,
"MACH_BACKEND",
) catch |err| switch (err) {
error.EnvironmentVariableNotFound => {
// default backend
break :blk .wayland;
},
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, "wayland")) break :blk .wayland;
Expand All @@ -102,54 +100,45 @@ pub fn init(
// Try to initialize the desired backend, falling back to the other if that one is not supported
switch (desired_backend) {
.x11 => {
X11.init(linux, core, options) catch |err| {
X11.initWindow(core, window_id) catch |err| {
const err_msg = switch (err) {
error.LibraryNotFound => "Missing X11 library",
error.FailedToConnectToDisplay => "Failed to connect to X11 display",
else => "An unknown error occured while trying to connect to X11",
};
log.err("{s}\n\nFalling back to Wayland\n", .{err_msg});
try Wayland.init(linux, core, options);
try Wayland.initWindow(core, window_id);
};
},
.wayland => {
Wayland.init(linux, core, options) catch |err| {
Wayland.initWindow(core, window_id) catch |err| {
const err_msg = switch (err) {
error.NoServerSideDecorationSupport => "Server Side Decorations aren't supported",
error.LibraryNotFound => "Missing Wayland library",
error.FailedToConnectToDisplay => "Failed to connect to Wayland display",
else => "An unknown error occured while trying to connect to Wayland",
};
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
// 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 {
if (linux.gamemode != null and linux.gamemode.?) deinitLinuxGamemode();

linux.allocator.free(linux.title);

switch (linux.backend) {
.wayland => linux.backend.wayland.deinit(linux),
.x11 => linux.backend.x11.deinit(linux),
}
}
// pub fn deinit(linux: *Linux) void {
// if (linux.gamemode != null and linux.gamemode.?) deinitLinuxGamemode();
//
// linux.allocator.free(linux.title);
//
// switch (linux.backend) {
// .wayland => linux.backend.wayland.deinit(linux),
// .x11 => linux.backend.x11.deinit(linux),
// }
// }

pub fn update(linux: *Linux) !void {
switch (linux.backend) {
Expand All @@ -158,16 +147,10 @@ pub fn update(linux: *Linux) !void {
}
}

pub fn setTitle(linux: *Linux, title: [:0]const u8) void {
const new_title = linux.allocator.dupeZ(u8, title) catch {
log.err("Failed to reallocate memory for new window title", .{});
return;
};
linux.allocator.free(linux.title);
linux.title = new_title;
switch (linux.backend) {
.wayland => linux.backend.wayland.setTitle(linux.title),
.x11 => linux.backend.x11.setTitle(linux.title),
fn setTitle(native: *const Native, title: [:0]const u8) void {
switch (native.*) {
.wayland => |wl| Wayland.setTitle(&wl, title),
.x11 => |x| X11.setTitle(&x, title),
}
}

Expand Down Expand Up @@ -204,6 +187,17 @@ pub fn setCursorShape(_: *Linux, _: CursorShape) void {
return;
}

/// Checks for updates in mach object fields. Does nothing if window is not initialized.
fn check_for_mach_updates(core: *Core, window_id: mach.ObjectID) void {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should remove this function and inline this functionality where written

const core_window = core.windows.getValue(window_id);
const native = &core_window.native;
if (native.*) |n| {
if (core.windows.updated(window_id, .title)) {
setTitle(&n, core_window.title);
}
}
}

/// Check if gamemode should be activated
pub fn wantGamemode(allocator: std.mem.Allocator) error{ OutOfMemory, InvalidWtf8 }!bool {
const use_gamemode = std.process.getEnvVarOwned(
Expand Down
Loading
Loading