Thirty settings pages is the opposite of the usual problem: a person arriving from GNOME, macOS or Windows cannot tell which few things matter. This is those few, once, on the first start. Not a tour. Nobody reads a tour, and a multi-step wizard on a desktop somebody just installed is one more thing between them and using it. One card, five keys, and a way out. The chords come from the live keymap rather than being written here, so a machine whose owner has already rebound something teaches what they actually have. A welcome screen is the one surface read by somebody with no way to tell it is wrong, which is exactly why it must not be. Two deliberate departures from how every other surface behaves. It does not close on a click outside, because a stray click in the first thirty seconds would throw away the only explanation on offer. And dismissing by any route marks it seen, Escape included, because a desktop that reintroduces itself every login has failed to take no for an answer. It stays reachable from the launcher afterwards, since the moment somebody wants it again is exactly when a one-shot has thrown it away. Also teaches the keymap to spell punctuation: slash, period, comma and the rest were rendering as their raw keysym names, so the welcome screen offered "Super + slash" and the cheatsheet agreed with it.
143 lines
5.8 KiB
QML
143 lines
5.8 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" | "cheatsheet" | "welcome"
|
|
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"
|
|
readonly property bool cheatsheetOpen: activeOverlay === "cheatsheet"
|
|
readonly property bool welcomeOpen: activeOverlay === "welcome"
|
|
|
|
// 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
|
|
}
|