gtk: build gtk4-layer-shell ourselves

As of now `gtk4-layer-shell` is unavailable on recent, stable releases
of many distros (Debian 12, Ubuntu 24.04, openSUSE Leap & Tumbleweed, etc.)
and outdated on many others (Nixpkgs 24.11/unstable, Fedora 41, etc.)
This is inconvenient for our users and severely limits where the quick
terminal can be used. As a result we then build gtk4-layer-shell ourselves
by default unless `--system` or `-fsys=gtk4-layer-shell` are specified.
This also allows me to add an idiomatic Zig API on top of the library
and avoiding adding even more raw C code in the GTK apprt.

Since we now build gtk4-layer-shell it should be theoretically available
on all Linux systems we target. As such, the `-Dgtk-layer-shell` build
option has been removed. This is somewhat of an experimental change as
I don't know if gtk4-layer-shell works perfectly across all distros, and
we can always add the option back if need be.
This commit is contained in:
Leah Amelia Chen
2025-03-07 17:03:23 +01:00
parent e07b6fdf6b
commit cd442eb9e2
15 changed files with 241 additions and 68 deletions

View File

@@ -781,10 +781,7 @@ fn toggleQuickTerminal(self: *App) !bool {
return true;
}
if (!self.winproto.supportsQuickTerminal()) {
log.err("quick terminal not supported on current platform", .{});
return false;
}
if (!self.winproto.supportsQuickTerminal()) return false;
const qt = Window.create(self.core_app.alloc, self) catch |err| {
log.err("failed to initialize quick terminal={}", .{err});

View File

@@ -15,7 +15,6 @@ pub const c = @cImport({
@cInclude("X11/XKBlib.h");
}
if (build_options.wayland) {
if (build_options.layer_shell) @cInclude("gtk4-layer-shell/gtk4-layer-shell.h");
@cInclude("gdk/wayland/gdkwayland.h");
}

View File

@@ -4,6 +4,8 @@ const Allocator = std.mem.Allocator;
const build_options = @import("build_options");
const wayland = @import("wayland");
const gtk = @import("gtk");
const gtk4_layer_shell = @import("gtk4-layer-shell");
const c = @import("../c.zig").c;
const Config = @import("../../../config.zig").Config;
@@ -90,17 +92,19 @@ pub const App = struct {
}
pub fn supportsQuickTerminal(_: App) bool {
if (comptime !build_options.layer_shell) return false;
return c.gtk_layer_is_supported() != 0;
if (!gtk4_layer_shell.isSupported()) {
log.warn("your compositor does not support the wlr-layer-shell protocol; disabling quick terminal", .{});
return false;
}
return true;
}
pub fn initQuickTerminal(_: *App, apprt_window: *ApprtWindow) !void {
if (comptime !build_options.layer_shell) unreachable;
const window: *gtk.Window = @ptrCast(apprt_window.window);
c.gtk_layer_init_for_window(apprt_window.window);
c.gtk_layer_set_layer(apprt_window.window, c.GTK_LAYER_SHELL_LAYER_TOP);
c.gtk_layer_set_keyboard_mode(apprt_window.window, c.GTK_LAYER_SHELL_KEYBOARD_MODE_ON_DEMAND);
gtk4_layer_shell.initForWindow(window);
gtk4_layer_shell.setLayer(window, .top);
gtk4_layer_shell.setKeyboardMode(window, .on_demand);
}
fn registryListener(
@@ -336,11 +340,10 @@ pub const Window = struct {
}
fn syncQuickTerminal(self: *Window) !void {
if (comptime !build_options.layer_shell) return;
const window: *gtk.Window = @ptrCast(self.apprt_window.window);
const position = self.apprt_window.config.quick_terminal_position;
const window = self.apprt_window.window;
const anchored_edge: ?LayerShellEdge = switch (self.apprt_window.config.quick_terminal_position) {
const anchored_edge: ?gtk4_layer_shell.ShellEdge = switch (position) {
.left => .left,
.right => .right,
.top => .top,
@@ -348,23 +351,23 @@ pub const Window = struct {
.center => null,
};
for (std.meta.tags(LayerShellEdge)) |edge| {
for (std.meta.tags(gtk4_layer_shell.ShellEdge)) |edge| {
if (anchored_edge) |anchored| {
if (edge == anchored) {
c.gtk_layer_set_margin(window, @intFromEnum(edge), 0);
c.gtk_layer_set_anchor(window, @intFromEnum(edge), @intFromBool(true));
gtk4_layer_shell.setMargin(window, edge, 0);
gtk4_layer_shell.setAnchor(window, edge, true);
continue;
}
}
// Arbitrary margin - could be made customizable?
c.gtk_layer_set_margin(window, @intFromEnum(edge), 20);
c.gtk_layer_set_anchor(window, @intFromEnum(edge), @intFromBool(false));
gtk4_layer_shell.setMargin(window, edge, 20);
gtk4_layer_shell.setAnchor(window, edge, false);
}
switch (self.apprt_window.config.quick_terminal_position) {
.top, .bottom, .center => c.gtk_window_set_default_size(window, 800, 400),
.left, .right => c.gtk_window_set_default_size(window, 400, 800),
switch (position) {
.top, .bottom, .center => window.setDefaultSize(800, 400),
.left, .right => window.setDefaultSize(400, 800),
}
if (self.apprt_window.isQuickTerminal()) {
@@ -377,26 +380,18 @@ pub const Window = struct {
log.warn("could not create slide object={}", .{err});
break :slide null;
};
slide.setLocation(@intCast(@intFromEnum(anchored.toKdeSlideLocation())));
const slide_location: org.KdeKwinSlide.Location = switch (anchored) {
.top => .top,
.bottom => .bottom,
.left => .left,
.right => .right,
};
slide.setLocation(@intCast(@intFromEnum(slide_location)));
slide.commit();
break :slide slide;
} else null;
}
}
};
const LayerShellEdge = enum(c_uint) {
left = c.GTK_LAYER_SHELL_EDGE_LEFT,
right = c.GTK_LAYER_SHELL_EDGE_RIGHT,
top = c.GTK_LAYER_SHELL_EDGE_TOP,
bottom = c.GTK_LAYER_SHELL_EDGE_BOTTOM,
fn toKdeSlideLocation(self: LayerShellEdge) org.KdeKwinSlide.Location {
return switch (self) {
.left => .left,
.top => .top,
.right => .right,
.bottom => .bottom,
};
}
};

View File

@@ -150,6 +150,7 @@ pub const App = struct {
}
pub fn supportsQuickTerminal(_: App) bool {
log.warn("quick terminal is not yet supported on X11", .{});
return false;
}