From a218a20c9225f2a11f787a4ff1922f25ab9d930a Mon Sep 17 00:00:00 2001 From: Joshua Holmes Date: Thu, 10 Oct 2024 12:54:00 -0700 Subject: [PATCH 1/6] core: enable x11 and set as default for linux --- src/core/Linux.zig | 49 +++++++++++++++++++++++------------------- src/core/linux/X11.zig | 10 ++++----- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/src/core/Linux.zig b/src/core/Linux.zig index 7b9e00770b..e826fca7ca 100644 --- a/src/core/Linux.zig +++ b/src/core/Linux.zig @@ -54,6 +54,14 @@ pub fn init( 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; + if (!options.headless) { + // TODO: this function does nothing right now + setDisplayMode(linux, options.display_mode); + } const desired_backend: BackendEnum = blk: { const backend = std.process.getEnvVarOwned( @@ -61,8 +69,7 @@ pub fn init( "MACH_CORE_BACKEND", ) catch |err| switch (err) { error.EnvironmentVariableNotFound => { - // TODO(core): default to .x11 in the future - break :blk .wayland; + break :blk .x11; }, else => return err, }; @@ -73,31 +80,27 @@ pub fn init( std.debug.panic("mach: unknown MACH_CORE_BACKEND: {s}", .{backend}); }; - if (desired_backend == .x11) { - // TODO(core): support X11 in the future - @panic("X11 is not supported...YET"); - } - // Try to initialize the desired backend, falling back to the other if that one is not supported switch (desired_backend) { - .x11 => { - // const x11 = X11.init(linux, core, options) catch |err| switch (err) { - // error.NotSupported => { - // log.err("failed to initialize X11 backend, falling back to Wayland", .{}); - // linux.backend = .{ .wayland = try Wayland.init(linux, core, options) }; - // }, - // else => return err, - // }; - // linux.backend = .{ .x11 = x11 }; + .x11 => blk: { + const x11 = X11.init(linux, core, options) catch |err| switch (err) { + error.LibraryNotFound => { + log.err("failed to initialize X11 backend, falling back to Wayland", .{}); + linux.backend = .{ .wayland = try Wayland.init(linux, core, options) }; + + break :blk; + }, + else => return err, + }; + linux.backend = .{ .x11 = x11 }; }, - .wayland => { + .wayland => blk: { const wayland = Wayland.init(linux, core, options) catch |err| switch (err) { error.LibraryNotFound => { log.err("failed to initialize Wayland backend, falling back to X11", .{}); linux.backend = .{ .x11 = try X11.init(linux, core, options) }; - // TODO(core): support X11 in the future - @panic("X11 is not supported...YET"); + break :blk; }, else => return err, }; @@ -114,8 +117,6 @@ pub fn init( }, } - linux.refresh_rate = 60; // TODO: set to something meaningful - return; } @@ -129,7 +130,11 @@ pub fn deinit(linux: *Linux) void { return; } -pub fn update(_: *Linux) !void { +pub fn update(linux: *Linux) !void { + switch (linux.backend) { + .wayland => {}, + .x11 => try linux.backend.x11.update(), + } return; } diff --git a/src/core/linux/X11.zig b/src/core/linux/X11.zig index c73835cf5a..bf84485afd 100644 --- a/src/core/linux/X11.zig +++ b/src/core/linux/X11.zig @@ -74,7 +74,7 @@ display_mode: DisplayMode = .windowed, vsync_mode: VSyncMode = .triple, border: bool, headless: bool, -size: Core.Size, +size: *Core.Size, cursor_mode: CursorMode = .normal, cursor_shape: CursorShape = .arrow, surface_descriptor: *gpu.Surface.DescriptorFromXlibWindow, @@ -119,8 +119,8 @@ pub fn init( root_window, @divFloor(libx11.XDisplayWidth(display, screen), 2), // TODO: add window width? @divFloor(libx11.XDisplayHeight(display, screen), 2), // TODO: add window height? - options.size.width, - options.size.height, + linux.size.width, + linux.size.height, 0, c.DefaultDepth(display, screen), c.InputOutput, @@ -130,7 +130,7 @@ pub fn init( ); var window_attrs: c.XWindowAttributes = undefined; _ = libx11.XGetWindowAttributes(display, window, &window_attrs); - const window_size = Core.Size{ + linux.size = Core.Size{ .width = @intCast(window_attrs.width), .height = @intCast(window_attrs.height), }; @@ -180,7 +180,7 @@ pub fn init( .display_mode = .windowed, .border = options.border, .headless = options.headless, - .size = window_size, + .size = &linux.size, .cursors = std.mem.zeroes([@typeInfo(CursorShape).@"enum".fields.len]?c.Cursor), .surface_descriptor = surface_descriptor, .libxkbcommon = try LibXkbCommon.load(), From c27ea11dc5d724603022ec5d7a17eaeea6cca6f0 Mon Sep 17 00:00:00 2001 From: Joshua Holmes Date: Thu, 10 Oct 2024 19:27:54 -0700 Subject: [PATCH 2/6] core: fix wayland window size conflict --- src/core/linux/Wayland.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/linux/Wayland.zig b/src/core/linux/Wayland.zig index aa1030a27c..23d70354a9 100644 --- a/src/core/linux/Wayland.zig +++ b/src/core/linux/Wayland.zig @@ -130,8 +130,8 @@ pub fn init( region, 0, 0, - @intCast(options.size.width), - @intCast(options.size.height), + @intCast(wl.size.width), + @intCast(wl.size.height), ); c.wl_surface_set_opaque_region(wl.surface, region); c.wl_region_destroy(region); From ec9df13dfca817f44013e11a28ce9336a46abbf5 Mon Sep 17 00:00:00 2001 From: Joshua Holmes Date: Thu, 10 Oct 2024 21:01:56 -0700 Subject: [PATCH 3/6] core: set wayland as default --- src/core/Linux.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Linux.zig b/src/core/Linux.zig index e826fca7ca..25a0c3c697 100644 --- a/src/core/Linux.zig +++ b/src/core/Linux.zig @@ -69,7 +69,7 @@ pub fn init( "MACH_CORE_BACKEND", ) catch |err| switch (err) { error.EnvironmentVariableNotFound => { - break :blk .x11; + break :blk .wayland; }, else => return err, }; From 2f0097cf57a8eab717806731f81b9a625e02948f Mon Sep 17 00:00:00 2001 From: Joshua Holmes Date: Thu, 10 Oct 2024 21:05:36 -0700 Subject: [PATCH 4/6] core: use MACH_BACKEND instead of MACH_CORE_BACKEND env var for selecting linux backend --- src/core/Linux.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/Linux.zig b/src/core/Linux.zig index 25a0c3c697..e012628466 100644 --- a/src/core/Linux.zig +++ b/src/core/Linux.zig @@ -66,7 +66,7 @@ pub fn init( const desired_backend: BackendEnum = blk: { const backend = std.process.getEnvVarOwned( linux.allocator, - "MACH_CORE_BACKEND", + "MACH_BACKEND", ) catch |err| switch (err) { error.EnvironmentVariableNotFound => { break :blk .wayland; @@ -77,7 +77,7 @@ pub fn init( if (std.ascii.eqlIgnoreCase(backend, "x11")) break :blk .x11; if (std.ascii.eqlIgnoreCase(backend, "wayland")) break :blk .wayland; - std.debug.panic("mach: unknown MACH_CORE_BACKEND: {s}", .{backend}); + std.debug.panic("mach: unknown MACH_BACKEND: {s}", .{backend}); }; // Try to initialize the desired backend, falling back to the other if that one is not supported From 4ad20917788fb47f19de1b0ffe59113ecc495d5a Mon Sep 17 00:00:00 2001 From: Joshua Holmes Date: Fri, 11 Oct 2024 19:03:01 -0700 Subject: [PATCH 5/6] core: send info message about missing features in linux --- src/core/Linux.zig | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/core/Linux.zig b/src/core/Linux.zig index e012628466..ade7201716 100644 --- a/src/core/Linux.zig +++ b/src/core/Linux.zig @@ -46,6 +46,11 @@ surface_descriptor: gpu.Surface.Descriptor, gamemode: ?bool = null, 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/title/cursor" }; +const MISSING_FEATURES_WAYLAND = [_][]const u8{ "Resizing window", "Keyboard input", "Changing display mode", "VSync", "Setting window border/title/cursor" }; + pub fn init( linux: *Linux, core: *Core.Mod, @@ -117,6 +122,10 @@ pub fn init( }, } + // 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); + return; } @@ -195,3 +204,37 @@ pub fn deinitLinuxGamemode() void { mach.gamemode.stop(); gamemode_log.info("gamemode: deactivated", .{}); } + +/// Used to inform users that some features are not present. Remove when features are complete. +fn warnAboutIncompleteFeatures(backend: BackendEnum, missing_features_x11: []const []const u8, missing_features_wayland: []const []const u8, alloc: std.mem.Allocator) !void { + const features_incomplete_message = + \\WARNING: You are using the {s} backend, which is currently experimental as we continue to rewrite Mach in Zig instead of using C libraries like GLFW/etc. The following features are expected to not work: + \\ + \\{s} + \\ + \\Contributions welcome! + ; + const bullet_points = switch (backend) { + .x11 => try generateFeatureBulletPoints(missing_features_x11, alloc), + .wayland => try generateFeatureBulletPoints(missing_features_wayland, alloc), + }; + defer bullet_points.deinit(); + log.info(features_incomplete_message, .{ @tagName(backend), bullet_points.items }); +} + +/// Turn an array of strings into a single, bullet-pointed string, like this: +/// * Item one +/// * Item two +/// +/// Returned value will need to be deinitialized. +fn generateFeatureBulletPoints(features: []const []const u8, alloc: std.mem.Allocator) !std.ArrayList(u8) { + var message = std.ArrayList(u8).init(alloc); + for (features, 0..) |str, i| { + try message.appendSlice("* "); + try message.appendSlice(str); + if (i < features.len - 1) { + try message.appendSlice("\n"); + } + } + return message; +} From 6a5857d4ce321ae96ecc6c5578ce12e78065f895 Mon Sep 17 00:00:00 2001 From: Joshua Holmes Date: Fri, 18 Oct 2024 15:29:18 -0700 Subject: [PATCH 6/6] core: silently fail to connect to linux display and improve logging --- src/core/Linux.zig | 39 ++++++++++++++++++++------------------ src/core/linux/Wayland.zig | 2 +- src/core/linux/X11.zig | 3 +-- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/core/Linux.zig b/src/core/Linux.zig index ade7201716..60b56116ed 100644 --- a/src/core/Linux.zig +++ b/src/core/Linux.zig @@ -88,26 +88,28 @@ pub fn init( // Try to initialize the desired backend, falling back to the other if that one is not supported switch (desired_backend) { .x11 => blk: { - const x11 = X11.init(linux, core, options) catch |err| switch (err) { - error.LibraryNotFound => { - log.err("failed to initialize X11 backend, falling back to Wayland", .{}); - linux.backend = .{ .wayland = try Wayland.init(linux, core, options) }; - - break :blk; - }, - else => return err, + const x11 = X11.init(linux, core, options) catch |err| { + const err_msg = switch (err) { + error.LibraryNotFound => "Missing X11 library", + error.FailedToConnectToDisplay => "Failed to connect to display", + else => "An unknown error occured while trying to connect to X11", + }; + log.err("{s}\nFalling back to Wayland\n", .{err_msg}); + linux.backend = .{ .wayland = try Wayland.init(linux, core, options) }; + break :blk; }; linux.backend = .{ .x11 = x11 }; }, .wayland => blk: { - const wayland = Wayland.init(linux, core, options) catch |err| switch (err) { - error.LibraryNotFound => { - log.err("failed to initialize Wayland backend, falling back to X11", .{}); - linux.backend = .{ .x11 = try X11.init(linux, core, options) }; - - break :blk; - }, - else => return err, + const wayland = Wayland.init(linux, core, options) catch |err| { + const err_msg = switch (err) { + error.LibraryNotFound => "Missing Wayland library", + error.FailedToConnectToDisplay => "Failed to connect to display", + else => "An unknown error occured while trying to connect to Wayland", + }; + log.err("{s}\nFalling back to X11\n", .{err_msg}); + linux.backend = .{ .x11 = try X11.init(linux, core, options) }; + break :blk; }; linux.backend = .{ .wayland = wayland }; }, @@ -196,13 +198,13 @@ pub fn wantGamemode(allocator: std.mem.Allocator) error{ OutOfMemory, InvalidWtf pub fn initLinuxGamemode() bool { mach.gamemode.start(); if (!mach.gamemode.isActive()) return false; - gamemode_log.info("gamemode: activated", .{}); + gamemode_log.info("gamemode: activated\n", .{}); return true; } pub fn deinitLinuxGamemode() void { mach.gamemode.stop(); - gamemode_log.info("gamemode: deactivated", .{}); + gamemode_log.info("gamemode: deactivated\n", .{}); } /// Used to inform users that some features are not present. Remove when features are complete. @@ -213,6 +215,7 @@ fn warnAboutIncompleteFeatures(backend: BackendEnum, missing_features_x11: []con \\{s} \\ \\Contributions welcome! + \\ ; const bullet_points = switch (backend) { .x11 => try generateFeatureBulletPoints(missing_features_x11, alloc), diff --git a/src/core/linux/Wayland.zig b/src/core/linux/Wayland.zig index 23d70354a9..1c35d21d98 100644 --- a/src/core/linux/Wayland.zig +++ b/src/core/linux/Wayland.zig @@ -83,7 +83,7 @@ pub fn init( .libxkbcommon = try LibXkbCommon.load(), .libwaylandclient = libwaylandclient_global, .interfaces = Interfaces{}, - .display = libwaylandclient_global.wl_display_connect(null) orelse return error.FailedToConnectToWaylandDisplay, + .display = libwaylandclient_global.wl_display_connect(null) orelse return error.FailedToConnectToDisplay, .title = try options.allocator.dupeZ(u8, options.title), .size = &linux.size, .modifiers = .{ diff --git a/src/core/linux/X11.zig b/src/core/linux/X11.zig index bf84485afd..b649ef377a 100644 --- a/src/core/linux/X11.zig +++ b/src/core/linux/X11.zig @@ -99,8 +99,7 @@ pub fn init( else => return err, }; const display = libx11.XOpenDisplay(null) orelse { - std.log.err("X11: Cannot open display", .{}); - return error.CannotOpenDisplay; + return error.FailedToConnectToDisplay; }; const screen = c.DefaultScreen(display); const visual = c.DefaultVisual(display, screen);