mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
gtk: implement quick terminal (#6027)
This commit is contained in:
@ -31,6 +31,7 @@
|
|||||||
glib,
|
glib,
|
||||||
glslang,
|
glslang,
|
||||||
gtk4,
|
gtk4,
|
||||||
|
gtk4-layer-shell,
|
||||||
gobject-introspection,
|
gobject-introspection,
|
||||||
libadwaita,
|
libadwaita,
|
||||||
blueprint-compiler,
|
blueprint-compiler,
|
||||||
@ -88,6 +89,7 @@
|
|||||||
|
|
||||||
libadwaita
|
libadwaita
|
||||||
gtk4
|
gtk4
|
||||||
|
gtk4-layer-shell
|
||||||
glib
|
glib
|
||||||
gobject-introspection
|
gobject-introspection
|
||||||
wayland
|
wayland
|
||||||
@ -167,6 +169,7 @@ in
|
|||||||
blueprint-compiler
|
blueprint-compiler
|
||||||
libadwaita
|
libadwaita
|
||||||
gtk4
|
gtk4
|
||||||
|
gtk4-layer-shell
|
||||||
glib
|
glib
|
||||||
gobject-introspection
|
gobject-introspection
|
||||||
wayland
|
wayland
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
libGL,
|
libGL,
|
||||||
glib,
|
glib,
|
||||||
gtk4,
|
gtk4,
|
||||||
|
gtk4-layer-shell,
|
||||||
gobject-introspection,
|
gobject-introspection,
|
||||||
libadwaita,
|
libadwaita,
|
||||||
blueprint-compiler,
|
blueprint-compiler,
|
||||||
@ -118,6 +119,7 @@ in
|
|||||||
libXrandr
|
libXrandr
|
||||||
]
|
]
|
||||||
++ lib.optionals enableWayland [
|
++ lib.optionals enableWayland [
|
||||||
|
gtk4-layer-shell
|
||||||
wayland
|
wayland
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -73,6 +73,8 @@ parts:
|
|||||||
- blueprint-compiler
|
- blueprint-compiler
|
||||||
- libgtk-4-dev
|
- libgtk-4-dev
|
||||||
- libadwaita-1-dev
|
- libadwaita-1-dev
|
||||||
|
# TODO: Add when the Snap is updated to Ubuntu 24.10+
|
||||||
|
# - gtk4-layer-shell
|
||||||
- libxml2-utils
|
- libxml2-utils
|
||||||
- git
|
- git
|
||||||
- patchelf
|
- patchelf
|
||||||
|
@ -70,6 +70,10 @@ config_errors_window: ?*ConfigErrorsWindow = null,
|
|||||||
/// The clipboard confirmation window, if it is currently open.
|
/// The clipboard confirmation window, if it is currently open.
|
||||||
clipboard_confirmation_window: ?*ClipboardConfirmationWindow = null,
|
clipboard_confirmation_window: ?*ClipboardConfirmationWindow = null,
|
||||||
|
|
||||||
|
/// The window containing the quick terminal.
|
||||||
|
/// Null when never initialized.
|
||||||
|
quick_terminal: ?*Window = null,
|
||||||
|
|
||||||
/// This is set to false when the main loop should exit.
|
/// This is set to false when the main loop should exit.
|
||||||
running: bool = true,
|
running: bool = true,
|
||||||
|
|
||||||
@ -497,10 +501,10 @@ pub fn performAction(
|
|||||||
.toggle_window_decorations => self.toggleWindowDecorations(target),
|
.toggle_window_decorations => self.toggleWindowDecorations(target),
|
||||||
.quit_timer => self.quitTimer(value),
|
.quit_timer => self.quitTimer(value),
|
||||||
.prompt_title => try self.promptTitle(target),
|
.prompt_title => try self.promptTitle(target),
|
||||||
|
.toggle_quick_terminal => return try self.toggleQuickTerminal(),
|
||||||
|
|
||||||
// Unimplemented
|
// Unimplemented
|
||||||
.close_all_windows,
|
.close_all_windows,
|
||||||
.toggle_quick_terminal,
|
|
||||||
.toggle_visibility,
|
.toggle_visibility,
|
||||||
.cell_size,
|
.cell_size,
|
||||||
.secure_input,
|
.secure_input,
|
||||||
@ -764,6 +768,33 @@ fn toggleWindowDecorations(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn toggleQuickTerminal(self: *App) !bool {
|
||||||
|
if (self.quick_terminal) |qt| {
|
||||||
|
qt.toggleVisibility();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!self.winproto.supportsQuickTerminal()) {
|
||||||
|
log.err("quick terminal not supported on current platform", .{});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const qt = Window.create(self.core_app.alloc, self) catch |err| {
|
||||||
|
log.err("failed to initialize quick terminal={}", .{err});
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
self.quick_terminal = qt;
|
||||||
|
|
||||||
|
// The setup has to happen *before* the window-specific winproto is
|
||||||
|
// initialized, so we need to initialize it through the app winproto
|
||||||
|
try self.winproto.initQuickTerminal(qt);
|
||||||
|
|
||||||
|
// Finalize creating the quick terminal
|
||||||
|
try qt.newTab(null);
|
||||||
|
qt.present();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
fn quitTimer(self: *App, mode: apprt.action.QuitTimer) void {
|
fn quitTimer(self: *App, mode: apprt.action.QuitTimer) void {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
.start => self.startQuitTimer(),
|
.start => self.startQuitTimer(),
|
||||||
@ -1372,6 +1403,9 @@ fn newWindow(self: *App, parent_: ?*CoreSurface) !void {
|
|||||||
|
|
||||||
// Add our initial tab
|
// Add our initial tab
|
||||||
try window.newTab(parent_);
|
try window.newTab(parent_);
|
||||||
|
|
||||||
|
// Show the new window
|
||||||
|
window.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn quit(self: *App) void {
|
fn quit(self: *App) void {
|
||||||
|
@ -193,10 +193,6 @@ pub fn addTab(self: *TabView, tab: *Tab, title: [:0]const u8) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn closeTab(self: *TabView, tab: *Tab) void {
|
pub fn closeTab(self: *TabView, tab: *Tab) void {
|
||||||
// Save a pointer to the GTK window in case we need it later. It may be
|
|
||||||
// impossible to access later due to how resources are cleaned up.
|
|
||||||
const window: *gtk.Window = @ptrCast(@alignCast(self.window.window));
|
|
||||||
|
|
||||||
// closeTab always expects to close unconditionally so we mark this
|
// closeTab always expects to close unconditionally so we mark this
|
||||||
// as true so that the close_page call below doesn't request
|
// as true so that the close_page call below doesn't request
|
||||||
// confirmation.
|
// confirmation.
|
||||||
@ -225,7 +221,7 @@ pub fn closeTab(self: *TabView, tab: *Tab) void {
|
|||||||
box.as(gobject.Object).unref();
|
box.as(gobject.Object).unref();
|
||||||
}
|
}
|
||||||
|
|
||||||
window.destroy();
|
self.window.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,7 +230,9 @@ pub fn createWindow(currentWindow: *Window) !*Window {
|
|||||||
const app = currentWindow.app;
|
const app = currentWindow.app;
|
||||||
|
|
||||||
// Create a new window
|
// Create a new window
|
||||||
return Window.create(alloc, app);
|
const window = try Window.create(alloc, app);
|
||||||
|
window.present();
|
||||||
|
return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn adwPageAttached(_: *adw.TabView, page: *adw.TabPage, _: c_int, self: *TabView) callconv(.C) void {
|
fn adwPageAttached(_: *adw.TabView, page: *adw.TabPage, _: c_int, self: *TabView) callconv(.C) void {
|
||||||
|
@ -79,6 +79,8 @@ pub const DerivedConfig = struct {
|
|||||||
gtk_wide_tabs: bool,
|
gtk_wide_tabs: bool,
|
||||||
gtk_toolbar_style: configpkg.Config.GtkToolbarStyle,
|
gtk_toolbar_style: configpkg.Config.GtkToolbarStyle,
|
||||||
|
|
||||||
|
quick_terminal_position: configpkg.Config.QuickTerminalPosition,
|
||||||
|
|
||||||
maximize: bool,
|
maximize: bool,
|
||||||
fullscreen: bool,
|
fullscreen: bool,
|
||||||
window_decoration: configpkg.Config.WindowDecoration,
|
window_decoration: configpkg.Config.WindowDecoration,
|
||||||
@ -94,6 +96,8 @@ pub const DerivedConfig = struct {
|
|||||||
.gtk_wide_tabs = config.@"gtk-wide-tabs",
|
.gtk_wide_tabs = config.@"gtk-wide-tabs",
|
||||||
.gtk_toolbar_style = config.@"gtk-toolbar-style",
|
.gtk_toolbar_style = config.@"gtk-toolbar-style",
|
||||||
|
|
||||||
|
.quick_terminal_position = config.@"quick-terminal-position",
|
||||||
|
|
||||||
.maximize = config.maximize,
|
.maximize = config.maximize,
|
||||||
.fullscreen = config.fullscreen,
|
.fullscreen = config.fullscreen,
|
||||||
.window_decoration = config.@"window-decoration",
|
.window_decoration = config.@"window-decoration",
|
||||||
@ -364,9 +368,16 @@ pub fn init(self: *Window, app: *App) !void {
|
|||||||
|
|
||||||
// If we are in fullscreen mode, new windows start fullscreen.
|
// If we are in fullscreen mode, new windows start fullscreen.
|
||||||
if (self.config.fullscreen) c.gtk_window_fullscreen(self.window);
|
if (self.config.fullscreen) c.gtk_window_fullscreen(self.window);
|
||||||
|
}
|
||||||
|
|
||||||
// Show the window
|
pub fn present(self: *Window) void {
|
||||||
c.gtk_widget_show(gtk_widget);
|
const window: *gtk.Window = @ptrCast(self.window);
|
||||||
|
window.present();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggleVisibility(self: *Window) void {
|
||||||
|
const window: *gtk.Widget = @ptrCast(self.window);
|
||||||
|
window.setVisible(@intFromBool(window.isVisible() == 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateConfig(
|
pub fn updateConfig(
|
||||||
@ -408,6 +419,9 @@ pub fn syncAppearance(self: *Window) !void {
|
|||||||
// Never display the header bar when CSDs are disabled.
|
// Never display the header bar when CSDs are disabled.
|
||||||
if (!csd_enabled) break :visible false;
|
if (!csd_enabled) break :visible false;
|
||||||
|
|
||||||
|
// Never display the header bar as a quick terminal.
|
||||||
|
if (self.app.quick_terminal == self) break :visible false;
|
||||||
|
|
||||||
// Unconditionally disable the header bar when fullscreened.
|
// Unconditionally disable the header bar when fullscreened.
|
||||||
if (self.config.fullscreen) break :visible false;
|
if (self.config.fullscreen) break :visible false;
|
||||||
|
|
||||||
@ -458,11 +472,11 @@ pub fn syncAppearance(self: *Window) !void {
|
|||||||
log.warn("failed to sync winproto appearance error={}", .{err});
|
log.warn("failed to sync winproto appearance error={}", .{err});
|
||||||
};
|
};
|
||||||
|
|
||||||
toggleCssClass(
|
if (self.app.quick_terminal == self) {
|
||||||
@ptrCast(self.window),
|
self.winproto.syncQuickTerminal() catch |err| {
|
||||||
"background",
|
log.warn("failed to sync quick terminal appearance error={}", .{err});
|
||||||
self.config.background_opacity >= 1,
|
};
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toggleCssClass(
|
fn toggleCssClass(
|
||||||
@ -780,11 +794,23 @@ fn adwTabOverviewFocusTimer(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn close(self: *Window) void {
|
||||||
|
const window: *gtk.Window = @ptrCast(self.window);
|
||||||
|
|
||||||
|
// Unset the quick terminal on the app level
|
||||||
|
if (self.app.quick_terminal == self) self.app.quick_terminal = null;
|
||||||
|
|
||||||
|
window.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
fn gtkCloseRequest(v: *c.GtkWindow, ud: ?*anyopaque) callconv(.C) bool {
|
fn gtkCloseRequest(v: *c.GtkWindow, ud: ?*anyopaque) callconv(.C) bool {
|
||||||
_ = v;
|
_ = v;
|
||||||
log.debug("window close request", .{});
|
log.debug("window close request", .{});
|
||||||
const self = userdataSelf(ud.?);
|
const self = userdataSelf(ud.?);
|
||||||
|
|
||||||
|
// This path should never occur, but this is here as a safety measure.
|
||||||
|
if (self.app.quick_terminal == self) return true;
|
||||||
|
|
||||||
// If none of our surfaces need confirmation, we can just exit.
|
// If none of our surfaces need confirmation, we can just exit.
|
||||||
for (self.app.core_app.surfaces.items) |surface| {
|
for (self.app.core_app.surfaces.items) |surface| {
|
||||||
if (surface.container.window()) |window| {
|
if (surface.container.window()) |window| {
|
||||||
@ -792,7 +818,7 @@ fn gtkCloseRequest(v: *c.GtkWindow, ud: ?*anyopaque) callconv(.C) bool {
|
|||||||
surface.core_surface.needsConfirmQuit()) break;
|
surface.core_surface.needsConfirmQuit()) break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.gtk_window_destroy(self.window);
|
self.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -836,7 +862,7 @@ fn gtkCloseConfirmation(
|
|||||||
c.gtk_window_destroy(@ptrCast(alert));
|
c.gtk_window_destroy(@ptrCast(alert));
|
||||||
if (response == c.GTK_RESPONSE_YES) {
|
if (response == c.GTK_RESPONSE_YES) {
|
||||||
const self = userdataSelf(ud.?);
|
const self = userdataSelf(ud.?);
|
||||||
c.gtk_window_destroy(self.window);
|
self.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -934,7 +960,7 @@ fn gtkActionClose(
|
|||||||
_: ?*glib.Variant,
|
_: ?*glib.Variant,
|
||||||
self: *Window,
|
self: *Window,
|
||||||
) callconv(.C) void {
|
) callconv(.C) void {
|
||||||
c.gtk_window_destroy(self.window);
|
self.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gtkActionNewWindow(
|
fn gtkActionNewWindow(
|
||||||
|
@ -15,6 +15,7 @@ pub const c = @cImport({
|
|||||||
@cInclude("X11/XKBlib.h");
|
@cInclude("X11/XKBlib.h");
|
||||||
}
|
}
|
||||||
if (build_options.wayland) {
|
if (build_options.wayland) {
|
||||||
|
if (build_options.layer_shell) @cInclude("gtk4-layer-shell/gtk4-layer-shell.h");
|
||||||
@cInclude("gdk/wayland/gdkwayland.h");
|
@cInclude("gdk/wayland/gdkwayland.h");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +59,23 @@ pub const App = union(Protocol) {
|
|||||||
inline else => |*v| v.eventMods(device, gtk_mods),
|
inline else => |*v| v.eventMods(device, gtk_mods),
|
||||||
} orelse key.translateMods(gtk_mods);
|
} orelse key.translateMods(gtk_mods);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn supportsQuickTerminal(self: App) bool {
|
||||||
|
return switch (self) {
|
||||||
|
inline else => |v| v.supportsQuickTerminal(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set up necessary support for the quick terminal that must occur
|
||||||
|
/// *before* the window-level winproto object is created.
|
||||||
|
///
|
||||||
|
/// Only has an effect on the Wayland backend, where the gtk4-layer-shell
|
||||||
|
/// library is initialized.
|
||||||
|
pub fn initQuickTerminal(self: *App, apprt_window: *ApprtWindow) !void {
|
||||||
|
switch (self.*) {
|
||||||
|
inline else => |*v| try v.initQuickTerminal(apprt_window),
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Per-Window state for the underlying windowing protocol.
|
/// Per-Window state for the underlying windowing protocol.
|
||||||
@ -116,6 +133,12 @@ pub const Window = union(Protocol) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn syncQuickTerminal(self: *Window) !void {
|
||||||
|
switch (self.*) {
|
||||||
|
inline else => |*v| try v.syncQuickTerminal(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn clientSideDecorationEnabled(self: Window) bool {
|
pub fn clientSideDecorationEnabled(self: Window) bool {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
inline else => |v| v.clientSideDecorationEnabled(),
|
inline else => |v| v.clientSideDecorationEnabled(),
|
||||||
|
@ -29,6 +29,11 @@ pub const App = struct {
|
|||||||
) ?input.Mods {
|
) ?input.Mods {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn supportsQuickTerminal(_: App) bool {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pub fn initQuickTerminal(_: *App, _: *ApprtWindow) !void {}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Window = struct {
|
pub const Window = struct {
|
||||||
@ -54,6 +59,8 @@ pub const Window = struct {
|
|||||||
|
|
||||||
pub fn syncAppearance(_: *Window) !void {}
|
pub fn syncAppearance(_: *Window) !void {}
|
||||||
|
|
||||||
|
pub fn syncQuickTerminal(_: *Window) !void {}
|
||||||
|
|
||||||
/// This returns true if CSD is enabled for this window. This
|
/// This returns true if CSD is enabled for this window. This
|
||||||
/// should be the actual present state of the window, not the
|
/// should be the actual present state of the window, not the
|
||||||
/// desired state.
|
/// desired state.
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
//! Wayland protocol implementation for the Ghostty GTK apprt.
|
//! Wayland protocol implementation for the Ghostty GTK apprt.
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const wayland = @import("wayland");
|
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
const build_options = @import("build_options");
|
||||||
|
const wayland = @import("wayland");
|
||||||
|
|
||||||
const c = @import("../c.zig").c;
|
const c = @import("../c.zig").c;
|
||||||
const Config = @import("../../../config.zig").Config;
|
const Config = @import("../../../config.zig").Config;
|
||||||
const input = @import("../../../input.zig");
|
const input = @import("../../../input.zig");
|
||||||
@ -84,6 +87,20 @@ pub const App = struct {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn supportsQuickTerminal(_: App) bool {
|
||||||
|
if (comptime !build_options.layer_shell) return false;
|
||||||
|
|
||||||
|
return c.gtk_layer_is_supported() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initQuickTerminal(_: *App, apprt_window: *ApprtWindow) !void {
|
||||||
|
if (comptime !build_options.layer_shell) unreachable;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
fn registryListener(
|
fn registryListener(
|
||||||
registry: *wl.Registry,
|
registry: *wl.Registry,
|
||||||
event: wl.Registry.Event,
|
event: wl.Registry.Event,
|
||||||
@ -156,7 +173,7 @@ pub const App = struct {
|
|||||||
|
|
||||||
/// Per-window (wl_surface) state for the Wayland protocol.
|
/// Per-window (wl_surface) state for the Wayland protocol.
|
||||||
pub const Window = struct {
|
pub const Window = struct {
|
||||||
config: *const ApprtWindow.DerivedConfig,
|
apprt_window: *ApprtWindow,
|
||||||
|
|
||||||
/// The Wayland surface for this window.
|
/// The Wayland surface for this window.
|
||||||
surface: *wl.Surface,
|
surface: *wl.Surface,
|
||||||
@ -210,7 +227,7 @@ pub const Window = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.config = &apprt_window.config,
|
.apprt_window = apprt_window,
|
||||||
.surface = wl_surface,
|
.surface = wl_surface,
|
||||||
.app_context = app.context,
|
.app_context = app.context,
|
||||||
.blur_token = null,
|
.blur_token = null,
|
||||||
@ -255,7 +272,7 @@ pub const Window = struct {
|
|||||||
/// Update the blur state of the window.
|
/// Update the blur state of the window.
|
||||||
fn syncBlur(self: *Window) !void {
|
fn syncBlur(self: *Window) !void {
|
||||||
const manager = self.app_context.kde_blur_manager orelse return;
|
const manager = self.app_context.kde_blur_manager orelse return;
|
||||||
const blur = self.config.background_blur;
|
const blur = self.apprt_window.config.background_blur;
|
||||||
|
|
||||||
if (self.blur_token) |tok| {
|
if (self.blur_token) |tok| {
|
||||||
// Only release token when transitioning from blurred -> not blurred
|
// Only release token when transitioning from blurred -> not blurred
|
||||||
@ -283,11 +300,51 @@ pub const Window = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn getDecorationMode(self: Window) org.KdeKwinServerDecorationManager.Mode {
|
fn getDecorationMode(self: Window) org.KdeKwinServerDecorationManager.Mode {
|
||||||
return switch (self.config.window_decoration) {
|
return switch (self.apprt_window.config.window_decoration) {
|
||||||
.auto => self.app_context.default_deco_mode orelse .Client,
|
.auto => self.app_context.default_deco_mode orelse .Client,
|
||||||
.client => .Client,
|
.client => .Client,
|
||||||
.server => .Server,
|
.server => .Server,
|
||||||
.none => .None,
|
.none => .None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn syncQuickTerminal(self: *Window) !void {
|
||||||
|
if (comptime !build_options.layer_shell) return;
|
||||||
|
|
||||||
|
const window = self.apprt_window.window;
|
||||||
|
|
||||||
|
const anchored_edge: ?LayerShellEdge = switch (self.apprt_window.config.quick_terminal_position) {
|
||||||
|
.left => .left,
|
||||||
|
.right => .right,
|
||||||
|
.top => .top,
|
||||||
|
.bottom => .bottom,
|
||||||
|
.center => null,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (std.meta.tags(LayerShellEdge)) |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));
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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,
|
||||||
};
|
};
|
||||||
|
@ -148,6 +148,12 @@ pub const App = struct {
|
|||||||
|
|
||||||
return mods;
|
return mods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn supportsQuickTerminal(_: App) bool {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initQuickTerminal(_: *App, _: *ApprtWindow) !void {}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Window = struct {
|
pub const Window = struct {
|
||||||
@ -222,6 +228,8 @@ pub const Window = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn syncQuickTerminal(_: *Window) !void {}
|
||||||
|
|
||||||
pub fn clientSideDecorationEnabled(self: Window) bool {
|
pub fn clientSideDecorationEnabled(self: Window) bool {
|
||||||
return switch (self.config.window_decoration) {
|
return switch (self.config.window_decoration) {
|
||||||
.auto, .client => true,
|
.auto, .client => true,
|
||||||
|
@ -34,6 +34,7 @@ font_backend: font.Backend = .freetype,
|
|||||||
/// Feature flags
|
/// Feature flags
|
||||||
x11: bool = false,
|
x11: bool = false,
|
||||||
wayland: bool = false,
|
wayland: bool = false,
|
||||||
|
layer_shell: bool = false,
|
||||||
sentry: bool = true,
|
sentry: bool = true,
|
||||||
wasm_shared: bool = true,
|
wasm_shared: bool = true,
|
||||||
|
|
||||||
@ -109,7 +110,6 @@ pub fn init(b: *std.Build) !Config {
|
|||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Comptime Interfaces
|
// Comptime Interfaces
|
||||||
|
|
||||||
config.font_backend = b.option(
|
config.font_backend = b.option(
|
||||||
font.Backend,
|
font.Backend,
|
||||||
"font-backend",
|
"font-backend",
|
||||||
@ -163,6 +163,12 @@ pub fn init(b: *std.Build) !Config {
|
|||||||
"Enables linking against X11 libraries when using the GTK rendering backend.",
|
"Enables linking against X11 libraries when using the GTK rendering backend.",
|
||||||
) orelse gtk_targets.x11;
|
) orelse gtk_targets.x11;
|
||||||
|
|
||||||
|
config.layer_shell = b.option(
|
||||||
|
bool,
|
||||||
|
"gtk-layer-shell",
|
||||||
|
"Enables linking against the gtk4-layer-shell library for quick terminal support. Requires Wayland.",
|
||||||
|
) orelse gtk_targets.layer_shell;
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
//---------------------------------------------------------------
|
||||||
// Ghostty Exe Properties
|
// Ghostty Exe Properties
|
||||||
|
|
||||||
@ -392,6 +398,7 @@ pub fn addOptions(self: *const Config, step: *std.Build.Step.Options) !void {
|
|||||||
step.addOption(bool, "flatpak", self.flatpak);
|
step.addOption(bool, "flatpak", self.flatpak);
|
||||||
step.addOption(bool, "x11", self.x11);
|
step.addOption(bool, "x11", self.x11);
|
||||||
step.addOption(bool, "wayland", self.wayland);
|
step.addOption(bool, "wayland", self.wayland);
|
||||||
|
step.addOption(bool, "layer_shell", self.layer_shell);
|
||||||
step.addOption(bool, "sentry", self.sentry);
|
step.addOption(bool, "sentry", self.sentry);
|
||||||
step.addOption(apprt.Runtime, "app_runtime", self.app_runtime);
|
step.addOption(apprt.Runtime, "app_runtime", self.app_runtime);
|
||||||
step.addOption(font.Backend, "font_backend", self.font_backend);
|
step.addOption(font.Backend, "font_backend", self.font_backend);
|
||||||
|
@ -460,12 +460,8 @@ pub fn add(
|
|||||||
|
|
||||||
if (self.config.wayland) {
|
if (self.config.wayland) {
|
||||||
const scanner = Scanner.create(b.dependency("zig_wayland", .{}), .{
|
const scanner = Scanner.create(b.dependency("zig_wayland", .{}), .{
|
||||||
// We shouldn't be using getPath but we need to for now
|
.wayland_xml = b.dependency("wayland", .{}).path("protocol/wayland.xml"),
|
||||||
// https://codeberg.org/ifreund/zig-wayland/issues/66
|
.wayland_protocols = b.dependency("wayland_protocols", .{}).path(""),
|
||||||
.wayland_xml = b.dependency("wayland", .{})
|
|
||||||
.path("protocol/wayland.xml"),
|
|
||||||
.wayland_protocols = b.dependency("wayland_protocols", .{})
|
|
||||||
.path(""),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const wayland = b.createModule(.{ .root_source_file = scanner.result });
|
const wayland = b.createModule(.{ .root_source_file = scanner.result });
|
||||||
@ -485,6 +481,8 @@ pub fn add(
|
|||||||
|
|
||||||
step.root_module.addImport("wayland", wayland);
|
step.root_module.addImport("wayland", wayland);
|
||||||
step.root_module.addImport("gdk_wayland", gobject.module("gdkwayland4"));
|
step.root_module.addImport("gdk_wayland", gobject.module("gdkwayland4"));
|
||||||
|
|
||||||
|
if (self.config.layer_shell) step.linkSystemLibrary2("gtk4-layer-shell", dynamic_link_opts);
|
||||||
step.linkSystemLibrary2("wayland-client", dynamic_link_opts);
|
step.linkSystemLibrary2("wayland-client", dynamic_link_opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@ RUN DEBIAN_FRONTEND="noninteractive" apt-get -qq update && \
|
|||||||
# Ghostty Dependencies
|
# Ghostty Dependencies
|
||||||
libadwaita-1-dev \
|
libadwaita-1-dev \
|
||||||
libgtk-4-dev && \
|
libgtk-4-dev && \
|
||||||
|
# TODO: Add when this is updated to Debian 13++
|
||||||
|
# gtk4-layer-shell
|
||||||
# Clean up for better caching
|
# Clean up for better caching
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ const std = @import("std");
|
|||||||
pub const Targets = packed struct {
|
pub const Targets = packed struct {
|
||||||
x11: bool = false,
|
x11: bool = false,
|
||||||
wayland: bool = false,
|
wayland: bool = false,
|
||||||
|
layer_shell: bool = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Returns the targets that GTK4 was compiled with.
|
/// Returns the targets that GTK4 was compiled with.
|
||||||
@ -17,8 +18,24 @@ pub fn targets(b: *std.Build) Targets {
|
|||||||
.Ignore,
|
.Ignore,
|
||||||
) catch return .{};
|
) catch return .{};
|
||||||
|
|
||||||
|
const x11 = std.mem.indexOf(u8, output, "x11") != null;
|
||||||
|
const wayland = std.mem.indexOf(u8, output, "wayland") != null;
|
||||||
|
|
||||||
|
const layer_shell = layer_shell: {
|
||||||
|
if (!wayland) break :layer_shell false;
|
||||||
|
|
||||||
|
_ = b.runAllowFail(
|
||||||
|
&.{ "pkg-config", "--exists", "gtk4-layer-shell-0" },
|
||||||
|
&code,
|
||||||
|
.Ignore,
|
||||||
|
) catch break :layer_shell false;
|
||||||
|
|
||||||
|
break :layer_shell true;
|
||||||
|
};
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.x11 = std.mem.indexOf(u8, output, "x11") != null,
|
.x11 = x11,
|
||||||
.wayland = std.mem.indexOf(u8, output, "wayland") != null,
|
.wayland = wayland,
|
||||||
|
.layer_shell = layer_shell,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user