Drop the product branding: this is just Settings

It is the system settings app for this desktop, so it is named the way
one is. The window is "Settings", the titlebar is "Settings", the
wordmark above the search field is gone, the sidebar's last row is
"About", and the status line reads "Desktop is healthy".

Prose followed the same rule. Forty-odd strings explained what "Panama"
does -- "Panama never animates while idle", "Restore Panama defaults",
"Panama looks in ~/Pictures/Wallpapers" -- which is how a product
describes itself, not how a settings panel describes a setting. They now
say what happens. No user-visible "Panama" remains anywhere in the app.

Two consequences worth naming:

The SUPER+I shortcut's description is user-visible, because the
Shortcuts page is generated from it, so that is renamed too. Rebindings
are keyed by shipped chord rather than description, so no existing
override is orphaned by this.

Three contracts matched the window by title and one matched that
shortcut by description; all four are updated. There are no Hyprland
window rules keyed on the title, so nothing about the window's placement
changes.

The desktop entry is now Name=Settings, but the FILE keeps its
panama-settings name, as does the icon: the dock pins applications by
desktop id, and renaming the file would silently unpin it.
dock-pins-contract covers exactly that.

The dated design docs under docs/superpowers keep the old name. They are
a record of what was decided when, and editing them to agree with the
present would make them lie about the past.

Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L
This commit is contained in:
Gabriel Brown
2026-08-18 10:08:55 -04:00
parent 816ea68f9a
commit 9b2fa80ab7
29 changed files with 88 additions and 87 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ same Tokyo Night Moon palette.
| Piece | What it is | | Piece | What it is |
|---|---| |---|---|
| `config/dot/hypr/` | Compositor config. **Lua, not hyprlang** — see its README | | `config/dot/hypr/` | Compositor config. **Lua, not hyprlang** — see its README |
| `config/dot/quickshell/` | The shell: bar, dock, Continuum overview, Panama Settings, Screen Intelligence, focus sessions, quick settings, notifications, screenshot UI | | `config/dot/quickshell/` | The shell: bar, dock, Continuum overview, Settings, Screen Intelligence, focus sessions, quick settings, notifications, screenshot UI |
| `config/dot/vicinae/` | Raycast-style launcher, themed | | `config/dot/vicinae/` | Raycast-style launcher, themed |
| `config/dot/uwsm/` | Session environment (see the uwsm caveat in the hypr README) | | `config/dot/uwsm/` | Session environment (see the uwsm caveat in the hypr README) |
| `config/dot/wofi/` | Fallback launcher, in case the shell fails to start | | `config/dot/wofi/` | Fallback launcher, in case the shell fails to start |
+1 -1
View File
@@ -36,7 +36,7 @@ Last live audit: 2026-08-17, Fedora 44, Hyprland 0.56.2, Quickshell 0.3.0.
| Removable media | udiskie plus udisks notifications | Live | | Removable media | udiskie plus udisks notifications | Live |
| Autostart apps | Nextcloud, Bitwarden, and RustDesk system service/tray | Live | | Autostart apps | Nextcloud, Bitwarden, and RustDesk system service/tray | Live |
| Printer administration | CUPS with the `system-config-printer` graphical interface | Live | | Printer administration | CUPS with the `system-config-printer` graphical interface | Live |
| System settings | Panama Settings for display policy, appearance, desktop, sound, focus, shortcuts, and services; labelled GNOME hardware/account handoffs | Live | | System settings | The Settings app for display policy, appearance, desktop, sound, focus, shortcuts, and services; labelled GNOME hardware/account handoffs | Live |
## GNOME extension migration ## GNOME extension migration
+8 -8
View File
@@ -27,7 +27,7 @@ Don't "fix" them.
| File | Contents | | File | Contents |
|---|---| |---|---|
| `hyprland.lua` | Entry point. Each `require()` is its own error scope | | `hyprland.lua` | Entry point. Each `require()` is its own error scope |
| `prefs.lua` | Reads the settings file Panama Settings writes. See below | | `prefs.lua` | Reads the settings file the Settings app writes. See below |
| `env.lua` | Environment. Note the uwsm caveat below | | `env.lua` | Environment. Note the uwsm caveat below |
| `monitors.lua` | DP-2 geometry, scaling, and the HDR decision | | `monitors.lua` | DP-2 geometry, scaling, and the HDR decision |
| `looks.lua` | Colours, blur, glow, shadows, animations, VRR, scanout | | `looks.lua` | Colours, blur, glow, shadows, animations, VRR, scanout |
@@ -59,7 +59,7 @@ generated elsewhere:
`quickshell/scripts/panama-idle` regenerates the hypridle config from the `quickshell/scripts/panama-idle` regenerates the hypridle config from the
settings store and restarts the daemon. `hypridle.conf` in this directory settings store and restarts the daemon. `hypridle.conf` in this directory
remains the shipped default and is what runs when the drop-in is not installed; remains the shipped default and is what runs when the drop-in is not installed;
Panama Settings shows which of the two states you are in rather than presenting The Settings app shows which of the two states you are in rather than presenting
controls that quietly do nothing. controls that quietly do nothing.
Remove the drop-in and go back to the shipped config with: Remove the drop-in and go back to the shipped config with:
@@ -77,7 +77,7 @@ relationship is:
`prefs.get("key", <shipped value>)`, so the config still works standalone with `prefs.get("key", <shipped value>)`, so the config still works standalone with
no settings file at all. no settings file at all.
- **The JSON is the truth.** Hyprland and Quickshell both read it. - **The JSON is the truth.** Hyprland and Quickshell both read it.
- **Panama Settings is the editor.** It writes the file *and* applies the change - **The Settings app is the editor.** It writes the file *and* applies the change
live, so nothing needs a reload and the two sides cannot drift apart. live, so nothing needs a reload and the two sides cannot drift apart.
To add an adjustable setting: add an entry to To add an adjustable setting: add an entry to
@@ -95,7 +95,7 @@ accepts the config in each of those states.
Every bind in `keybinds.lua` goes through a local `bind()` wrapper that Every bind in `keybinds.lua` goes through a local `bind()` wrapper that
substitutes the chord from a stored override, so shortcuts can be moved from substitutes the chord from a stored override, so shortcuts can be moved from
Panama Settings without editing this file. the Settings app without editing this file.
```lua ```lua
bind(mod .. " + Q", hl.dsp.window.close(), { description = "Close window" }) bind(mod .. " + Q", hl.dsp.window.close(), { description = "Close window" })
@@ -118,7 +118,7 @@ shipped one, so a hand-edited `settings.json` cannot cost you a keymap.
Every `hl.bind` must pass a `description`. Hyprland reports Lua-defined binds Every `hl.bind` must pass a `description`. Hyprland reports Lua-defined binds
with dispatcher `__lua` and a bytecode offset as the argument, so a bind without with dispatcher `__lua` and a bytecode offset as the argument, so a bind without
one has nothing readable beside its chord, and Panama Settings drops it from the one has nothing readable beside its chord, and the Settings app drops it from the
Input & Shortcuts page rather than showing a mystery row. Input & Shortcuts page rather than showing a mystery row.
`tests/quickshell/keybinds-contract.sh` fails if any bind lacks a description, so `tests/quickshell/keybinds-contract.sh` fails if any bind lacks a description, so
this cannot regress silently. this cannot regress silently.
@@ -275,7 +275,7 @@ The mental model is unchanged from Forge:
| `SUPER + V` | Clipboard history | | `SUPER + V` | Clipboard history |
| `SUPER + .` | Emoji picker | | `SUPER + .` | Emoji picker |
| `SUPER + S` | Quick settings | | `SUPER + S` | Quick settings |
| `SUPER + I` | Panama Settings | | `SUPER + I` | Settings |
| `SUPER + SHIFT + F` | Start or reveal focus session | | `SUPER + SHIFT + F` | Start or reveal focus session |
| `SUPER + B` | Notification centre | | `SUPER + B` | Notification centre |
| `SUPER + grave` | Workspace overview | | `SUPER + grave` | Workspace overview |
@@ -288,7 +288,7 @@ The mental model is unchanged from Forge:
### Apps ### Apps
`SUPER + T` terminal · `N` neovim · `W` browser · `F` files · `C` calculator · `SUPER + T` terminal · `N` neovim · `W` browser · `F` files · `C` calculator ·
`E` mail · `I` Panama Settings · `CTRL + SHIFT + Esc` system monitor. GNOME `E` mail · `I` Settings · `CTRL + SHIFT + Esc` system monitor. GNOME
Settings remains searchable in Vicinae for hardware and account panels. Settings remains searchable in Vicinae for hardware and account panels.
## Calendar and notifications ## Calendar and notifications
@@ -326,7 +326,7 @@ one place. Home and Phone continue the same surface rather than opening extra
dashboard windows. dashboard windows.
Home shows the first four selected favourites at rest and every selected light Home shows the first four selected favourites at rest and every selected light
when expanded. Use **Panama Settings → Home & Phone** to choose favourites, when expanded. Use **Settings → Home & Phone** to choose favourites,
set Panama-only aliases, and arrange their order. Dragging a brightness control set Panama-only aliases, and arrange their order. Dragging a brightness control
only previews the value; releasing it sends one brightness request. A normal only previews the value; releasing it sends one brightness request. A normal
power toggle leaves Home Assistant responsible for restoring its previous power toggle leaves Home Assistant responsible for restoring its previous
+1 -1
View File
@@ -80,7 +80,7 @@ bind(mod .. " + W", hl.dsp.exec_cmd(browser), { description = "Browser" })
bind(mod .. " + F", hl.dsp.exec_cmd(files), { description = "Files" }) bind(mod .. " + F", hl.dsp.exec_cmd(files), { description = "Files" })
bind(mod .. " + C", hl.dsp.exec_cmd(calculator), { description = "Calculator" }) bind(mod .. " + C", hl.dsp.exec_cmd(calculator), { description = "Calculator" })
bind(mod .. " + E", hl.dsp.exec_cmd(mail), { description = "Mail" }) bind(mod .. " + E", hl.dsp.exec_cmd(mail), { description = "Mail" })
bind(mod .. " + I", hl.dsp.exec_cmd(settings), { description = "Panama Settings" }) bind(mod .. " + I", hl.dsp.exec_cmd(settings), { description = "Settings" })
bind("CTRL + SHIFT + Escape", hl.dsp.exec_cmd(sysmonitor), { description = "System monitor" }) bind("CTRL + SHIFT + Escape", hl.dsp.exec_cmd(sysmonitor), { description = "System monitor" })
-- ── Launcher ──────────────────────────────────────────────────────────────── -- ── Launcher ────────────────────────────────────────────────────────────────
@@ -6,7 +6,7 @@ import qs.services
SettingsPage { SettingsPage {
id: root id: root
title: "About Panama" title: "About"
lede: "A curated Hyprland desktop built around focus, speed, and good taste." lede: "A curated Hyprland desktop built around focus, speed, and good taste."
Component.onCompleted: { Component.onCompleted: {
@@ -17,7 +17,7 @@ SettingsPage {
} }
SettingsCard { SettingsCard {
title: "Panama Desktop" title: "Desktop"
subtitle: "Tokyo Night Moon · Prism glass · native tiling" subtitle: "Tokyo Night Moon · Prism glass · native tiling"
TextRow { TextRow {
@@ -41,15 +41,37 @@ SettingsPage {
} }
// What GNOME's About panel answers and this page did not: what am I running // What GNOME's About panel answers and this page did not: what am I running
// on. The rows come from MachineInfo, except graphics, which is joined from // on. Rows come from MachineInfo, except graphics, which is joined from
// GraphicsDevices rather than read a second time -- two readouts of the same // GraphicsDevices rather than read a second time -- two readouts of the same
// hardware are two things that can disagree. // hardware are two things that can disagree.
//
// The join splices the GPU rows in directly after Processor rather than
// appending them, so the card reads the way fastfetch does: what the system
// is, then what is installed on it, then the hardware underneath. A GPU
// listed after "Disk" reads as an afterthought.
readonly property var machineRows: {
const rows = (MachineInfo.facts ?? []).slice();
const gpus = GraphicsDevices.devices ?? [];
if (gpus.length === 0)
return rows;
const graphics = gpus.map((device, index) => ({
label: gpus.length > 1 ? "Graphics " + (index + 1) : "Graphics",
value: device.name
}));
const after = rows.findIndex(row => row.label === "Processor");
if (after < 0)
return rows.concat(graphics);
return rows.slice(0, after + 1).concat(graphics, rows.slice(after + 1));
}
SettingsCard { SettingsCard {
title: "This machine" title: "This machine"
subtitle: "Hardware and system, as the kernel reports it." subtitle: "Hardware and system, as the kernel reports it."
Repeater { Repeater {
model: MachineInfo.facts model: root.machineRows
TextRow { TextRow {
id: machineRow id: machineRow
@@ -58,27 +80,12 @@ SettingsPage {
label: machineRow.modelData.label label: machineRow.modelData.label
value: machineRow.modelData.value value: machineRow.modelData.value
} divider: machineRow.index < root.machineRows.length - 1
}
Repeater {
model: GraphicsDevices.devices
TextRow {
id: gpuRow
required property var modelData
required property int index
label: GraphicsDevices.devices.length > 1
? "Graphics " + (gpuRow.index + 1)
: "Graphics"
value: gpuRow.modelData.name
divider: gpuRow.index < GraphicsDevices.devices.length - 1
} }
} }
TextRow { TextRow {
visible: MachineInfo.scanned && MachineInfo.facts.length === 0 visible: MachineInfo.scanned && root.machineRows.length === 0
label: "Hardware" label: "Hardware"
detail: "The system did not report anything readable" detail: "The system did not report anything readable"
value: "Unavailable" value: "Unavailable"
@@ -25,14 +25,14 @@ SettingsPage {
SettingsCard { SettingsCard {
title: "Text" title: "Text"
subtitle: "Scales text in applications. Panama's own panels are drawn at their design size, so the shell is unaffected." subtitle: "Scales text in applications. The shell's own panels are drawn at their design size, so they are unaffected."
SliderRow { setting: "textScale"; divider: false } SliderRow { setting: "textScale"; divider: false }
} }
SettingsCard { SettingsCard {
title: "Motion" title: "Motion"
subtitle: "Panama never animates while idle. This affects motion you asked for — windows opening, workspaces sliding, panels appearing." subtitle: "Nothing animates while idle. This affects motion you asked for — windows opening, workspaces sliding, panels appearing."
ToggleRow { setting: "animationsEnabled"; divider: false } ToggleRow { setting: "animationsEnabled"; divider: false }
} }
@@ -46,7 +46,7 @@ SettingsPage {
title: "Background" title: "Background"
subtitle: Wallpaper.lastError !== "" subtitle: Wallpaper.lastError !== ""
? Wallpaper.lastError ? Wallpaper.lastError
: "Applied to every display. Panama looks in ~/Pictures/Wallpapers, ~/Pictures/Backgrounds, ~/.local/share/backgrounds, and /usr/share/backgrounds." : "Applied to every display. Looked for in ~/Pictures/Wallpapers, ~/Pictures/Backgrounds, ~/.local/share/backgrounds, and /usr/share/backgrounds."
WallpaperPicker { WallpaperPicker {
id: wallpapers id: wallpapers
@@ -184,7 +184,7 @@ SettingsPage {
SettingsCard { SettingsCard {
title: "Theme" title: "Theme"
subtitle: "Panama has one curated visual identity rather than a matrix of partially compatible themes. The controls above adjust its parameters — how much space, how soft, how much motion — without replacing it." subtitle: "This desktop has one curated visual identity rather than a matrix of partially compatible themes. The controls above adjust its parameters — how much space, how soft, how much motion — without replacing it."
TextRow { label: "Color palette"; detail: "Tokyo Night Moon"; value: "Prism" } TextRow { label: "Color palette"; detail: "Tokyo Night Moon"; value: "Prism" }
TextRow { label: "Interface type"; detail: "Adwaita Sans"; value: "System"; divider: false } TextRow { label: "Interface type"; detail: "Adwaita Sans"; value: "System"; divider: false }
@@ -209,7 +209,7 @@ SettingsPage {
SettingsCard { SettingsCard {
title: "Compositor autostart" title: "Compositor autostart"
subtitle: "Panama starts these from Hyprland configuration. They are read-only here." subtitle: "These are started from the Hyprland configuration. They are read-only here."
TextRow { TextRow {
visible: !DefaultApps.busy && DefaultApps.luaAutostartEntries.length === 0 visible: !DefaultApps.busy && DefaultApps.luaAutostartEntries.length === 0
@@ -47,7 +47,7 @@ SettingsPage {
SettingsCard { SettingsCard {
title: "Window layout" title: "Window layout"
subtitle: "Panama follows the Forge mental model with native Hyprland tiling." subtitle: "Follows the Forge mental model, with native Hyprland tiling."
// These were two read-only rows reporting "Tiling" and "Dynamic", which // These were two read-only rows reporting "Tiling" and "Dynamic", which
// described settings rather than facts -- both are ordinary Hyprland // described settings rather than facts -- both are ordinary Hyprland
@@ -121,10 +121,10 @@ SettingsPage {
SettingsCard { SettingsCard {
title: "Reset" title: "Reset"
subtitle: "Restores Panama's appearance, dock, clock, focus, and display policy, and clears your Home accessory arrangement. Pinned applications, files, and paired devices are not changed." subtitle: "Restores the appearance, dock, clock, focus, and display policy, and clears your Home accessory arrangement. Pinned applications, files, and paired devices are not changed."
ActionRow { ActionRow {
label: "Restore Panama defaults" label: "Restore defaults"
detail: "Applies immediately, including to the compositor" detail: "Applies immediately, including to the compositor"
action: "Restore defaults" action: "Restore defaults"
divider: false divider: false
@@ -89,9 +89,12 @@ Rectangle {
} }
} }
// The real bar carries a clock here, not a name. Standing in with the
// actual time keeps the preview a picture of this desktop rather than
// a picture of a product.
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent
text: "Panama" text: Qt.formatTime(new Date(), "h:mm")
color: Theme.alpha(Theme.fg, 0.45) color: Theme.alpha(Theme.fg, 0.45)
font.family: Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: 9 font.pixelSize: 9
@@ -149,7 +149,7 @@ SettingsPage {
ActionRow { ActionRow {
visible: Displays.isOverridden(root.monitor ? root.monitor.name : "") visible: Displays.isOverridden(root.monitor ? root.monitor.name : "")
label: "Using a custom display setting" label: "Using a custom display setting"
detail: "Forget it to go back to the resolution and scale Panama ships" detail: "Forget it to go back to the shipped resolution and scale"
action: "Forget" action: "Forget"
divider: false divider: false
onTriggered: Displays.forget(root.monitor.name) onTriggered: Displays.forget(root.monitor.name)
@@ -248,7 +248,7 @@ SettingsPage {
SettingsCard { SettingsCard {
title: "Gaming display policy" title: "Gaming display policy"
subtitle: "Applied immediately and restored when Panama starts." subtitle: "Applied immediately and restored when the session starts."
ToggleRow { setting: "autoHdr" } ToggleRow { setting: "autoHdr" }
ChoiceRow { setting: "vrrPolicy" } ChoiceRow { setting: "vrrPolicy" }
@@ -9,7 +9,7 @@ SettingsPage {
readonly property string greeting: openedHour < 12 ? "Good morning" : (openedHour < 18 ? "Good afternoon" : "Good evening") readonly property string greeting: openedHour < 12 ? "Good morning" : (openedHour < 18 ? "Good afternoon" : "Good evening")
title: `${root.greeting}, Gabriel` title: `${root.greeting}, Gabriel`
lede: "Your Panama desktop is configured and ready." lede: "Your desktop is configured and ready."
SettingsCard { SettingsCard {
title: SystemSettings.monitorDescription || "Active display" title: SystemSettings.monitorDescription || "Active display"
@@ -202,7 +202,7 @@ SettingsPage {
SettingRow { SettingRow {
label: "Private configuration" label: "Private configuration"
detail: "Saved with owner-only permissions in Panama's private environment file" detail: "Saved with owner-only permissions in a private environment file"
controlWidth: 216 controlWidth: 216
Row { Row {
@@ -239,7 +239,7 @@ SettingsPage {
SettingRow { SettingRow {
label: "Light catalog" label: "Light catalog"
detail: "Panama reads light state through the Home Assistant helper." detail: "Light state is read through the Home Assistant helper."
divider: false divider: false
controlWidth: 176 controlWidth: 176
@@ -24,7 +24,7 @@ SettingsPage {
TextRow { TextRow {
label: "Notification history" label: "Notification history"
detail: "Live notifications retained by Panama" detail: "Live notifications retained by the shell"
value: `${Notifs.history.length} items` value: `${Notifs.history.length} items`
} }
@@ -20,8 +20,8 @@ SettingsPage {
SettingsCard { SettingsCard {
title: "Idle behaviour" title: "Idle behaviour"
subtitle: IdleLock.managed subtitle: IdleLock.managed
? "Panama is managing hypridle. Changes take effect immediately." ? "Idle timings are managed here. Changes take effect immediately."
: "hypridle is running Panama's shipped configuration. Turn on management below to make these adjustable." : "hypridle is running its shipped configuration. Turn on management below to make these adjustable."
SliderRow { setting: "screenBlankMinutes"; zeroLabel: "Never" } SliderRow { setting: "screenBlankMinutes"; zeroLabel: "Never" }
SliderRow { setting: "lockMinutes"; zeroLabel: "Never" } SliderRow { setting: "lockMinutes"; zeroLabel: "Never" }
@@ -41,10 +41,10 @@ SettingsPage {
SettingsCard { SettingsCard {
title: "Management" title: "Management"
subtitle: "Panama generates hypridle's configuration into your state directory and points the service at it with a systemd drop-in. ~/.config/hypr is a symlink into the Panama repository, so the shipped configuration cannot be rewritten in place." subtitle: "hypridle's configuration is generated into your state directory and the service is pointed at it with a systemd drop-in. ~/.config/hypr is a symlink into the configuration repository, so the shipped file cannot be rewritten in place."
SettingRow { SettingRow {
label: "Let Panama manage idle timings" label: "Manage idle timings here"
detail: IdleLock.serviceState === "active" detail: IdleLock.serviceState === "active"
? "hypridle is running" ? "hypridle is running"
: "hypridle is " + IdleLock.serviceState : "hypridle is " + IdleLock.serviceState
@@ -90,7 +90,7 @@ SettingsPage {
SettingsCard { SettingsCard {
title: "Owned by Fedora" title: "Owned by Fedora"
subtitle: "File history and trash retention are GNOME preferences, applied by a housekeeping service that does not run in a Hyprland session. Panama does not offer them as switches, because storing that preference here would change nothing." subtitle: "File history and trash retention are GNOME preferences, applied by a housekeeping service that does not run in a Hyprland session. They are not offered as switches here, because storing that preference would change nothing."
ActionRow { ActionRow {
label: "File history & trash" label: "File history & trash"
@@ -1,4 +1,4 @@
# Panama Settings # Settings
The control centre for everything Panama owns. Anything the system owns — The control centre for everything Panama owns. Anything the system owns —
hardware, accounts, printers — is delegated to GNOME Settings and labelled as hardware, accounts, printers — is delegated to GNOME Settings and labelled as
@@ -55,11 +55,11 @@ SettingsPage {
SettingsCard { SettingsCard {
title: "Formats" title: "Formats"
subtitle: "Dates, times, and numbers follow the language above. Panama's own clock formatting is on the Appearance page." subtitle: "Dates, times, and numbers follow the language above. The desktop's own clock formatting is on the Appearance page."
ActionRow { ActionRow {
label: "Clock and date display" label: "Clock and date display"
detail: "How Panama itself shows the time" detail: "How the desktop itself shows the time"
action: "Open appearance" action: "Open appearance"
onTriggered: ShellState.openSettings("appearance") onTriggered: ShellState.openSettings("appearance")
} }
@@ -18,7 +18,7 @@ SettingsPage {
SettingsCard { SettingsCard {
title: "Read anything on screen" title: "Read anything on screen"
subtitle: "Select a region, window, or display. Panama recognizes it locally and gives you clean follow-up actions." subtitle: "Select a region, window, or display. It is recognized locally, with clean follow-up actions."
SettingRow { SettingRow {
icon: "󰗊" icon: "󰗊"
@@ -52,7 +52,7 @@ SettingsPage {
SettingsCard { SettingsCard {
title: "Local recognition" title: "Local recognition"
subtitle: "The screen image stays in Panama's cache and is deleted when you dismiss the result." subtitle: "The screen image stays in a local cache and is deleted when you dismiss the result."
TextRow { TextRow {
label: "Text recognition" label: "Text recognition"
@@ -120,7 +120,7 @@ SettingsPage {
SettingsCard { SettingsCard {
title: "Fedora system settings" title: "Fedora system settings"
subtitle: "Panels Panama does not own, because they configure system services rather than the desktop. Each row opens the panel that actually owns it. Printers and online accounts live with the rest of the network hardware, on Network & Devices." subtitle: "Panels this app does not own, because they configure system services rather than the desktop. Each row opens the panel that actually owns it. Printers and online accounts live with the rest of the network hardware, on Network & Devices."
// This was one row listing five subjects and opening the network panel // This was one row listing five subjects and opening the network panel
// regardless. Naming a panel and then not opening it is worse than not // regardless. Naming a panel and then not opening it is worse than not
@@ -40,7 +40,7 @@ Rectangle {
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: 18 anchors.leftMargin: 18
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "Panama Settings" text: "Settings"
color: Theme.fg color: Theme.fg
font.family: Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize font.pixelSize: Theme.fontSize
@@ -40,7 +40,7 @@ Rectangle {
{ page: "datetime", label: "Date & Time", icon: "\u{F0954}" }, { page: "datetime", label: "Date & Time", icon: "\u{F0954}" },
{ page: "applications", label: "Applications", icon: "\u{F003B}" }, { page: "applications", label: "Applications", icon: "\u{F003B}" },
{ page: "services", label: "Startup & Services", icon: "\u{F0493}" }, { page: "services", label: "Startup & Services", icon: "\u{F0493}" },
{ page: "about", label: "About Panama", icon: "\u{F02FD}" } { page: "about", label: "About", icon: "\u{F02FD}" }
] ]
width: 272 width: 272
@@ -59,15 +59,6 @@ Rectangle {
height: implicitHeight height: implicitHeight
spacing: 12 spacing: 12
Text {
text: "PANAMA"
color: Theme.fg
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.DemiBold
font.letterSpacing: 2.2
}
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 36 height: 36
@@ -317,7 +308,7 @@ Rectangle {
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: 36 anchors.leftMargin: 36
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: "Panama desktop is healthy" text: "Desktop is healthy"
color: Theme.fgDim color: Theme.fgDim
font.family: Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
@@ -8,7 +8,7 @@ FloatingWindow {
readonly property var homePhoneDiagnostics: settingsShell.homePhoneDiagnostics readonly property var homePhoneDiagnostics: settingsShell.homePhoneDiagnostics
title: "Panama Settings" title: "Settings"
visible: ShellState.settingsOpen visible: ShellState.settingsOpen
implicitWidth: 1120 implicitWidth: 1120
implicitHeight: 760 implicitHeight: 760
@@ -150,7 +150,7 @@ SettingsPage {
SettingsCard { SettingsCard {
visible: Object.keys(Keybinds.overrides).length > 0 visible: Object.keys(Keybinds.overrides).length > 0
title: "Changed shortcuts" title: "Changed shortcuts"
subtitle: "Rebinding stores only the new chord; what a shortcut does always comes from Panama's configuration." subtitle: "Rebinding stores only the new chord; what a shortcut does always comes from the desktop's configuration."
ActionRow { ActionRow {
label: "Restore every shipped shortcut" label: "Restore every shipped shortcut"
@@ -156,7 +156,7 @@ Item {
width: parent.width - 40 width: parent.width - 40
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: "No images found. Panama looks in ~/Pictures/Wallpapers, ~/Pictures/Backgrounds, ~/.local/share/backgrounds, and /usr/share/backgrounds." text: "No images found. Looked in ~/Pictures/Wallpapers, ~/Pictures/Backgrounds, ~/.local/share/backgrounds, and /usr/share/backgrounds."
color: Theme.fgMuted color: Theme.fgMuted
font.family: Theme.fontFamily font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
@@ -1,11 +1,11 @@
[Desktop Entry] [Desktop Entry]
Type=Application Type=Application
Name=Panama Settings Name=Settings
GenericName=System Settings GenericName=System Settings
Comment=Configure the Panama Hyprland desktop Comment=Configure this desktop
Exec=qs ipc call settings open Exec=qs ipc call settings open
Icon=panama-settings Icon=panama-settings
Terminal=false Terminal=false
StartupNotify=false StartupNotify=false
Categories=Settings; Categories=Settings;
Keywords=Panama;Hyprland;Display;Dock;Notifications;Shortcuts;Services; Keywords=Settings;Preferences;Configuration;Display;Sound;Network;Keyboard;Mouse;Privacy;Power;Shortcuts;
@@ -288,18 +288,18 @@ shell_pid="$(qs_for_test list | awk '/Process ID:/ { print $3; exit }')"
[[ "$shell_pid" =~ ^[0-9]+$ ]] || fail 'could not identify the branch shell process' [[ "$shell_pid" =~ ^[0-9]+$ ]] || fail 'could not identify the branch shell process'
for _ in $(seq 1 40); do for _ in $(seq 1 40); do
if /usr/sbin/hyprctl -j clients | jq -e --argjson pid "$shell_pid" \ if /usr/sbin/hyprctl -j clients | jq -e --argjson pid "$shell_pid" \
'[.[] | select(.pid == $pid and .title == "Panama Settings" and .floating == false)] | length == 1' >/dev/null; then '[.[] | select(.pid == $pid and .title == "Settings" and .floating == false)] | length == 1' >/dev/null; then
break break
fi fi
sleep 0.1 sleep 0.1
done done
/usr/sbin/hyprctl -j clients | jq -e --argjson pid "$shell_pid" \ /usr/sbin/hyprctl -j clients | jq -e --argjson pid "$shell_pid" \
'[.[] | select(.pid == $pid and .title == "Panama Settings" and .floating == false)] | length == 1' >/dev/null \ '[.[] | select(.pid == $pid and .title == "Settings" and .floating == false)] | length == 1' >/dev/null \
|| fail 'the branch shell did not own exactly one tiled Panama Settings client' || fail 'the branch shell did not own exactly one tiled Panama Settings client'
if [[ -n "${PANAMA_TEST_SCREENSHOT_PATH:-}" ]]; then if [[ -n "${PANAMA_TEST_SCREENSHOT_PATH:-}" ]]; then
geometry="$(/usr/sbin/hyprctl -j clients | jq -r --argjson pid "$shell_pid" \ geometry="$(/usr/sbin/hyprctl -j clients | jq -r --argjson pid "$shell_pid" \
'.[] | select(.pid == $pid and .title == "Panama Settings") | "\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"')" '.[] | select(.pid == $pid and .title == "Settings") | "\(.at[0]),\(.at[1]) \(.size[0])x\(.size[1])"')"
[[ -n "$geometry" ]] || fail 'could not resolve the Settings client geometry' [[ -n "$geometry" ]] || fail 'could not resolve the Settings client geometry'
grim -g "$geometry" "$PANAMA_TEST_SCREENSHOT_PATH" grim -g "$geometry" "$PANAMA_TEST_SCREENSHOT_PATH"
fi fi
+2 -2
View File
@@ -195,14 +195,14 @@ for page in "${pages[@]}"; do
done done
[[ "$(qs_for_test ipc call settings status | jq -r .page)" == "$page" ]] || fail "$page did not route" [[ "$(qs_for_test ipc call settings status | jq -r .page)" == "$page" ]] || fail "$page did not route"
/usr/sbin/hyprctl -j clients | jq -e --argjson pid "$shell_pid" \ /usr/sbin/hyprctl -j clients | jq -e --argjson pid "$shell_pid" \
'[.[] | select(.pid == $pid and .title == "Panama Settings" and .floating == false)] | length == 1' >/dev/null \ '[.[] | select(.pid == $pid and .title == "Settings" and .floating == false)] | length == 1' >/dev/null \
|| fail "$page created a missing, floating, or duplicate Settings window" || fail "$page created a missing, floating, or duplicate Settings window"
done done
qs_for_test ipc call settings page '__unsupported__' >/dev/null qs_for_test ipc call settings page '__unsupported__' >/dev/null
[[ "$(qs_for_test ipc call settings status | jq -r .page)" == "home" ]] || fail 'unsupported page did not fall back to Home' [[ "$(qs_for_test ipc call settings status | jq -r .page)" == "home" ]] || fail 'unsupported page did not fall back to Home'
/usr/sbin/hyprctl -j binds | jq -e '.[] | select(.description == "Panama Settings" and .key == "I" and .modmask == 64)' >/dev/null \ /usr/sbin/hyprctl -j binds | jq -e '.[] | select(.description == "Settings" and .key == "I" and .modmask == 64)' >/dev/null \
|| fail 'Super+I is not registered as Panama Settings' || fail 'Super+I is not registered as Panama Settings'
/usr/sbin/hyprctl -j binds | jq -e '.[] | select(.description == "Screen Intelligence" and .key == "S" and .modmask == 65)' >/dev/null \ /usr/sbin/hyprctl -j binds | jq -e '.[] | select(.description == "Screen Intelligence" and .key == "S" and .modmask == 65)' >/dev/null \
|| fail 'Super+Shift+S is not registered as Screen Intelligence' || fail 'Super+Shift+S is not registered as Screen Intelligence'
+6 -6
View File
@@ -16,14 +16,14 @@ qs ipc show | rg -q '^target settings$' || fail 'settings IPC target is missing'
qs ipc call settings open >/dev/null qs ipc call settings open >/dev/null
for _ in $(seq 1 40); do for _ in $(seq 1 40); do
if hyprctl -j clients | jq -e '[.[] | select(.title == "Panama Settings")] | length == 1' >/dev/null; then if hyprctl -j clients | jq -e '[.[] | select(.title == "Settings")] | length == 1' >/dev/null; then
break break
fi fi
sleep 0.1 sleep 0.1
done done
hyprctl -j clients | jq -e '[.[] | select(.title == "Panama Settings")] | length == 1' >/dev/null \ hyprctl -j clients | jq -e '[.[] | select(.title == "Settings")] | length == 1' >/dev/null \
|| fail 'exactly one Settings window did not map' || fail 'exactly one Settings window did not map'
hyprctl -j clients | jq -e '.[] | select(.title == "Panama Settings" and .floating == false)' >/dev/null \ hyprctl -j clients | jq -e '.[] | select(.title == "Settings" and .floating == false)' >/dev/null \
|| fail 'Settings window is not tiled' || fail 'Settings window is not tiled'
qs ipc call settings page displays >/dev/null qs ipc call settings page displays >/dev/null
@@ -32,7 +32,7 @@ qs ipc call settings page displays >/dev/null
qs ipc call settings page desktop >/dev/null qs ipc call settings page desktop >/dev/null
[[ "$(qs ipc call settings status | jq -r .page)" == "desktop" ]] || fail 'Desktop page did not route' [[ "$(qs ipc call settings status | jq -r .page)" == "desktop" ]] || fail 'Desktop page did not route'
address="$(hyprctl -j clients | jq -r '.[] | select(.title == "Panama Settings") | .address')" address="$(hyprctl -j clients | jq -r '.[] | select(.title == "Settings") | .address')"
hyprctl dispatch "hl.dsp.window.close({ window = \"address:$address\" })" >/dev/null hyprctl dispatch "hl.dsp.window.close({ window = \"address:$address\" })" >/dev/null
for _ in $(seq 1 40); do for _ in $(seq 1 40); do
[[ "$(qs ipc call settings status | jq -r .open)" == "false" ]] && break [[ "$(qs ipc call settings status | jq -r .open)" == "false" ]] && break
@@ -42,13 +42,13 @@ done
qs ipc call settings open >/dev/null qs ipc call settings open >/dev/null
for _ in $(seq 1 40); do for _ in $(seq 1 40); do
hyprctl -j clients | jq -e '.[] | select(.title == "Panama Settings")' >/dev/null && break hyprctl -j clients | jq -e '.[] | select(.title == "Settings")' >/dev/null && break
sleep 0.1 sleep 0.1
done done
qs ipc call settings close >/dev/null qs ipc call settings close >/dev/null
for _ in $(seq 1 40); do for _ in $(seq 1 40); do
if ! hyprctl -j clients | jq -e '.[] | select(.title == "Panama Settings")' >/dev/null; then if ! hyprctl -j clients | jq -e '.[] | select(.title == "Settings")' >/dev/null; then
trap - EXIT trap - EXIT
printf 'settings window contract: PASS\n' printf 'settings window contract: PASS\n'
exit 0 exit 0