apprt/gtk-ng: toggle_window_decorations

This commit is contained in:
Mitchell Hashimoto
2025-08-02 13:34:12 -07:00
parent 7836cc8f31
commit 5078fc5243
6 changed files with 71 additions and 21 deletions

View File

@@ -551,6 +551,7 @@ pub const Application = extern struct {
.toggle_fullscreen => Action.toggleFullscreen(target),
.toggle_quick_terminal => return Action.toggleQuickTerminal(self),
.toggle_tab_overview => return Action.toggleTabOverview(target),
.toggle_window_decorations => return Action.toggleWindowDecorations(target),
// Unimplemented but todo on gtk-ng branch
.prompt_title,
@@ -562,8 +563,6 @@ pub const Application = extern struct {
.equalize_splits,
.goto_split,
.toggle_split_zoom,
// TODO: winproto
.toggle_window_decorations,
=> {
log.warn("unimplemented action={}", .{action});
return false;
@@ -1768,6 +1767,25 @@ const Action = struct {
},
}
}
pub fn toggleWindowDecorations(target: apprt.Target) bool {
switch (target) {
.app => return false,
.surface => |core| {
const surface = core.rt_surface.surface;
const window = ext.getAncestor(
Window,
surface.as(gtk.Widget),
) orelse {
log.warn("surface is not in a window, ignoring new_tab", .{});
return false;
};
window.toggleWindowDecorations();
return true;
},
}
}
};
/// This sets various GTK-related environment variables as necessary

View File

@@ -10,6 +10,7 @@ const gtk = @import("gtk");
const i18n = @import("../../../os/main.zig").i18n;
const apprt = @import("../../../apprt.zig");
const configpkg = @import("../../../config.zig");
const input = @import("../../../input.zig");
const CoreSurface = @import("../../../Surface.zig");
const ext = @import("../ext.zig");
@@ -231,6 +232,11 @@ pub const Window = extern struct {
/// behaves slightly differently under certain scenarios.
quick_terminal: bool = false,
/// The window decoration override. If this is not set then we'll
/// inherit whatever the config has. This allows overriding the
/// config on a per-window basis.
window_decoration: ?configpkg.WindowDecoration = null,
/// Binding group for our active tab.
tab_bindings: *gobject.BindingGroup,
@@ -638,6 +644,36 @@ pub const Window = extern struct {
return self.private().config;
}
/// Get the current window decoration value for this window.
pub fn getWindowDecoration(self: *Self) configpkg.WindowDecoration {
const priv = self.private();
if (priv.window_decoration) |v| return v;
if (priv.config) |v| return v.get().@"window-decoration";
return .auto;
}
/// Toggle the window decorations for this window.
pub fn toggleWindowDecorations(self: *Self) void {
self.setWindowDecoration(switch (self.getWindowDecoration()) {
// Null will force using the central config
.none => null,
// Anything non-none to none
.auto, .client, .server => .none,
});
}
/// Set the window decoration override for this window. If this is null,
/// then we'll revert back to the configuration's default.
fn setWindowDecoration(
self: *Self,
new_: ?configpkg.WindowDecoration,
) void {
const priv = self.private();
priv.window_decoration = new_;
self.syncAppearance();
}
/// Get the currently selected tab as a Tab object.
fn getSelectedTab(self: *Self) ?*Tab {
const priv = self.private();

View File

@@ -396,12 +396,7 @@ pub const Window = struct {
}
fn getDecorationMode(self: Window) org.KdeKwinServerDecorationManager.Mode {
const config = if (self.apprt_window.getConfig()) |v|
v.get()
else
return .Client;
return switch (config.@"window-decoration") {
return switch (self.apprt_window.getWindowDecoration()) {
.auto => self.app_context.default_deco_mode orelse .Client,
.client => .Client,
.server => .Server,

View File

@@ -239,12 +239,7 @@ pub const Window = struct {
}
pub fn clientSideDecorationEnabled(self: Window) bool {
const config = if (self.apprt_window.getConfig()) |v|
v.get()
else
return true;
return switch (config.@"window-decoration") {
return switch (self.apprt_window.getWindowDecoration()) {
.auto, .client => true,
.server, .none => false,
};
@@ -289,11 +284,6 @@ pub const Window = struct {
}
fn syncDecorations(self: *Window) !void {
const config = if (self.apprt_window.getConfig()) |v|
v.get()
else
return;
var hints: MotifWMHints = .{};
self.getWindowProperty(
@@ -314,7 +304,7 @@ pub const Window = struct {
};
hints.flags.decorations = true;
hints.decorations.all = switch (config.@"window-decoration") {
hints.decorations.all = switch (self.apprt_window.getWindowDecoration()) {
.server => true,
.auto, .client, .none => false,
};

View File

@@ -35,6 +35,7 @@ pub const RepeatableStringMap = @import("config/RepeatableStringMap.zig");
pub const RepeatablePath = Config.RepeatablePath;
pub const Path = Config.Path;
pub const ShellIntegrationFeatures = Config.ShellIntegrationFeatures;
pub const WindowDecoration = Config.WindowDecoration;
pub const WindowPaddingColor = Config.WindowPaddingColor;
pub const BackgroundImagePosition = Config.BackgroundImagePosition;
pub const BackgroundImageFit = Config.BackgroundImageFit;

View File

@@ -7434,12 +7434,22 @@ pub const BackgroundBlur = union(enum) {
};
/// See window-decoration
pub const WindowDecoration = enum {
pub const WindowDecoration = enum(c_int) {
auto,
client,
server,
none,
/// Make this a valid gobject if we're in a GTK environment.
pub const getGObjectType = switch (build_config.app_runtime) {
.gtk, .@"gtk-ng" => @import("gobject").ext.defineEnum(
WindowDecoration,
.{ .name = "GhosttyConfigWindowDecoration" },
),
.none => void,
};
pub fn parseCLI(input_: ?[]const u8) !WindowDecoration {
const input = input_ orelse return .auto;