From a8fde31c82d890ca755dd9d8da73f41863ac90eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 21 Apr 2026 19:46:27 +0400 Subject: [PATCH 1/3] add fullscreen toggle with F11 and hide title bar in fullscreen Adds toggle_fullscreen action (F11), command palette entry, and shortcuts overlay row. Hides the CSD header bar on fullscreen via notify::fullscreened signal, restoring it on exit. SSD mode is unaffected since the WM manages its own decorations. Co-Authored-By: Claude Opus 4.6 --- src/command_palette.zig | 1 + src/keybinds.zig | 3 +++ src/shortcuts_overlay.zig | 1 + src/window.zig | 26 ++++++++++++++++++++++++++ 4 files changed, 31 insertions(+) diff --git a/src/command_palette.zig b/src/command_palette.zig index e856fb7..d116f7b 100644 --- a/src/command_palette.zig +++ b/src/command_palette.zig @@ -117,6 +117,7 @@ const static_commands = [_]Command{ .{ .label = "Jump to Unread", .action = .jump_to_unread, .keywords = "jump unread notification" }, .{ .label = "Open Settings", .action = .open_settings, .keywords = "settings preferences config options" }, .{ .label = "Reload Configuration", .action = .reload_config, .keywords = "config reload refresh settings" }, + .{ .label = "Toggle Fullscreen", .action = .toggle_fullscreen, .keywords = "fullscreen toggle window maximize f11" }, .{ .label = "Quit Seance", .action = .quit_app, .keywords = "quit exit close application app shutdown" }, // Workspace commands diff --git a/src/keybinds.zig b/src/keybinds.zig index 8ed2096..3fb98ee 100644 --- a/src/keybinds.zig +++ b/src/keybinds.zig @@ -73,6 +73,7 @@ pub const Action = enum(u8) { // Window new_window, + toggle_fullscreen, quit_app, // Command palette @@ -260,6 +261,7 @@ fn initDefaults() void { // Window set(.new_window, .{ .key = c.GDK_KEY_N, .ctrl = true, .shift = true }); + set(.toggle_fullscreen, .{ .key = c.GDK_KEY_F11 }); set(.quit_app, .{ .key = c.GDK_KEY_Q, .ctrl = true, .shift = true }); // Command palette @@ -547,6 +549,7 @@ pub fn executeAction(action: Action, state: *Window.WindowState) c.gboolean { .new_window => { _ = state.window_manager.newWindow(); }, + .toggle_fullscreen => state.toggleFullscreen(), .quit_app => state.quitApp(), // Command palette diff --git a/src/shortcuts_overlay.zig b/src/shortcuts_overlay.zig index b98f185..203f354 100644 --- a/src/shortcuts_overlay.zig +++ b/src/shortcuts_overlay.zig @@ -121,6 +121,7 @@ const groups = [_]Group{ .title = "General", .rows = &.{ .{ .single = .{ .action = .new_window, .label = "New Window" } }, + .{ .single = .{ .action = .toggle_fullscreen, .label = "Fullscreen" } }, .{ .single = .{ .action = .open_command_palette, .label = "Command Palette" } }, .{ .single = .{ .action = .open_folder, .label = "Open Folder" } }, .{ .single = .{ .action = .open_settings, .label = "Settings" } }, diff --git a/src/window.zig b/src/window.zig index 3f11a04..b90a1c9 100644 --- a/src/window.zig +++ b/src/window.zig @@ -814,6 +814,15 @@ pub const WindowState = struct { /// `confirm_close_window` is enabled and there's interesting state to /// warn about (multiple windows or multiple workspaces), shows a single /// quit confirmation dialog instead of doing it per-window. + pub fn toggleFullscreen(self: *WindowState) void { + const win: *c.GtkWindow = @ptrCast(self.gtk_window); + if (c.gtk_window_is_fullscreen(win) != 0) { + c.gtk_window_unfullscreen(win); + } else { + c.gtk_window_fullscreen(win); + } + } + pub fn quitApp(self: *WindowState) void { const cfg = config_mod.get(); if (!cfg.confirm_close_window or !hasInterestingState(self.window_manager)) { @@ -1552,6 +1561,16 @@ pub fn create(wm: *WindowManager) !*WindowState { 0, ); + // Hide CSD title bar when entering fullscreen + _ = c.g_signal_connect_data( + @as(c.gpointer, @ptrCast(window)), + "notify::fullscreened", + @as(c.GCallback, @ptrCast(&onFullscreenChanged)), + @ptrCast(state), + null, + 0, + ); + // Load theme-aware CSS loadThemeCss(); @@ -1695,6 +1714,13 @@ fn onWindowFocusChanged(_: *c.GObject, _: ?*anyopaque, data: c.gpointer) callcon } } +fn onFullscreenChanged(_: *c.GObject, _: ?*anyopaque, data: c.gpointer) callconv(.c) void { + const state: *WindowState = @ptrCast(@alignCast(data)); + const tv = state.toolbar_view orelse return; + const is_fullscreen = c.gtk_window_is_fullscreen(@as(*c.GtkWindow, @ptrCast(state.gtk_window))); + c.adw_toolbar_view_set_reveal_top_bars(@as(*c.AdwToolbarView, @ptrCast(tv)), if (is_fullscreen != 0) 0 else 1); +} + fn onWorkspaceSelect(index: usize) void { if (window_manager) |wm| if (wm.active_window) |state| state.selectWorkspace(index); } From 37a47d77d0361d026b5e410d404f83578407521f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Sat, 25 Apr 2026 01:19:34 +0400 Subject: [PATCH 2/3] fix zsh not finding user config in shell wrapper directory The wrapper resources directory was missing ghostty's .zshenv symlink, so zsh (with ZDOTDIR pointing there) found no startup files and showed the new-user wizard instead of sourcing the user's config. Co-Authored-By: Claude Opus 4.6 --- src/ghostty_bridge.zig | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/ghostty_bridge.zig b/src/ghostty_bridge.zig index 42c6754..a555de0 100644 --- a/src/ghostty_bridge.zig +++ b/src/ghostty_bridge.zig @@ -211,6 +211,21 @@ fn createWrapperResourcesDir() bool { } } + // Symlink ghostty's .zshenv — ghostty sets ZDOTDIR to this directory so + // zsh auto-sources .zshenv, which restores the real ZDOTDIR and chains + // into ghostty-integration. Without this symlink the wrapper directory + // has no .zshenv and zsh shows the new-user wizard. + { + var zbuf: [std.fs.max_path_bytes]u8 = undefined; + const ztarget = std.fmt.bufPrint(&zbuf, "{s}/shell-integration/zsh/.zshenv", .{real}) catch return false; + var zsh_dir = wd.openDir("shell-integration/zsh", .{}) catch return false; + defer zsh_dir.close(); + zsh_dir.symLink(ztarget, ".zshenv", .{}) catch |e| { + std.log.warn("ghostty_bridge: failed to symlink .zshenv: {}", .{e}); + return false; + }; + } + // Write wrapper shell integration scripts writeShellWrapper(wd, "shell-integration/bash/ghostty.bash", real, "/shell-integration/bash/ghostty.bash", "/bash-integration.sh") catch return false; writeShellWrapper(wd, "shell-integration/zsh/ghostty-integration", real, "/shell-integration/zsh/ghostty-integration", "/zsh-integration.sh") catch return false; From 7bf738b191e7da0220623797c3d69ed01a17db61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Sat, 25 Apr 2026 01:22:06 +0400 Subject: [PATCH 3/3] namespace seance resources under share/seance/ Move shell-integration and bin install paths from share/shell-integration and share/bin to share/seance/shell-integration and share/seance/bin to avoid conflicts with other packages. Co-Authored-By: Claude Opus 4.6 --- build.zig | 4 ++-- src/pane.zig | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build.zig b/build.zig index 2db6478..e86ad34 100644 --- a/build.zig +++ b/build.zig @@ -182,14 +182,14 @@ pub fn build(b: *std.Build) void { b.installDirectory(.{ .source_dir = b.path("resources/shell-integration"), .install_dir = .prefix, - .install_subdir = "share/shell-integration", + .install_subdir = "share/seance/shell-integration", }); // Install wrapper scripts (claude wrapper, etc.) b.installDirectory(.{ .source_dir = b.path("resources/bin"), .install_dir = .prefix, - .install_subdir = "share/bin", + .install_subdir = "share/seance/bin", }); // Install bundled icons (from GNOME Icon Library) into hicolor theme diff --git a/src/pane.zig b/src/pane.zig index 23fe877..66a0432 100644 --- a/src/pane.zig +++ b/src/pane.zig @@ -670,10 +670,10 @@ fn initSurface(pane: *Pane, width: u32, height: u32) void { if (std.fs.selfExePath(&exe_buf)) |exe_path| { if (std.fs.path.dirname(exe_path)) |exe_dir| { if (std.fs.path.dirname(exe_dir)) |prefix| { - if (std.fmt.bufPrintZ(&int_env_val_buf, "{s}/share/shell-integration", .{prefix})) |iv| { + if (std.fmt.bufPrintZ(&int_env_val_buf, "{s}/share/seance/shell-integration", .{prefix})) |iv| { int_val = iv; } else |_| {} - if (std.fmt.bufPrintZ(&bin_env_val_buf, "{s}/share/bin", .{prefix})) |bv| { + if (std.fmt.bufPrintZ(&bin_env_val_buf, "{s}/share/seance/bin", .{prefix})) |bv| { bin_val = bv; } else |_| {} }