apprt/gtk-ng: quick terminal

This commit is contained in:
Mitchell Hashimoto
2025-08-01 20:51:39 -07:00
parent 084a20c865
commit 7aa84cd372
4 changed files with 80 additions and 2 deletions

View File

@@ -549,6 +549,7 @@ pub const Application = extern struct {
.toggle_maximize => Action.toggleMaximize(target),
.toggle_fullscreen => Action.toggleFullscreen(target),
.toggle_quick_terminal => return Action.toggleQuickTerminal(self),
.toggle_tab_overview => return Action.toggleTabOverview(target),
// Unimplemented but todo on gtk-ng branch
@@ -562,7 +563,6 @@ pub const Application = extern struct {
.goto_split,
.toggle_split_zoom,
// TODO: winproto
.toggle_quick_terminal,
.toggle_window_decorations,
=> {
log.warn("unimplemented action={}", .{action});
@@ -1477,7 +1477,14 @@ const Action = struct {
parent: ?*CoreSurface,
) !void {
const win = Window.new(self);
initAndShowWindow(self, win, parent);
}
fn initAndShowWindow(
self: *Application,
win: *Window,
parent: ?*CoreSurface,
) void {
// Setup a binding so that whenever our config changes so does the
// window. There's never a time when the window config should be out
// of sync with the application config.
@@ -1694,6 +1701,48 @@ const Action = struct {
}
}
pub fn toggleQuickTerminal(self: *Application) bool {
// If we already have a quick terminal window, we just toggle the
// visibility of it.
if (getQuickTerminalWindow()) |win| {
win.toggleVisibility();
return true;
}
// If we don't support quick terminals then we do nothing.
const priv = self.private();
if (!priv.winproto.supportsQuickTerminal()) return false;
// Create our new window as a quick terminal
const win = gobject.ext.newInstance(Window, .{
.application = self,
.@"quick-terminal" = true,
});
assert(win.isQuickTerminal());
initAndShowWindow(self, win, null);
return true;
}
fn getQuickTerminalWindow() ?*Window {
// Find a quick terminal window.
const list = gtk.Window.listToplevels();
defer list.free();
const elem_: ?*glib.List = list.findCustom(null, struct {
fn callback(data: ?*const anyopaque, _: ?*const anyopaque) callconv(.c) c_int {
const ptr = data orelse return 1;
const gtk_window: *gtk.Window = @ptrCast(@alignCast(@constCast(ptr)));
const window = gobject.ext.cast(
Window,
gtk_window,
) orelse return 1;
if (window.isQuickTerminal()) return 0;
return 1;
}
}.callback);
const elem = elem_ orelse return null;
return @ptrCast(@alignCast(elem.f_data));
}
pub fn toggleMaximize(target: apprt.Target) void {
switch (target) {
.app => {},

View File

@@ -498,6 +498,12 @@ pub const Window = extern struct {
tab_overview.setOpen(@intFromBool(!is_open));
}
/// Toggle the visible property.
pub fn toggleVisibility(self: *Self) void {
const widget = self.as(gtk.Widget);
widget.setVisible(@intFromBool(widget.isVisible() == 0));
}
/// Updates various appearance properties. This should always be safe
/// to call multiple times. This should be called whenever a change
/// happens that might affect how the window appears (config change,
@@ -768,6 +774,26 @@ pub const Window = extern struct {
action.setEnabled(@intFromBool(has_selection));
}
fn propQuickTerminal(
_: *adw.ApplicationWindow,
_: *gobject.ParamSpec,
self: *Self,
) callconv(.c) void {
const priv = self.private();
if (priv.surface_init) {
log.warn("quick terminal property can't be changed after surfaces have been initialized", .{});
return;
}
if (priv.quick_terminal) {
// Initialize the quick terminal at the app-layer
Application.default().winproto().initQuickTerminal(self) catch |err| {
log.warn("failed to initialize quick terminal error={}", .{err});
return;
};
}
}
/// Add or remove "background" CSS class depending on if the background
/// should be opaque.
fn propBackgroundOpaque(
@@ -1473,6 +1499,7 @@ pub const Window = extern struct {
properties.config.impl,
properties.debug.impl,
properties.@"headerbar-visible".impl,
properties.@"quick-terminal".impl,
properties.@"tabs-autohide".impl,
properties.@"tabs-visible".impl,
properties.@"tabs-wide".impl,
@@ -1503,6 +1530,7 @@ pub const Window = extern struct {
class.bindTemplateCallback("notify_fullscreened", &propFullscreened);
class.bindTemplateCallback("notify_maximized", &propMaximized);
class.bindTemplateCallback("notify_menu_active", &propMenuActive);
class.bindTemplateCallback("notify_quick_terminal", &propQuickTerminal);
class.bindTemplateCallback("notify_scale_factor", &propScaleFactor);
// Virtual methods

View File

@@ -12,6 +12,7 @@ template $GhosttyWindow: Adw.ApplicationWindow {
notify::config => $notify_config();
notify::fullscreened => $notify_fullscreened();
notify::maximized => $notify_maximized();
notify::quick-terminal => $notify_quick_terminal();
notify::scale-factor => $notify_scale_factor();
default-width: 800;
default-height: 600;

View File

@@ -127,7 +127,7 @@ pub const App = struct {
}
pub fn initQuickTerminal(_: *App, apprt_window: *ApprtWindow) !void {
const window = apprt_window.window.as(gtk.Window);
const window = apprt_window.as(gtk.Window);
layer_shell.initForWindow(window);
layer_shell.setLayer(window, .top);