197 lines
5.4 KiB
Zig
197 lines
5.4 KiB
Zig
const std = @import("std");
|
|
const mach = @import("../main.zig");
|
|
const Core = @import("../Core.zig");
|
|
const X11 = @import("linux/X11.zig");
|
|
const Wayland = @import("linux/Wayland.zig");
|
|
const gpu = mach.gpu;
|
|
const InitOptions = Core.InitOptions;
|
|
const Event = Core.Event;
|
|
const KeyEvent = Core.KeyEvent;
|
|
const MouseButtonEvent = Core.MouseButtonEvent;
|
|
const MouseButton = Core.MouseButton;
|
|
const Size = Core.Size;
|
|
const DisplayMode = Core.DisplayMode;
|
|
const CursorShape = Core.CursorShape;
|
|
const VSyncMode = Core.VSyncMode;
|
|
const CursorMode = Core.CursorMode;
|
|
const Position = Core.Position;
|
|
const Key = Core.Key;
|
|
const KeyMods = Core.KeyMods;
|
|
|
|
const log = std.log.scoped(.mach);
|
|
const gamemode_log = std.log.scoped(.gamemode);
|
|
|
|
const BackendEnum = enum {
|
|
x11,
|
|
wayland,
|
|
};
|
|
const Backend = union(BackendEnum) {
|
|
x11: X11,
|
|
wayland: Wayland,
|
|
};
|
|
|
|
pub const Linux = @This();
|
|
|
|
allocator: std.mem.Allocator,
|
|
|
|
display_mode: DisplayMode,
|
|
vsync_mode: VSyncMode,
|
|
cursor_mode: CursorMode,
|
|
cursor_shape: CursorShape,
|
|
border: bool,
|
|
headless: bool,
|
|
refresh_rate: u32,
|
|
size: Size,
|
|
surface_descriptor: gpu.Surface.Descriptor,
|
|
gamemode: ?bool = null,
|
|
backend: Backend,
|
|
|
|
pub fn init(
|
|
linux: *Linux,
|
|
core: *Core.Mod,
|
|
options: InitOptions,
|
|
) !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;
|
|
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(
|
|
linux.allocator,
|
|
"MACH_CORE_BACKEND",
|
|
) catch |err| switch (err) {
|
|
error.EnvironmentVariableNotFound => {
|
|
break :blk .wayland;
|
|
},
|
|
else => return err,
|
|
};
|
|
defer linux.allocator.free(backend);
|
|
|
|
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});
|
|
};
|
|
|
|
// 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,
|
|
};
|
|
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,
|
|
};
|
|
linux.backend = .{ .wayland = wayland };
|
|
},
|
|
}
|
|
|
|
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 } };
|
|
},
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
pub fn deinit(linux: *Linux) void {
|
|
if (linux.gamemode != null and linux.gamemode.?) deinitLinuxGamemode();
|
|
switch (linux.backend) {
|
|
.wayland => linux.backend.wayland.deinit(linux),
|
|
.x11 => linux.backend.x11.deinit(linux),
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
pub fn update(linux: *Linux) !void {
|
|
switch (linux.backend) {
|
|
.wayland => {},
|
|
.x11 => try linux.backend.x11.update(),
|
|
}
|
|
return;
|
|
}
|
|
|
|
pub fn setTitle(_: *Linux, _: [:0]const u8) void {
|
|
return;
|
|
}
|
|
|
|
pub fn setDisplayMode(_: *Linux, _: DisplayMode) void {
|
|
return;
|
|
}
|
|
|
|
pub fn setBorder(_: *Linux, _: bool) void {
|
|
return;
|
|
}
|
|
|
|
pub fn setHeadless(_: *Linux, _: bool) void {
|
|
return;
|
|
}
|
|
|
|
pub fn setVSync(_: *Linux, _: VSyncMode) void {
|
|
return;
|
|
}
|
|
|
|
pub fn setSize(_: *Linux, _: Size) void {
|
|
return;
|
|
}
|
|
|
|
pub fn setCursorMode(_: *Linux, _: CursorMode) void {
|
|
return;
|
|
}
|
|
|
|
pub fn setCursorShape(_: *Linux, _: CursorShape) void {
|
|
return;
|
|
}
|
|
|
|
/// Check if gamemode should be activated
|
|
pub fn wantGamemode(allocator: std.mem.Allocator) error{ OutOfMemory, InvalidWtf8 }!bool {
|
|
const use_gamemode = std.process.getEnvVarOwned(
|
|
allocator,
|
|
"MACH_USE_GAMEMODE",
|
|
) catch |err| switch (err) {
|
|
error.EnvironmentVariableNotFound => return true,
|
|
else => |e| return e,
|
|
};
|
|
defer allocator.free(use_gamemode);
|
|
|
|
return !(std.ascii.eqlIgnoreCase(use_gamemode, "off") or std.ascii.eqlIgnoreCase(use_gamemode, "false"));
|
|
}
|
|
|
|
pub fn initLinuxGamemode() bool {
|
|
mach.gamemode.start();
|
|
if (!mach.gamemode.isActive()) return false;
|
|
gamemode_log.info("gamemode: activated", .{});
|
|
return true;
|
|
}
|
|
|
|
pub fn deinitLinuxGamemode() void {
|
|
mach.gamemode.stop();
|
|
gamemode_log.info("gamemode: deactivated", .{});
|
|
}
|