Build the Panama Hyprland desktop
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
pragma Singleton
|
||||
|
||||
// User choices that Panama Settings may change at runtime. This is deliberately
|
||||
// separate from Settings.qml: the latter remains the stable public surface used
|
||||
// by the shell, while this object owns durable mutation and shipped defaults.
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import QtQuick
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property alias use24Hour: values.use24Hour
|
||||
property alias showSeconds: values.showSeconds
|
||||
property alias showWeekday: values.showWeekday
|
||||
property alias showCpu: values.showCpu
|
||||
property alias showMemory: values.showMemory
|
||||
property alias showGpu: values.showGpu
|
||||
property alias dockAutohide: values.dockAutohide
|
||||
property alias dockRevealDelayMs: values.dockRevealDelayMs
|
||||
property alias dockHideDelayMs: values.dockHideDelayMs
|
||||
property alias focusDurationMinutes: values.focusDurationMinutes
|
||||
property alias autoHdr: values.autoHdr
|
||||
property alias vrrPolicy: values.vrrPolicy
|
||||
property alias directScanoutPolicy: values.directScanoutPolicy
|
||||
property alias nightLightEnabled: values.nightLightEnabled
|
||||
property alias nightLightAutomatic: values.nightLightAutomatic
|
||||
property alias nightLightTemperature: values.nightLightTemperature
|
||||
property alias lastPage: values.lastPage
|
||||
|
||||
FileView {
|
||||
id: preferencesFile
|
||||
|
||||
path: Quickshell.stateDir + "/panama-settings.json"
|
||||
blockLoading: true
|
||||
printErrors: false
|
||||
atomicWrites: true
|
||||
|
||||
JsonAdapter {
|
||||
id: values
|
||||
|
||||
property bool use24Hour: false
|
||||
property bool showSeconds: true
|
||||
property bool showWeekday: true
|
||||
property bool showCpu: true
|
||||
property bool showMemory: true
|
||||
property bool showGpu: true
|
||||
property bool dockAutohide: true
|
||||
property int dockRevealDelayMs: 0
|
||||
property int dockHideDelayMs: 250
|
||||
property int focusDurationMinutes: 45
|
||||
property bool autoHdr: true
|
||||
property int vrrPolicy: 3
|
||||
property int directScanoutPolicy: 2
|
||||
property bool nightLightEnabled: false
|
||||
property bool nightLightAutomatic: false
|
||||
property int nightLightTemperature: 3500
|
||||
property string lastPage: "home"
|
||||
}
|
||||
}
|
||||
|
||||
// Listen after the adapter has been constructed instead of writing from
|
||||
// FileView.onAdapterUpdated. The latter also fires for default-property
|
||||
// initialization, which can overwrite a valid file before it is loaded.
|
||||
Connections {
|
||||
target: values
|
||||
function onUse24HourChanged(): void { persistTimer.restart(); }
|
||||
function onShowSecondsChanged(): void { persistTimer.restart(); }
|
||||
function onShowWeekdayChanged(): void { persistTimer.restart(); }
|
||||
function onShowCpuChanged(): void { persistTimer.restart(); }
|
||||
function onShowMemoryChanged(): void { persistTimer.restart(); }
|
||||
function onShowGpuChanged(): void { persistTimer.restart(); }
|
||||
function onDockAutohideChanged(): void { persistTimer.restart(); }
|
||||
function onDockRevealDelayMsChanged(): void { persistTimer.restart(); }
|
||||
function onDockHideDelayMsChanged(): void { persistTimer.restart(); }
|
||||
function onFocusDurationMinutesChanged(): void { persistTimer.restart(); }
|
||||
function onAutoHdrChanged(): void { persistTimer.restart(); }
|
||||
function onVrrPolicyChanged(): void { persistTimer.restart(); }
|
||||
function onDirectScanoutPolicyChanged(): void { persistTimer.restart(); }
|
||||
function onNightLightEnabledChanged(): void { persistTimer.restart(); }
|
||||
function onNightLightAutomaticChanged(): void { persistTimer.restart(); }
|
||||
function onNightLightTemperatureChanged(): void { persistTimer.restart(); }
|
||||
function onLastPageChanged(): void { persistTimer.restart(); }
|
||||
}
|
||||
|
||||
// Singleton construction can happen after FileView's preload phase when a
|
||||
// test or a lazy page first references it. An explicit reload makes the
|
||||
// durable state authoritative in that case as well as in the main shell.
|
||||
Component.onCompleted: preferencesFile.reload()
|
||||
|
||||
// Coalesce a group of UI changes into one atomic write. Writing from the
|
||||
// adapter's change signal itself can race a second property assignment and
|
||||
// reload the older value before the batch has finished.
|
||||
Timer {
|
||||
id: persistTimer
|
||||
interval: 0
|
||||
onTriggered: preferencesFile.writeAdapter()
|
||||
}
|
||||
|
||||
function resetDesktopDefaults(): void {
|
||||
values.use24Hour = false;
|
||||
values.showSeconds = true;
|
||||
values.showWeekday = true;
|
||||
values.showCpu = true;
|
||||
values.showMemory = true;
|
||||
values.showGpu = true;
|
||||
values.dockAutohide = true;
|
||||
values.dockRevealDelayMs = 0;
|
||||
values.dockHideDelayMs = 250;
|
||||
values.focusDurationMinutes = 45;
|
||||
values.autoHdr = true;
|
||||
values.vrrPolicy = 3;
|
||||
values.directScanoutPolicy = 2;
|
||||
values.nightLightEnabled = false;
|
||||
values.nightLightAutomatic = false;
|
||||
values.nightLightTemperature = 3500;
|
||||
values.lastPage = "home";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
pragma Singleton
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// User-facing knobs. Everything here is something you might reasonably want to
|
||||
// change without understanding the rest of the shell.
|
||||
//
|
||||
// Theme.qml holds *how it looks*; this holds *what it does*.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
// ── Clock ───────────────────────────────────────────────────────────────
|
||||
// Carried over from GNOME: 12-hour, weekday + date shown, seconds on.
|
||||
readonly property bool use24Hour: DesktopPreferences.use24Hour
|
||||
readonly property bool showSeconds: DesktopPreferences.showSeconds
|
||||
readonly property bool showWeekday: DesktopPreferences.showWeekday
|
||||
|
||||
// ── Weather ─────────────────────────────────────────────────────────────
|
||||
// Coordinates taken from the GNOME night-light setting, which had already
|
||||
// resolved the location. Uses Open-Meteo, which needs no API key.
|
||||
readonly property real latitude: 27.7375
|
||||
readonly property real longitude: -82.6861
|
||||
// Open-Meteo returns coordinates but no friendly place name. Keep the
|
||||
// label deliberately general rather than exposing precise coordinates in
|
||||
// the UI or guessing at a city from them.
|
||||
readonly property string weatherLocation: "Local weather"
|
||||
readonly property string temperatureUnit: "fahrenheit"
|
||||
readonly property int weatherRefreshMinutes: 20
|
||||
|
||||
// ── Vitals ──────────────────────────────────────────────────────────────
|
||||
// The GNOME Vitals extension showed processor usage, memory usage and GPU
|
||||
// usage, in that order. Same here.
|
||||
readonly property int vitalsIntervalMs: 2000
|
||||
readonly property bool showCpu: DesktopPreferences.showCpu
|
||||
readonly property bool showMemory: DesktopPreferences.showMemory
|
||||
readonly property bool showGpu: DesktopPreferences.showGpu
|
||||
|
||||
// amdgpu exposes utilisation here. Verified present on this machine; the
|
||||
// widget hides itself if the path is missing rather than showing zeros.
|
||||
readonly property string gpuBusyPath: "/sys/class/drm/card1/device/gpu_busy_percent"
|
||||
|
||||
// ── Night light ─────────────────────────────────────────────────────────
|
||||
// Matches the (disabled) GNOME schedule: 3500K from 17:00 to 10:00.
|
||||
readonly property int nightLightTemperature: DesktopPreferences.nightLightTemperature
|
||||
readonly property real nightLightFrom: 17.0
|
||||
readonly property real nightLightTo: 10.0
|
||||
readonly property bool nightLightEnabledByDefault: DesktopPreferences.nightLightEnabled
|
||||
|
||||
// ── Notifications ───────────────────────────────────────────────────────
|
||||
readonly property int notificationTimeoutMs: 5000
|
||||
readonly property int notificationTimeoutCriticalMs: 0 // 0 = never auto-expire
|
||||
readonly property int notificationHistoryLimit: 100
|
||||
readonly property int maxVisibleToasts: 4
|
||||
|
||||
// ── Focus ──────────────────────────────────────────────────────────────
|
||||
// One deliberate default rather than a preset picker: quick settings and
|
||||
// the keyboard shortcut should start a useful session in one action.
|
||||
readonly property int focusDurationMinutes: DesktopPreferences.focusDurationMinutes
|
||||
|
||||
// ── Dock ────────────────────────────────────────────────────────────────
|
||||
// Pinned apps, in order, taken from the GNOME dash favourites.
|
||||
readonly property list<string> dockPinned: [
|
||||
"org.gnome.Settings",
|
||||
"kitty",
|
||||
"org.gnome.Nautilus",
|
||||
"com.bitwarden.desktop",
|
||||
"org.gnome.Software",
|
||||
"helium",
|
||||
"org.mozilla.thunderbird_esr",
|
||||
"com.slack.Slack",
|
||||
"app.bluebubbles.BlueBubbles",
|
||||
"rustdesk",
|
||||
"io.podman_desktop.PodmanDesktop",
|
||||
"claude-desktop",
|
||||
"codex-desktop",
|
||||
"md.obsidian.Obsidian",
|
||||
"com.obsproject.Studio",
|
||||
"steam"
|
||||
]
|
||||
|
||||
// Dash-to-Dock was set to intellihide against all windows: the dock hides
|
||||
// when any window would overlap it, and comes back on hover.
|
||||
readonly property bool dockAutohide: DesktopPreferences.dockAutohide
|
||||
|
||||
// 0: reveal the instant the pointer reaches the bottom edge. A reveal delay
|
||||
// is indistinguishable from lag, because the user has already committed to
|
||||
// the gesture by the time the strip is hit.
|
||||
readonly property int dockRevealDelayMs: DesktopPreferences.dockRevealDelayMs
|
||||
|
||||
// Hiding keeps a delay, so brushing past the bottom edge or crossing the
|
||||
// gap between two icons doesn't make the dock flicker.
|
||||
readonly property int dockHideDelayMs: DesktopPreferences.dockHideDelayMs
|
||||
|
||||
// ── Capture ─────────────────────────────────────────────────────────────
|
||||
readonly property string screenshotDir: "Pictures/Screenshots"
|
||||
readonly property string recordingDir: "Videos/Recordings"
|
||||
// Passed to wf-recorder. Uses VAAPI on the AMD card so recording does not
|
||||
// cost CPU while gaming.
|
||||
readonly property string recorderArgs: "-c h264_vaapi -d /dev/dri/renderD128"
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
pragma Singleton
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Tokyo Night Moon — the single source of truth for every colour, radius,
|
||||
// duration and font in the shell. Nothing below this file should hardcode a
|
||||
// colour; if you find yourself writing "#" outside this file, add a token here.
|
||||
//
|
||||
// The bar keeps GNOME's 36px information density but sits directly on the
|
||||
// desktop, edge to edge. The dock retains the former glass vocabulary: bottom,
|
||||
// 48px icons and dot indicators.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
import Quickshell
|
||||
// QtQuick is required even though nothing visual is declared here: `color` is a
|
||||
// QtQuick value type, and Qt.rgba() lives in its JS namespace.
|
||||
import QtQuick
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
// ── Palette ─────────────────────────────────────────────────────────────
|
||||
// Canonical Tokyo Night Moon. `accent` matches the GNOME accent exactly.
|
||||
readonly property color bg: "#222436"
|
||||
readonly property color bgDark: "#1e2030"
|
||||
readonly property color bgHighlight: "#2f334d"
|
||||
readonly property color bgPanel: "#2e2f3d" // dock glass surface
|
||||
readonly property color bgPopover: "#21212f" // Openbar submenu background
|
||||
|
||||
readonly property color fg: "#c8d3f5"
|
||||
readonly property color fgDim: "#828bb8"
|
||||
readonly property color fgMuted: "#636da6"
|
||||
readonly property color gutter: "#3b4261"
|
||||
|
||||
// The pair. `accent` is the primary and carries every state meaning
|
||||
// (focused, active, on). `accentSecondary` is the orchid from the tmux
|
||||
// theme — it never appears alone, only as the far end of a gradient. That
|
||||
// restraint is the whole point: the two colours meeting is the signature,
|
||||
// so the pink stops being special the moment it's used as a flat fill.
|
||||
readonly property color accent: "#82aaff" // blue
|
||||
readonly property color accentSecondary: "#b172b0" // orchid, from tmux
|
||||
readonly property color accentAlt: "#65bcff" // blue1, a lighter blue
|
||||
readonly property color cyan: "#86e1fc"
|
||||
readonly property color teal: "#4fd6be"
|
||||
readonly property color green: "#c3e88d"
|
||||
readonly property color yellow: "#ffc777"
|
||||
readonly property color orange: "#ff966c"
|
||||
readonly property color red: "#ff757f"
|
||||
readonly property color redDeep: "#c53b53"
|
||||
readonly property color magenta: "#c099ff"
|
||||
readonly property color pink: "#fca7ea"
|
||||
|
||||
// Semantic aliases — prefer these in widgets so intent survives a repaint.
|
||||
readonly property color ok: green
|
||||
readonly property color warn: yellow
|
||||
readonly property color danger: red
|
||||
readonly property color urgent: orange
|
||||
|
||||
// ── Surface alphas ──────────────────────────────────────────────────────
|
||||
// The dock sits on compositor blur, so its fill is deliberately very
|
||||
// translucent. Popovers are near-opaque because they carry text that must
|
||||
// stay legible. The bar itself has no surface or alpha token.
|
||||
readonly property real dockAlpha: 0.34
|
||||
readonly property real popoverAlpha: 0.92
|
||||
readonly property real overlayAlpha: 0.55
|
||||
readonly property real hoverAlpha: 0.14
|
||||
readonly property real activeAlpha: 0.24
|
||||
|
||||
// ── Geometry ────────────────────────────────────────────────────────────
|
||||
readonly property int barHeight: 36
|
||||
readonly property int barGap: 6 // breathing room below the bar for popovers
|
||||
readonly property int barSideMargin: 10 // inset for floating popovers
|
||||
|
||||
readonly property int dockIconSize: 48
|
||||
readonly property int dockPadding: 8
|
||||
readonly property int dockGap: 8
|
||||
readonly property int dockRadius: 20
|
||||
|
||||
readonly property int popoverRadius: 18
|
||||
readonly property int popoverPadding: 14
|
||||
readonly property int popoverWidth: 380
|
||||
|
||||
readonly property int cardRadius: 12
|
||||
readonly property int pillRadius: 999
|
||||
readonly property int itemSpacing: 8
|
||||
readonly property int sectionSpacing: 14
|
||||
|
||||
// ── Type ────────────────────────────────────────────────────────────────
|
||||
// Adwaita Sans for everything the user reads as text. No exceptions: a
|
||||
// monospaced clock or percentage reads as a terminal readout pasted into a
|
||||
// UI, which is the opposite of the intent here.
|
||||
readonly property string fontFamily: "Adwaita Sans"
|
||||
|
||||
// Nerd Font, used ONLY to draw icon glyphs — never for text. It is the
|
||||
// pragmatic alternative to freedesktop symbolic icons, which ship with a
|
||||
// hardcoded dark fill Qt will not recolour (see widgets/ThemedIcon.qml).
|
||||
readonly property string fontMono: "VictorMono Nerd Font"
|
||||
|
||||
// Apply to any text whose digits change in place — clocks, percentages,
|
||||
// elapsed timers, dimension readouts. Tabular figures all share one
|
||||
// advance width, so the text stops twitching as the numbers tick without
|
||||
// needing a monospaced face.
|
||||
//
|
||||
// font.family: Theme.fontFamily
|
||||
// font.features: Theme.tabularFigures
|
||||
readonly property var tabularFigures: ({
|
||||
"tnum": 1
|
||||
})
|
||||
readonly property int fontSize: 13
|
||||
readonly property int fontSizeSmall: 11
|
||||
readonly property int fontSizeLarge: 16
|
||||
readonly property int fontSizeTitle: 20
|
||||
|
||||
// ── Motion ──────────────────────────────────────────────────────────────
|
||||
// Event-driven only. Nothing in this shell animates while idle — no pulse,
|
||||
// no shimmer, no spinners. These durations are used for open/close/hover.
|
||||
readonly property int durFast: 120
|
||||
readonly property int durNormal: 200
|
||||
readonly property int durSlow: 320
|
||||
|
||||
// The dock revealing is the one animation that answers a live pointer
|
||||
// movement, so it gets its own (much shorter) duration. Anything slower
|
||||
// reads as the desktop lagging behind the cursor rather than as motion.
|
||||
readonly property int durDockReveal: 90
|
||||
|
||||
// Matches the "snappy" spring curve defined in hypr/looks.lua.
|
||||
readonly property list<real> easeStandard: [0.05, 0.9, 0.1, 1.0]
|
||||
readonly property list<real> easeOvershoot: [0.34, 1.56, 0.64, 1.0]
|
||||
|
||||
// ── Helpers ─────────────────────────────────────────────────────────────
|
||||
// Qt.alpha() does not exist; this is the idiomatic way to re-alpha a token.
|
||||
function alpha(c: color, a: real): color {
|
||||
return Qt.rgba(c.r, c.g, c.b, a);
|
||||
}
|
||||
|
||||
// Blend two tokens — used for hover/pressed states so we never invent a
|
||||
// colour that isn't derived from the palette.
|
||||
function mix(a: color, b: color, ratio: real): color {
|
||||
return Qt.rgba(a.r + (b.r - a.r) * ratio, a.g + (b.g - a.g) * ratio, a.b + (b.b - a.b) * ratio, a.a + (b.a - a.a) * ratio);
|
||||
}
|
||||
|
||||
// ── The prism ───────────────────────────────────────────────────────────
|
||||
// Where the two accents meet. Used for the hairline along the top edge of
|
||||
// every glass surface (widgets/PrismEdge.qml), the focused window border,
|
||||
// the active workspace pill and slider fills.
|
||||
//
|
||||
// Where the gradient runs left-to-right the blue leads, because the eye
|
||||
// reads left first and blue is the colour that carries meaning.
|
||||
readonly property real prismStart: 0.22
|
||||
readonly property real prismEnd: 0.78
|
||||
|
||||
// Opacity of the hairline itself. Deliberately below 1: at full strength it
|
||||
// reads as a drawn line rather than as light catching an edge.
|
||||
readonly property real prismEdgeAlpha: 0.85
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
module qs.config
|
||||
singleton DesktopPreferences 1.0 DesktopPreferences.qml
|
||||
singleton Settings 1.0 Settings.qml
|
||||
singleton Theme 1.0 Theme.qml
|
||||
Reference in New Issue
Block a user