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:
@@ -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 |
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user