mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-09-05 19:08:17 +00:00
gtk(wayland): customize keyboard interactivity for quick terminal (#7477)
Fixes #7476
This commit is contained in:
@@ -27,6 +27,10 @@ pub fn isSupported() bool {
|
||||
return c.gtk_layer_is_supported() != 0;
|
||||
}
|
||||
|
||||
pub fn getProtocolVersion() c_uint {
|
||||
return c.gtk_layer_get_protocol_version();
|
||||
}
|
||||
|
||||
pub fn initForWindow(window: *gtk.Window) void {
|
||||
c.gtk_layer_init_for_window(@ptrCast(window));
|
||||
}
|
||||
@@ -46,3 +50,7 @@ pub fn setMargin(window: *gtk.Window, edge: ShellEdge, margin_size: c_int) void
|
||||
pub fn setKeyboardMode(window: *gtk.Window, mode: KeyboardMode) void {
|
||||
c.gtk_layer_set_keyboard_mode(@ptrCast(window), @intFromEnum(mode));
|
||||
}
|
||||
|
||||
pub fn setNamespace(window: *gtk.Window, name: [:0]const u8) void {
|
||||
c.gtk_layer_set_namespace(@ptrCast(window), name.ptr);
|
||||
}
|
||||
|
@@ -90,6 +90,7 @@ pub const DerivedConfig = struct {
|
||||
quick_terminal_position: configpkg.Config.QuickTerminalPosition,
|
||||
quick_terminal_size: configpkg.Config.QuickTerminalSize,
|
||||
quick_terminal_autohide: bool,
|
||||
quick_terminal_keyboard_interactivity: configpkg.Config.QuickTerminalKeyboardInteractivity,
|
||||
|
||||
maximize: bool,
|
||||
fullscreen: bool,
|
||||
@@ -109,6 +110,7 @@ pub const DerivedConfig = struct {
|
||||
.quick_terminal_position = config.@"quick-terminal-position",
|
||||
.quick_terminal_size = config.@"quick-terminal-size",
|
||||
.quick_terminal_autohide = config.@"quick-terminal-autohide",
|
||||
.quick_terminal_keyboard_interactivity = config.@"quick-terminal-keyboard-interactivity",
|
||||
|
||||
.maximize = config.maximize,
|
||||
.fullscreen = config.fullscreen,
|
||||
|
@@ -6,8 +6,8 @@ const build_options = @import("build_options");
|
||||
const gdk = @import("gdk");
|
||||
const gdk_wayland = @import("gdk_wayland");
|
||||
const gobject = @import("gobject");
|
||||
const gtk4_layer_shell = @import("gtk4-layer-shell");
|
||||
const gtk = @import("gtk");
|
||||
const layer_shell = @import("gtk4-layer-shell");
|
||||
const wayland = @import("wayland");
|
||||
|
||||
const Config = @import("../../../config.zig").Config;
|
||||
@@ -98,7 +98,7 @@ pub const App = struct {
|
||||
}
|
||||
|
||||
pub fn supportsQuickTerminal(_: App) bool {
|
||||
if (!gtk4_layer_shell.isSupported()) {
|
||||
if (!layer_shell.isSupported()) {
|
||||
log.warn("your compositor does not support the wlr-layer-shell protocol; disabling quick terminal", .{});
|
||||
return false;
|
||||
}
|
||||
@@ -108,9 +108,9 @@ pub const App = struct {
|
||||
pub fn initQuickTerminal(_: *App, apprt_window: *ApprtWindow) !void {
|
||||
const window = apprt_window.window.as(gtk.Window);
|
||||
|
||||
gtk4_layer_shell.initForWindow(window);
|
||||
gtk4_layer_shell.setLayer(window, .top);
|
||||
gtk4_layer_shell.setKeyboardMode(window, .on_demand);
|
||||
layer_shell.initForWindow(window);
|
||||
layer_shell.setLayer(window, .top);
|
||||
layer_shell.setNamespace(window, "ghostty-quick-terminal");
|
||||
}
|
||||
|
||||
fn registryListener(
|
||||
@@ -356,9 +356,24 @@ pub const Window = struct {
|
||||
|
||||
fn syncQuickTerminal(self: *Window) !void {
|
||||
const window = self.apprt_window.window.as(gtk.Window);
|
||||
const position = self.apprt_window.config.quick_terminal_position;
|
||||
const config = &self.apprt_window.config;
|
||||
|
||||
const anchored_edge: ?gtk4_layer_shell.ShellEdge = switch (position) {
|
||||
layer_shell.setKeyboardMode(
|
||||
window,
|
||||
switch (config.quick_terminal_keyboard_interactivity) {
|
||||
.none => .none,
|
||||
.@"on-demand" => on_demand: {
|
||||
if (layer_shell.getProtocolVersion() < 4) {
|
||||
log.warn("your compositor does not support on-demand keyboard access; falling back to exclusive access", .{});
|
||||
break :on_demand .exclusive;
|
||||
}
|
||||
break :on_demand .on_demand;
|
||||
},
|
||||
.exclusive => .exclusive,
|
||||
},
|
||||
);
|
||||
|
||||
const anchored_edge: ?layer_shell.ShellEdge = switch (config.quick_terminal_position) {
|
||||
.left => .left,
|
||||
.right => .right,
|
||||
.top => .top,
|
||||
@@ -366,43 +381,41 @@ pub const Window = struct {
|
||||
.center => null,
|
||||
};
|
||||
|
||||
for (std.meta.tags(gtk4_layer_shell.ShellEdge)) |edge| {
|
||||
for (std.meta.tags(layer_shell.ShellEdge)) |edge| {
|
||||
if (anchored_edge) |anchored| {
|
||||
if (edge == anchored) {
|
||||
gtk4_layer_shell.setMargin(window, edge, 0);
|
||||
gtk4_layer_shell.setAnchor(window, edge, true);
|
||||
layer_shell.setMargin(window, edge, 0);
|
||||
layer_shell.setAnchor(window, edge, true);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Arbitrary margin - could be made customizable?
|
||||
gtk4_layer_shell.setMargin(window, edge, 20);
|
||||
gtk4_layer_shell.setAnchor(window, edge, false);
|
||||
layer_shell.setMargin(window, edge, 20);
|
||||
layer_shell.setAnchor(window, edge, false);
|
||||
}
|
||||
|
||||
if (self.apprt_window.isQuickTerminal()) {
|
||||
if (self.slide) |slide| slide.release();
|
||||
if (self.slide) |slide| slide.release();
|
||||
|
||||
self.slide = if (anchored_edge) |anchored| slide: {
|
||||
const mgr = self.app_context.kde_slide_manager orelse break :slide null;
|
||||
self.slide = if (anchored_edge) |anchored| slide: {
|
||||
const mgr = self.app_context.kde_slide_manager orelse break :slide null;
|
||||
|
||||
const slide = mgr.create(self.surface) catch |err| {
|
||||
log.warn("could not create slide object={}", .{err});
|
||||
break :slide null;
|
||||
};
|
||||
const slide = mgr.create(self.surface) catch |err| {
|
||||
log.warn("could not create slide object={}", .{err});
|
||||
break :slide null;
|
||||
};
|
||||
|
||||
const slide_location: org.KdeKwinSlide.Location = switch (anchored) {
|
||||
.top => .top,
|
||||
.bottom => .bottom,
|
||||
.left => .left,
|
||||
.right => .right,
|
||||
};
|
||||
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;
|
||||
}
|
||||
slide.setLocation(@intCast(@intFromEnum(slide_location)));
|
||||
slide.commit();
|
||||
break :slide slide;
|
||||
} else null;
|
||||
}
|
||||
|
||||
/// Update the size of the quick terminal based on monitor dimensions.
|
||||
@@ -412,16 +425,18 @@ pub const Window = struct {
|
||||
apprt_window: *ApprtWindow,
|
||||
) callconv(.c) void {
|
||||
const window = apprt_window.window.as(gtk.Window);
|
||||
const size = apprt_window.config.quick_terminal_size;
|
||||
const position = apprt_window.config.quick_terminal_position;
|
||||
const config = &apprt_window.config;
|
||||
|
||||
var monitor_size: gdk.Rectangle = undefined;
|
||||
monitor.getGeometry(&monitor_size);
|
||||
|
||||
const dims = size.calculate(position, .{
|
||||
.width = @intCast(monitor_size.f_width),
|
||||
.height = @intCast(monitor_size.f_height),
|
||||
});
|
||||
const dims = config.quick_terminal_size.calculate(
|
||||
config.quick_terminal_position,
|
||||
.{
|
||||
.width = @intCast(monitor_size.f_width),
|
||||
.height = @intCast(monitor_size.f_height),
|
||||
},
|
||||
);
|
||||
|
||||
window.setDefaultSize(@intCast(dims.width), @intCast(dims.height));
|
||||
}
|
||||
|
@@ -1808,6 +1808,34 @@ keybind: Keybinds = .{},
|
||||
/// On Linux the behavior is always equivalent to `move`.
|
||||
@"quick-terminal-space-behavior": QuickTerminalSpaceBehavior = .move,
|
||||
|
||||
/// Determines under which circumstances that the quick terminal should receive
|
||||
/// keyboard input. See the corresponding [Wayland documentation](https://wayland.app/protocols/wlr-layer-shell-unstable-v1#zwlr_layer_surface_v1:enum:keyboard_interactivity)
|
||||
/// for a more detailed explanation of the behavior of each option.
|
||||
///
|
||||
/// > [!NOTE]
|
||||
/// > The exact behavior of each option may differ significantly across
|
||||
/// > compositors -- experiment with them on your system to find one that
|
||||
/// > suits your liking!
|
||||
///
|
||||
/// Valid values are:
|
||||
///
|
||||
/// * `none`
|
||||
///
|
||||
/// The quick terminal will not receive any keyboard input.
|
||||
///
|
||||
/// * `on-demand` (default)
|
||||
///
|
||||
/// The quick terminal would only receive keyboard input when it is focused.
|
||||
///
|
||||
/// * `exclusive`
|
||||
///
|
||||
/// The quick terminal will always receive keyboard input, even when another
|
||||
/// window is currently focused.
|
||||
///
|
||||
/// Only has an effect on Linux Wayland.
|
||||
/// On macOS the behavior is always equivalent to `on-demand`.
|
||||
@"quick-terminal-keyboard-interactivity": QuickTerminalKeyboardInteractivity = .@"on-demand",
|
||||
|
||||
/// Whether to enable shell integration auto-injection or not. Shell integration
|
||||
/// greatly enhances the terminal experience by enabling a number of features:
|
||||
///
|
||||
@@ -6138,6 +6166,13 @@ pub const QuickTerminalSpaceBehavior = enum {
|
||||
move,
|
||||
};
|
||||
|
||||
/// See quick-terminal-keyboard-interactivity
|
||||
pub const QuickTerminalKeyboardInteractivity = enum {
|
||||
none,
|
||||
@"on-demand",
|
||||
exclusive,
|
||||
};
|
||||
|
||||
/// See grapheme-width-method
|
||||
pub const GraphemeWidthMethod = enum {
|
||||
legacy,
|
||||
|
Reference in New Issue
Block a user