Continuing towards GNOME Settings parity. GNOME's Privacy panel covers screen lock, camera and microphone access, file history, trash, and device security; Panama had no equivalent page at all, despite already tracking camera and microphone use for the bar indicator. Device security is a new read-only readout: Secure Boot, TPM, disk encryption, SELinux mode, and the firewall. None of these is a preference -- they are set in firmware, at install time, or by system policy, and a switch offering to change them would either fail or do something far-reaching from a control that looks like every other control. What it answers is "is this machine set up the way I think it is", which otherwise takes five commands and root. Facts that cannot be determined report Unknown rather than guessing, because a security readout that quietly says "fine" when it failed to look is worse than no readout. File history and trash retention are deliberately NOT offered as switches. They are GNOME preferences enforced by gsd-housekeeping, which does not run in a Hyprland session -- verified, it is not running here. Toggling them would store a preference, change nothing, and give no sign of it. They are delegated to GNOME Settings by name instead. Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L
117 lines
4.6 KiB
QML
117 lines
4.6 KiB
QML
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 = "";
|
|
}
|
|
|
|
function openSettings(page: string): void {
|
|
const allowed = ["home", "appearance", "displays", "connectivity", "home-phone", "desktop", "sound", "notifications", "screen-intelligence", "shortcuts", "mouse", "privacy", "accessibility", "power", "datetime", "applications", "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
|
|
}
|