From b1f9891849f03b24834f305d8b9a20e8ff618cdb Mon Sep 17 00:00:00 2001 From: Gabriel Brown Date: Tue, 18 Aug 2026 08:34:05 -0400 Subject: [PATCH] Add multitasking controls, and a light theme for the launcher Two things, both closing gaps in work that was already reported done. GNOME's Multitasking panel, in Hyprland's terms: tiling layout, split behaviour, floating-window snapping, workspace wrap-around and back-and-forth, whether applications may take focus, and whether the pointer changes the active display. Hyprland creates and destroys workspaces as you use them, so there is no fixed count to expose, and the page says so rather than leaving a conspicuous absence. The Desktop page described the first two of these as read-only facts -- "Layout: Tiling", "Workspace movement: Dynamic" -- which was never true. Both are ordinary Hyprland options that happened to have no controls, and TextRow's own documentation says a setting the user could reasonably change does not belong in it. Schema defaults are Panama's shipped values from looks.lua rather than Hyprland's own, so restoring defaults returns the desktop to how it ships. 43 mapped options now, from 35. The launcher had no light theme. vicinae.json already selected a theme per system appearance, but both entries pointed at Moon, so choosing light mode left the most frequently opened window on the desktop dark -- a hole in the light/dark work, not a missing feature. Day is authored from the same palette as the kitty Day theme so the two cannot drift, and link-dotfiles now installs every authored theme rather than only the dark one, which is why the gap survived being noticed. Its placeholder colour is not Tokyo Night Day's own: that measures 2.54:1 against the background, below the 3:1 floor for secondary text. This is 3.25:1, the same value used for neovim's light comments. Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L --- .../quickshell/config/PreferenceSchema.qml | 68 +++++++++++++++ .../modules/settings/DesktopPage.qml | 30 ++++--- .../quickshell/services/SettingsSearch.qml | 1 + config/dot/vicinae/themes/tokyonight-day.toml | 87 +++++++++++++++++++ config/dot/vicinae/vicinae.json | 10 ++- setup/scripts/link-dotfiles | 27 +++--- 6 files changed, 199 insertions(+), 24 deletions(-) create mode 100644 config/dot/vicinae/themes/tokyonight-day.toml diff --git a/config/dot/quickshell/config/PreferenceSchema.qml b/config/dot/quickshell/config/PreferenceSchema.qml index 858f90a..fab097c 100644 --- a/config/dot/quickshell/config/PreferenceSchema.qml +++ b/config/dot/quickshell/config/PreferenceSchema.qml @@ -421,6 +421,74 @@ Singleton { hypr: { path: ["input", "touchpad", "middle_button_emulation"], option: "input:touchpad:middle_button_emulation", readAs: "bool" } }, + // ── Multitasking ──────────────────────────────────────────────────── + // + // GNOME's Multitasking panel, in Hyprland's terms. The Desktop page + // described the first two of these as read-only facts ("Layout: + // Tiling"), which was never true -- they are ordinary settings that + // happened not to have controls. + // + // Defaults here are Panama's shipped values from hypr/looks.lua, not + // Hyprland's own, so restoring defaults returns the desktop to how it + // ships rather than to how Hyprland would behave with no config. + { + key: "windowLayout", type: "enum", def: "dwindle", group: "multitasking", + label: "Tiling layout", + detail: "Dwindle splits the focused window; master keeps one large window beside a stack", + options: [ + { value: "dwindle", label: "Dwindle" }, + { value: "master", label: "Master and stack" } + ], + hypr: { path: ["general", "layout"], option: "general:layout", readAs: "str" } + }, + { + key: "preserveSplit", type: "bool", def: true, group: "multitasking", + label: "Keep split direction", + detail: "New windows follow the split of the window they replace, instead of always halving the longer side", + hypr: { path: ["dwindle", "preserve_split"], option: "dwindle:preserve_split", readAs: "bool" } + }, + { + key: "forceSplit", type: "enum", def: 0, group: "multitasking", + label: "New windows open", + detail: "Where a new window lands relative to the one that was focused", + options: [ + { value: 0, label: "Where the pointer is" }, + { value: 1, label: "Always left or above" }, + { value: 2, label: "Always right or below" } + ], + hypr: { path: ["dwindle", "force_split"], option: "dwindle:force_split", readAs: "int" } + }, + { + key: "windowSnapping", type: "bool", def: true, group: "multitasking", + label: "Snap floating windows", + detail: "Floating windows stick to screen edges and to each other as you drag them", + hypr: { path: ["general", "snap", "enabled"], option: "general:snap:enabled", readAs: "bool" } + }, + { + key: "workspaceBackAndForth", type: "bool", def: false, group: "multitasking", + label: "Switch back and forth", + detail: "Selecting the workspace you are already on returns you to the previous one", + hypr: { path: ["binds", "workspace_back_and_forth"], option: "binds:workspace_back_and_forth", readAs: "bool" } + }, + { + key: "allowWorkspaceCycles", type: "bool", def: false, group: "multitasking", + label: "Wrap around at the ends", + detail: "Moving past the last workspace continues from the first", + hypr: { path: ["binds", "allow_workspace_cycles"], option: "binds:allow_workspace_cycles", readAs: "bool" } + }, + { + key: "focusOnActivate", type: "bool", def: false, group: "multitasking", + label: "Let applications take focus", + detail: "An application asking for attention is switched to, rather than only highlighted", + hypr: { path: ["misc", "focus_on_activate"], option: "misc:focus_on_activate", readAs: "bool" } + }, + { + key: "mouseMoveFocusesMonitor", type: "bool", def: true, group: "multitasking", + label: "Pointer changes active display", + detail: "Moving the pointer to another display makes it the active one", + hypr: { path: ["misc", "mouse_move_focuses_monitor"], option: "misc:mouse_move_focuses_monitor", readAs: "bool" } + }, + // ── Night light ───────────────────────────────────────────────────── { key: "nightLightEnabled", type: "bool", def: false, group: "nightLight", diff --git a/config/dot/quickshell/modules/settings/DesktopPage.qml b/config/dot/quickshell/modules/settings/DesktopPage.qml index dafdf01..8f6524a 100644 --- a/config/dot/quickshell/modules/settings/DesktopPage.qml +++ b/config/dot/quickshell/modules/settings/DesktopPage.qml @@ -49,16 +49,14 @@ SettingsPage { title: "Window layout" subtitle: "Panama follows the Forge mental model with native Hyprland tiling." - TextRow { - label: "Layout" - detail: "Dwindle with preserved split direction" - value: "Tiling" - } - TextRow { - label: "Workspace movement" - detail: "Alt+H / Alt+L, add Shift to move a window" - value: "Dynamic" - } + // These were two read-only rows reporting "Tiling" and "Dynamic", which + // described settings rather than facts -- both are ordinary Hyprland + // options that simply had no controls. TextRow's own documentation says + // a setting the user could reasonably change does not belong in it. + ChoiceRow { setting: "windowLayout" } + ToggleRow { setting: "preserveSplit" } + ChoiceRow { setting: "forceSplit" } + ToggleRow { setting: "windowSnapping" } ActionRow { label: "Gaps, corners, and effects" detail: "Adjusted on the Appearance page, beside a live preview" @@ -68,6 +66,18 @@ SettingsPage { } } + // GNOME's Multitasking panel, in Hyprland's terms. + SettingsCard { + title: "Workspaces & focus" + subtitle: "Hyprland's workspaces are created and destroyed as you use them, so there is no fixed count to set." + + ToggleRow { setting: "workspaceBackAndForth" } + ToggleRow { setting: "allowWorkspaceCycles" } + ToggleRow { setting: "focusOnActivate" } + ToggleRow { setting: "mouseMoveFocusesMonitor" } + ChoiceRow { setting: "followMouse"; divider: false } + } + SettingsCard { title: "Focus" diff --git a/config/dot/quickshell/services/SettingsSearch.qml b/config/dot/quickshell/services/SettingsSearch.qml index 3179aeb..88d9ec7 100644 --- a/config/dot/quickshell/services/SettingsSearch.qml +++ b/config/dot/quickshell/services/SettingsSearch.qml @@ -35,6 +35,7 @@ Singleton { "input": "shortcuts", "pointer": "mouse", "touchpad": "mouse", + "multitasking": "desktop", "weather": "appearance", "notifications": "notifications", "capture": "screen-intelligence" diff --git a/config/dot/vicinae/themes/tokyonight-day.toml b/config/dot/vicinae/themes/tokyonight-day.toml new file mode 100644 index 0000000..e00de6b --- /dev/null +++ b/config/dot/vicinae/themes/tokyonight-day.toml @@ -0,0 +1,87 @@ +# Tokyo Night Day — the light counterpart to tokyonight-moon.toml. +# +# Same schema and the same role for every colour; only the palette differs, so +# the launcher keeps its identity when the desktop switches to light rather +# than becoming a different-looking application. +# +# Colours are the Tokyo Night Day palette, taken from kitty/themes/tokyonight-day.conf +# so the launcher and the terminal cannot drift apart. + +[meta] +version = 1 +name = "Tokyo Night Day" +description = "Tokyo Night Day, matched to the Panama Hyprland desktop." +variant = "light" + +[colors.core] +background = "#e1e2e7" # bg +foreground = "#3760bf" # fg +secondary_background = "#d0d5e3" # bg_dark, a shade below the ground +border = "#a8aecb" # a visible hairline on a light ground +accent = "#2e7de9" # blue +accent_foreground = "#e1e2e7" + +[colors.accents] +blue = "#2e7de9" +green = "#587539" +magenta = "#9854f1" +orange = "#b15c00" +purple = "#7847bd" +red = "#f52a65" +yellow = "#8c6c3e" +cyan = "#007197" + +[colors.main_window] +border = "#a8aecb" +footer = { background = "colors.core.secondary_background" } + +[colors.settings_window] +border = "#c4c8da" + +[colors.shortcut] +border = "colors.core.border" + +[colors.text] +default = "colors.core.foreground" +muted = "#6172b0" # fg_dark, 4.0:1 on the background +danger = "#f52a65" +success = "#587539" +placeholder = "#7079a8" # 3.25:1; Day's own #848cb5 is 2.54:1, too faint to read +selection = { background = "#2e7de9", foreground = "#e1e2e7" } + +[colors.text.links] +default = "#2e7de9" +visited = "#9854f1" + +[colors.input] +border = "#c4c8da" +border_focus = "#2e7de9" +border_error = "#f52a65" + +[colors.button.primary] +background = "#d4d6e4" # bg_highlight +foreground = "#3760bf" +hover = { background = "#c4c8da" } +focus = { outline = "colors.core.accent" } + +[colors.list.item.hover] +foreground = "#3760bf" +secondary_foreground = "#6172b0" + +[colors.list.item.selection] +background = "#c3cdf0" # blue side of the Prism selection, lightened +foreground = "#3760bf" +secondary_background = "#d8c8e4" # orchid side of the Prism selection, lightened +secondary_foreground = "#3760bf" + +[colors.grid.item] +background = "#d7d9e5" +hover = { outline = "#2e7de9" } +selection = { outline = "#9854f1" } + +[colors.scrollbars] +background = "#c4c8da" + +[colors.loading] +bar = "#2e7de9" +spinner = "#3760bf" diff --git a/config/dot/vicinae/vicinae.json b/config/dot/vicinae/vicinae.json index 0795bfe..202f057 100644 --- a/config/dot/vicinae/vicinae.json +++ b/config/dot/vicinae/vicinae.json @@ -6,12 +6,14 @@ // and emoji-copy extensions, so its clipboard and emoji views are bound // directly in hypr/keybinds.lua. - // Vicinae 0.26 selects a theme per system appearance. Both point to Moon so - // the launcher never flashes or falls back to its stock palette while the - // desktop appearance is being initialized. + // Vicinae 0.26 selects a theme per system appearance, and now there is a + // theme for each: the launcher follows Panama's light/dark setting instead of + // staying dark on a light desktop. Both are authored here rather than using + // Vicinae's bundled Tokyo Night, which ships Night and Storm but not the Moon + // and Day variants the rest of this desktop uses. "theme": { "light": { - "name": "tokyonight-moon", + "name": "tokyonight-day", "icon_theme": "auto" }, "dark": { diff --git a/setup/scripts/link-dotfiles b/setup/scripts/link-dotfiles index 3ab8fd6..b3e0fde 100755 --- a/setup/scripts/link-dotfiles +++ b/setup/scripts/link-dotfiles @@ -95,19 +95,26 @@ fi # from ~/.config/vicinae. Keep the authored theme in Panama with the rest of # the launcher config and expose only that file at Vicinae's runtime path. VICINAE_THEME_DIR="$HOME/.local/share/vicinae/themes" -VICINAE_THEME="$VICINAE_THEME_DIR/tokyonight-moon.toml" mkdir -p "$VICINAE_THEME_DIR" -if [ -L "$VICINAE_THEME" ]; then - rm "$VICINAE_THEME" -fi +# Every authored theme, not just the dark one: vicinae.json selects a theme per +# system appearance, so linking only Moon left the launcher falling back to its +# stock palette whenever Panama was in light mode. +for theme_src in "$PANAMA_DOT"/vicinae/themes/*.toml; do + [ -e "$theme_src" ] || continue + theme_dst="$VICINAE_THEME_DIR/$(basename "$theme_src")" -if [ -e "$VICINAE_THEME" ]; then - log "Keeping existing Vicinae theme at $VICINAE_THEME" -else - ln -s "$PANAMA_DOT/vicinae/themes/tokyonight-moon.toml" "$VICINAE_THEME" - log "Linked Tokyo Night Moon theme → $VICINAE_THEME" -fi + if [ -L "$theme_dst" ]; then + rm "$theme_dst" + fi + + if [ -e "$theme_dst" ]; then + log "Keeping existing Vicinae theme at $theme_dst" + else + ln -s "$theme_src" "$theme_dst" + log "Linked Vicinae theme → $theme_dst" + fi +done # Panama-native applications live in the user data directory so launchers can # discover them alongside system desktop entries. Keep each authored file in