pragma Singleton // ───────────────────────────────────────────────────────────────────────────── // Shared UI state. // // Every overlay in the shell is mutually exclusive with the others -- opening // the overview should close the quick settings, and so on. Centralising that // here means no module needs a reference to any other module, and the IPC // handlers in shell.qml have exactly one thing to talk to. // ───────────────────────────────────────────────────────────────────────────── import Quickshell import QtQuick import qs.config Singleton { id: root // Exactly one of these may be non-empty at a time. // "" | "overview" | "quicksettings" | "notifications" | "clipboard" | "capture" | "activity" | "powermenu" property string activeOverlay: "" readonly property bool overviewOpen: activeOverlay === "overview" readonly property bool quickSettingsOpen: activeOverlay === "quicksettings" readonly property bool notificationsOpen: activeOverlay === "notifications" readonly property bool clipboardOpen: activeOverlay === "clipboard" readonly property bool captureOpen: activeOverlay === "capture" readonly property bool activityOpen: activeOverlay === "activity" readonly property bool powerMenuOpen: activeOverlay === "powermenu" // Settings is a normal application window rather than a transient overlay. // It can stay open while Quick Settings or the notification center appears. property bool settingsOpen: false property string settingsPage: "home" readonly property bool anyOverlayOpen: activeOverlay !== "" // The date menu keeps calendar context fixed while its right pane switches // between the schedule, persistent activity and message history. property string dateMenuPage: "agenda" // 0 means "use the currently focused workspace". A positive value lets a // contextual surface, such as Focus, open Mission Control at its target. property int overviewWorkspaceId: 0 property string overviewQuery: "" function toggle(name: string): void { root.activeOverlay = (root.activeOverlay === name) ? "" : name; } function open(name: string): void { root.activeOverlay = name; } function openDateMenu(page: string): void { root.dateMenuPage = root.normalizedDateMenuPage(page); root.activeOverlay = "notifications"; } function toggleDateMenu(page: string): void { const target = root.normalizedDateMenuPage(page); if (root.activeOverlay === "notifications" && root.dateMenuPage === target) { root.activeOverlay = ""; return; } root.dateMenuPage = target; root.activeOverlay = "notifications"; } function normalizedDateMenuPage(page: string): string { return ["agenda", "ongoing", "notifications"].indexOf(page) >= 0 ? page : "agenda"; } function openOverview(workspaceId: int): void { root.overviewWorkspaceId = Math.max(0, workspaceId); root.overviewQuery = ""; root.activeOverlay = "overview"; } function searchOverview(query: string): void { root.overviewWorkspaceId = 0; root.overviewQuery = query; root.activeOverlay = "overview"; } function close(): void { if (root.activeOverlay === "overview") { root.overviewWorkspaceId = 0; root.overviewQuery = ""; } root.activeOverlay = ""; } // A section within the page, for pages that have tabs. Consumed once by the // page and cleared, rather than bound to -- a binding would pin the tab and // stop anyone changing it by hand once they arrived. property string settingsSection: "" function takeSettingsSection(): string { const section = root.settingsSection; root.settingsSection = ""; return section; } function openSettings(page: string): void { root.settingsSection = ""; root.showSettings(page); } // Opening straight to a tab within a page. A separate function rather than a // default argument: QML has no default parameter values, and writing one // fails the whole configuration -- which takes the shell down with it. function openSettingsSection(page: string, section: string): void { root.settingsSection = section; root.showSettings(page); } function showSettings(page: string): void { const allowed = ["home", "appearance", "displays", "connectivity", "home-phone", "desktop", "sound", "gaming", "notifications", "screen-intelligence", "shortcuts", "mouse", "privacy", "region", "accounts", "accessibility", "power", "datetime", "applications", "updates", "storage", "snapshots", "users", "sharing", "firewall", "printers", "containers", "ssh-keys", "services", "about"]; root.settingsPage = allowed.indexOf(page) >= 0 ? page : "home"; DesktopPreferences.set("lastPage", root.settingsPage); root.settingsOpen = true; } function toggleSettings(): void { if (root.settingsOpen) { root.closeSettings(); return; } root.openSettings(DesktopPreferences.get("lastPage") || "home"); } function closeSettings(): void { root.settingsOpen = false; } // Set by Dock.qml so the bar can avoid fighting it for pointer grabs, and // read by the capture overlay so the dock isn't in the screenshot. property bool dockRevealed: false }