From 44124d72fa8d4545f97394d3d28431c8d3ea07bf Mon Sep 17 00:00:00 2001 From: Gabriel Brown Date: Sun, 23 Aug 2026 11:55:43 -0400 Subject: [PATCH] Take one machine's fingerprints off everyone's desktop The audit's second tier: values that were measurements of the author's desktop, shipped to every machine as if they were defaults. Settings greeted every human as Gabriel; it now greets whoever accountsservice says is signed in, and nobody when it says nothing. The weather shipped his home coordinates and confidently reported his forecast anywhere on earth; it now ships unset, fetches nothing until a location is chosen, and the location row says so. The GTK bookmarks carried seven /home/gib paths and his file server into every file dialog; they are now generated per machine from a template and gitignored -- Nautilus edits the instance freely, the way settings.ini already worked one file over. Web search routed through his personal bang redirector; the engine is now the webSearchUrl preference with a DuckDuckGo default, read by both the script command and the suggestions extension, which the launcher-search contract already pins to one another. The GPU vitals path defaulted to his card1 and lost the readout on any machine enumerated differently; a machine with exactly one GPU now adopts it. And the Containers and Snapshots pages hide once a scan proves their backing stack absent, instead of rendering permanently empty on machines that never had podman or snapper. Lesser residue swept in the same pass: the DP-2 hyprpaper block one machine needed, the author's username-typo expansions (moved to his personal seed in user/, where personal content belongs), a capture fallback into /home/gib, and a parity table asserting one machine's hardware as fact. Claude-Session: https://claude.ai/code/session_01Epx9ZC1gwm81K3jm9x9CKh --- .gitignore | 1 + config/dot/espanso/match/base.yml | 12 ---------- config/dot/gtk-3.0/bookmarks | 8 ------- config/dot/gtk-3.0/bookmarks.template | 6 +++++ config/dot/hypr/DESKTOP-PARITY.md | 2 +- config/dot/hypr/hyprpaper.conf | 12 ++++------ .../quickshell/config/PreferenceSchema.qml | 24 +++++++++++++++---- .../modules/settings/ApplicationsPage.qml | 2 ++ .../quickshell/modules/settings/HomePage.qml | 14 +++++++++-- .../modules/settings/SettingsSidebar.qml | 17 +++++++++++++ config/dot/quickshell/services/Capture.qml | 2 +- .../quickshell/services/GraphicsDevices.qml | 7 ++++++ .../quickshell/services/SettingsSearch.qml | 3 ++- config/dot/quickshell/services/Weather.qml | 8 +++++++ .../extensions/panama-search/src/search.tsx | 20 +++++++++++++++- config/local/share/vicinae/scripts/search-web | 7 ++++-- .../vicinae/scripts/settings-applications | 2 +- docs/settings.md | 10 +++++++- setup/scripts/link-dotfiles | 16 +++++++++++++ user/espanso/identity.yml | 8 +++++++ 20 files changed, 139 insertions(+), 42 deletions(-) delete mode 100644 config/dot/gtk-3.0/bookmarks create mode 100644 config/dot/gtk-3.0/bookmarks.template diff --git a/.gitignore b/.gitignore index 76395ae..d1204ff 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ __pycache__/ # Generated from the color scheme; machine state, not configuration. /config/dot/gtk-3.0/settings.ini +/config/dot/gtk-3.0/bookmarks /config/dot/gtk-4.0/settings.ini /config/dot/tmux/current-theme.conf /config/dot/hypr/hyprlock.conf diff --git a/config/dot/espanso/match/base.yml b/config/dot/espanso/match/base.yml index 6c4d2ba..c80e075 100644 --- a/config/dot/espanso/match/base.yml +++ b/config/dot/espanso/match/base.yml @@ -139,18 +139,6 @@ matches: - trigger: "dokcer" replace: "docker" - - trigger: "gborwn" - replace: "gbrown" - - - trigger: "gbrwon" - replace: "gbrown" - - - trigger: "gbronw" - replace: "gbrown" - - - trigger: "grbown" - replace: "gbrown" - - trigger: "restrat" replace: "restart" diff --git a/config/dot/gtk-3.0/bookmarks b/config/dot/gtk-3.0/bookmarks deleted file mode 100644 index f0644ed..0000000 --- a/config/dot/gtk-3.0/bookmarks +++ /dev/null @@ -1,8 +0,0 @@ -file:///home/gib/Documents Documents -file:///home/gib/Documents/Code Code -file:///home/gib/Downloads Downloads -file:///home/gib/Music Music -file:///home/gib/Pictures Pictures -file:///home/gib/Videos Videos -file:///home/gib/.local/share/Panama Panama -smb://server-gib.local/homes/ Gib's Server diff --git a/config/dot/gtk-3.0/bookmarks.template b/config/dot/gtk-3.0/bookmarks.template new file mode 100644 index 0000000..cf5c4e8 --- /dev/null +++ b/config/dot/gtk-3.0/bookmarks.template @@ -0,0 +1,6 @@ +file://$HOME/Documents Documents +file://$HOME/Downloads Downloads +file://$HOME/Music Music +file://$HOME/Pictures Pictures +file://$HOME/Videos Videos +file://$HOME/.local/share/Panama Panama diff --git a/config/dot/hypr/DESKTOP-PARITY.md b/config/dot/hypr/DESKTOP-PARITY.md index bbb02e5..4d9dea9 100644 --- a/config/dot/hypr/DESKTOP-PARITY.md +++ b/config/dot/hypr/DESKTOP-PARITY.md @@ -25,7 +25,7 @@ Last live audit: 2026-08-17, Fedora 44, Hyprland 0.56.2, Quickshell 0.3.0. | Calendar agenda | Existing GNOME, Google, iCloud, and Nextcloud sources through Evolution Data Server | Live | | Control Center | Wi-Fi, Bluetooth, audio input/output, Caffeine, Night Light, Focus, Home Assistant favorites, and KDE Connect phone continuity | Live | | Focus sessions | Persistent workspace-bound timer, DND/caffeine coordination, Signal Glass controls | Live | -| Brightness | Appears only when a backlight device exists | Live, not applicable on this monitor | +| Brightness | Appears only when a backlight device exists | Live where the hardware exposes it | | AppIndicator / tray | Native StatusNotifierItem host and themed menus | Live | | Screenshot and recording | Quickshell picker, grim/slurp/satty/wf-recorder | Live | | Screen text and code recognition | Local Tesseract/ZBar Read mode, selectable Prism result sheet | Live after package install | diff --git a/config/dot/hypr/hyprpaper.conf b/config/dot/hypr/hyprpaper.conf index cef63bf..4b6020d 100644 --- a/config/dot/hypr/hyprpaper.conf +++ b/config/dot/hypr/hyprpaper.conf @@ -17,20 +17,16 @@ # frame time for nothing. # ───────────────────────────────────────────────────────────────────────────── +# One block for every output: per-monitor wallpaper is applied at runtime by +# the shell (services/Wallpaper.qml) over IPC, so a per-connector block here +# would just be one machine's connector name in everyone's config. wallpaper { - monitor = DP-2 + monitor = path = ~/Pictures/Wallpapers/faroe_islands.jpg # cover = fill the output, cropping overflow. Matches the "zoom" picture # option this setup used under GNOME. fit_mode = cover } -# Fallback for any output without its own block above. -wallpaper { - monitor = - path = ~/Pictures/Wallpapers/faroe_islands.jpg - fit_mode = cover -} - ipc = on splash = false diff --git a/config/dot/quickshell/config/PreferenceSchema.qml b/config/dot/quickshell/config/PreferenceSchema.qml index 63108de..d218777 100644 --- a/config/dot/quickshell/config/PreferenceSchema.qml +++ b/config/dot/quickshell/config/PreferenceSchema.qml @@ -1297,28 +1297,44 @@ Singleton { detail: "Which GPU the graphics readout in the bar measures" }, + // ── Search ────────────────────────────────────────────────────────── + // The launcher's web search appends the query to this. It shipped + // pointing at the author's personal bang redirector once; a stranger's + // searches belong to no one's server but the engine they chose. + { + key: "webSearchUrl", type: "string", + def: "https://duckduckgo.com/?q=", group: "search", + pattern: "^https://[^\\s]{1,200}$", + label: "Web search engine", + detail: "Where the launcher's web search sends a query; the search text is appended" + }, + // ── Weather location ──────────────────────────────────────────────── // Coordinates rather than a place name, because that is what Open-Meteo // takes and it needs no API key. weatherLocation is only the label shown // in the UI; it is never sent anywhere, so it can say whatever makes the // reading recognizable. { - key: "weatherLatitude", type: "real", def: 27.7375, min: -90, max: 90, step: 0.0001, + key: "weatherLatitude", type: "real", def: 0, min: -90, max: 90, step: 0.0001, group: "weather", internal: true, label: "Latitude", detail: "Set by choosing a location" }, { - key: "weatherLongitude", type: "real", def: -82.6861, min: -180, max: 180, step: 0.0001, + key: "weatherLongitude", type: "real", def: 0, min: -180, max: 180, step: 0.0001, group: "weather", internal: true, label: "Longitude", detail: "Set by choosing a location" }, + // Empty until a location is chosen. The shipped value was once the + // author's home town, which confidently reported his weather on every + // machine anywhere; an unset location fetches nothing and says so + // instead. { - key: "weatherLocation", type: "string", def: "Local weather", group: "weather", + key: "weatherLocation", type: "string", def: "", group: "weather", internal: true, // Display only -- never sent to the weather service. - pattern: "^[^\\n]{1,64}$", + pattern: "^[^\\n]{0,64}$", label: "Weather location", detail: "The place the weather reading is for" }, diff --git a/config/dot/quickshell/modules/settings/ApplicationsPage.qml b/config/dot/quickshell/modules/settings/ApplicationsPage.qml index 61710a0..4864586 100644 --- a/config/dot/quickshell/modules/settings/ApplicationsPage.qml +++ b/config/dot/quickshell/modules/settings/ApplicationsPage.qml @@ -207,6 +207,8 @@ SettingsPage { title: "Search" subtitle: "Applications, files, the calculator, clipboard history, emoji, and open windows are all searched from the launcher." + TextEntryRow { setting: "webSearchUrl"; placeholder: "https://duckduckgo.com/?q=" } + TextRow { label: "Launcher" detail: SystemSettings.vicinaeActive diff --git a/config/dot/quickshell/modules/settings/HomePage.qml b/config/dot/quickshell/modules/settings/HomePage.qml index f768faf..cea0808 100644 --- a/config/dot/quickshell/modules/settings/HomePage.qml +++ b/config/dot/quickshell/modules/settings/HomePage.qml @@ -96,7 +96,17 @@ SettingsPage { return match[2] ? match[1] + " " + match[2].toUpperCase() : match[1]; } - title: `${root.greeting}, Gabriel` + // Greets whoever is signed in, from the same accountsservice record the + // lock screen shows. This once hardcoded the author's first name, which + // made the first screen of Settings wrong for every other human. + readonly property string greetingName: { + if (!UserAccounts.me) + return ""; + const full = UserAccounts.displayName(UserAccounts.me); + return full.split(" ")[0] || ""; + } + + title: root.greetingName !== "" ? `${root.greeting}, ${root.greetingName}` : root.greeting lede: Weather.available ? Math.round(Weather.temperature) + Weather.unitSuffix + " and " + Weather.description.toLowerCase() + " in " + Settings.weatherLocation @@ -275,7 +285,7 @@ SettingsPage { label: "Location" detail: "Only the search term is sent; the name is a label kept on this machine" - value: Settings.weatherLocation + value: Settings.weatherLocation !== "" ? Settings.weatherLocation : "Not set — choose one to see weather" LocationPicker { width: parent.width diff --git a/config/dot/quickshell/modules/settings/SettingsSidebar.qml b/config/dot/quickshell/modules/settings/SettingsSidebar.qml index a52e01f..ce5f214 100644 --- a/config/dot/quickshell/modules/settings/SettingsSidebar.qml +++ b/config/dot/quickshell/modules/settings/SettingsSidebar.qml @@ -55,6 +55,22 @@ Rectangle { { page: "about", label: "About", icon: "\u{F02FD}" } ] + // Pages whose entire backing stack can be absent hide once a scan has + // proven it absent: a Containers page with no podman and a Snapshots page + // with no snapper configuration render permanently empty, which reads as + // broken rather than inapplicable. Until the scan lands they stay + // visible, so machines that have the stack never see a blink -- and both + // scans fire when Settings opens (HomePage.onCompleted). + function pageAvailable(page: string): bool { + switch (page) { + case "containers": + return !Containers.scanned || Containers.available; + case "snapshots": + return !Snapshots.scanned || Snapshots.configs.length > 0; + } + return true; + } + width: 272 color: Theme.alpha(Theme.bgDark, 0.96) border.width: 0 @@ -236,6 +252,7 @@ Rectangle { Rectangle { id: navItem required property var modelData + visible: root.pageAvailable(modelData.page) width: parent.width height: 40 radius: 10 diff --git a/config/dot/quickshell/services/Capture.qml b/config/dot/quickshell/services/Capture.qml index d99e1e0..22ba190 100644 --- a/config/dot/quickshell/services/Capture.qml +++ b/config/dot/quickshell/services/Capture.qml @@ -76,7 +76,7 @@ Singleton { property real coordinateScale: 1.0 // ── Paths ─────────────────────────────────────────────────────────────── - readonly property string _home: Quickshell.env("HOME") || "/home/gib" + readonly property string _home: Quickshell.env("HOME") || "" // Both folders are settings now rather than a choice of three, so both can // name somewhere outside home -- a second drive, a network mount. Prefixing diff --git a/config/dot/quickshell/services/GraphicsDevices.qml b/config/dot/quickshell/services/GraphicsDevices.qml index 715a002..e9fb056 100644 --- a/config/dot/quickshell/services/GraphicsDevices.qml +++ b/config/dot/quickshell/services/GraphicsDevices.qml @@ -42,6 +42,13 @@ Singleton { const parsed = JSON.parse(this.text); root.devices = Array.isArray(parsed) ? parsed : []; root.lastError = ""; + // The shipped default is one machine's card index, and + // card numbering means nothing across machines. When the + // stored path is not present here and there is exactly + // one real answer, adopt it -- a single-GPU laptop should + // not lose its vitals readout to a desktop's enumeration. + if (root.selectionMissing && root.devices.length === 1) + root.select(root.devices[0].path); } catch (error) { root.devices = []; root.lastError = "The graphics devices could not be read."; diff --git a/config/dot/quickshell/services/SettingsSearch.qml b/config/dot/quickshell/services/SettingsSearch.qml index 2707e3c..1e19641 100644 --- a/config/dot/quickshell/services/SettingsSearch.qml +++ b/config/dot/quickshell/services/SettingsSearch.qml @@ -54,7 +54,8 @@ Singleton { "weather": "home", "notifications": "notifications", "capture": "screen-intelligence", - "gaming": "gaming" + "gaming": "gaming", + "search": "applications" }) // Settings that are real but have no schema entry, because the system owns diff --git a/config/dot/quickshell/services/Weather.qml b/config/dot/quickshell/services/Weather.qml index ce7a6e6..4c16bd9 100644 --- a/config/dot/quickshell/services/Weather.qml +++ b/config/dot/quickshell/services/Weather.qml @@ -59,7 +59,15 @@ Singleton { } } + // Nothing was chosen yet: fetch nothing, claim nothing. The card offers + // the location picker instead. + readonly property bool configured: Settings.weatherLocation !== "" + function refresh(): void { + if (!root.configured) { + root.available = false; + return; + } // Skip if the previous fetch is somehow still in flight. if (!fetch.running) fetch.running = true; diff --git a/config/local/share/vicinae/extensions/panama-search/src/search.tsx b/config/local/share/vicinae/extensions/panama-search/src/search.tsx index 23d894d..b3f32b0 100644 --- a/config/local/share/vicinae/extensions/panama-search/src/search.tsx +++ b/config/local/share/vicinae/extensions/panama-search/src/search.tsx @@ -6,7 +6,25 @@ import { Action, ActionPanel, Icon, List } from "@vicinae/api"; // search engine to be bounced, and falls through to an ordinary search when // there is no bang. Bang support is a property of this URL, not of this // extension, which is why there is no bang parsing below. -const ENGINE = "https://bang.gibbyb.com/?q="; +// The engine is Panama's webSearchUrl preference (Applications page), the +// same key the fallback script command reads -- launcher-search-contract pins +// the two to one default. Read once per command launch; DuckDuckGo when the +// preference is unset or unreadable. +const DEFAULT_ENGINE = "https://duckduckgo.com/?q="; +const ENGINE = (() => { + try { + const configHome = + process.env.XDG_CONFIG_HOME || `${process.env.HOME}/.config`; + const stored = JSON.parse( + require("fs").readFileSync(`${configHome}/panama/settings.json`, "utf8"), + ).webSearchUrl; + return typeof stored === "string" && stored.startsWith("https://") + ? stored + : DEFAULT_ENGINE; + } catch { + return DEFAULT_ENGINE; + } +})(); // The suggestion endpoint Firefox's address bar uses. Answers with // [query, [suggestion, ...], ...] and needs no key. diff --git a/config/local/share/vicinae/scripts/search-web b/config/local/share/vicinae/scripts/search-web index 6557eea..f003591 100755 --- a/config/local/share/vicinae/scripts/search-web +++ b/config/local/share/vicinae/scripts/search-web @@ -25,5 +25,8 @@ # # xdg-open rather than a named browser: the default browser is already a setting # this desktop owns, on the Applications page, and naming one here would quietly -# outrank it. -exec xdg-open "https://bang.gibbyb.com/?q=$1" +# outrank it. The engine is the webSearchUrl preference (Applications page); +# the shipped default asks DuckDuckGo, not somebody's personal redirector. +search_url="$(jq -r '.webSearchUrl // empty' "${XDG_CONFIG_HOME:-$HOME/.config}/panama/settings.json" 2>/dev/null)" +[ -n "$search_url" ] || search_url="https://duckduckgo.com/?q=" +exec xdg-open "${search_url}$1" diff --git a/config/local/share/vicinae/scripts/settings-applications b/config/local/share/vicinae/scripts/settings-applications index f752ef4..4498a0c 100755 --- a/config/local/share/vicinae/scripts/settings-applications +++ b/config/local/share/vicinae/scripts/settings-applications @@ -5,6 +5,6 @@ # @vicinae.mode silent # @vicinae.icon ../../icons/hicolor/scalable/apps/panama-settings.svg # @vicinae.description Open Applications in Settings. -# @vicinae.keywords ["settings", "default applications"] +# @vicinae.keywords ["settings", "web search engine", "default applications"] exec "$HOME/.config/quickshell/scripts/panama-action" settings-page applications diff --git a/docs/settings.md b/docs/settings.md index 92c214d..b5ddc3c 100644 --- a/docs/settings.md +++ b/docs/settings.md @@ -4,7 +4,7 @@ Do not edit this file. Run `quickshell/scripts/panama-settings-docs` after changing the schema; a contract fails when this copy is stale. -148 settings across 29 groups. 70 of them are applied to the compositor and confirmed by reading the value back. +149 settings across 30 groups. 70 of them are applied to the compositor and confirmed by reading the value back. ## accessibility @@ -255,6 +255,14 @@ Found on **Mouse & Touchpad**. | **Left-handed**
`leftHanded` `input:left_handed` | false | Swap the primary and secondary buttons | | **Middle-click paste**
`middleClickPaste` `misc:middle_click_paste` | true | Paste the primary selection in GTK and native Wayland applications | +## search + +Found on **Applications**. + +| Setting | Default | What it does | +|---|---|---| +| **Web search engine**
`webSearchUrl` | https://duckduckgo.com/?q= | Where the launcher's web search sends a query; the search text is appended | + ## themes Found on **Appearance**. diff --git a/setup/scripts/link-dotfiles b/setup/scripts/link-dotfiles index 926d98d..e16e97d 100755 --- a/setup/scripts/link-dotfiles +++ b/setup/scripts/link-dotfiles @@ -255,6 +255,22 @@ for icon_file in "$PANAMA_ICON_DIR"/*.svg; do done gtk-update-icon-cache -f -t "$HOME/.local/share/icons/hicolor" 2>/dev/null || true +# File-manager sidebar bookmarks, generated per machine from the template. +# The tracked file used to carry absolute /home/ paths -- seven dead +# sidebar entries in every file dialog for anyone else. Nautilus edits the +# generated instance in place (Ctrl+D writes this file through the symlink), +# which is exactly why it is gitignored: bookmarks are user data, not config. +BOOKMARKS_TEMPLATE="$PANAMA_DOT/gtk-3.0/bookmarks.template" +BOOKMARKS_FILE="$PANAMA_DOT/gtk-3.0/bookmarks" +if [ -r "$BOOKMARKS_TEMPLATE" ]; then + if [ -e "$BOOKMARKS_FILE" ]; then + log "Keeping existing GTK bookmarks at $BOOKMARKS_FILE" + else + sed "s|\$HOME|$HOME|g" "$BOOKMARKS_TEMPLATE" > "$BOOKMARKS_FILE" + log "Generated GTK bookmarks for $HOME" + fi +fi + # The pointer theme. oreo_blue_cursors is packaged by no Fedora repository -- it # is a GitHub project -- so rather than download it at install time and depend on # a URL that can rot, the theme is vendored into this repository and exposed the diff --git a/user/espanso/identity.yml b/user/espanso/identity.yml index 4ff1623..6700d22 100644 --- a/user/espanso/identity.yml +++ b/user/espanso/identity.yml @@ -9,3 +9,11 @@ matches: replace: "gib@gibbyb.com" - trigger: ":empro" replace: "me@gbrown.org" + - trigger: "gborwn" + replace: "gbrown" + - trigger: "gbrwon" + replace: "gbrown" + - trigger: "gbronw" + replace: "gbrown" + - trigger: "grbown" + replace: "gbrown"