aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/shell.qml
blob: ec58936d184177c07ec3c289220a8052163058c2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//@ pragma UseQApplication
// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// UseQApplication (line 1) is for the island's tray menus: SystemTrayItem
// display() fails without it. Pragmas are read only at launch, so changing
// it needs a restart, not a hot reload.
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import QtQuick
import "modules/ai"
import "modules/appearance"
import "modules/assistant"
import "modules/autostart"
import "modules/bluetooth"
import "modules/clipboard"
import "modules/git"
import "modules/kdeconnect"
import "modules/mail"
import "modules/network"
import "modules/notes"
import "modules/perf"
import "modules/sound"
import "modules/status"
import "modules/updates"
import "modules/user"
import "modules/vm"
import "island"
import "assistant"

ShellRoot {
    // Quickshell exits once no window is visible, and the drawer is closed
    // most of the time. See AGENTS.md.
    //
    // It is also the window the idle inhibitor attaches to: IdleInhibitor
    // needs a non-null window, and this is the one window that exists for
    // the whole life of the shell.
    PanelWindow {
        id: keepalive
        visible: true
        implicitWidth: 1
        implicitHeight: 1
        color: "transparent"
        exclusionMode: ExclusionMode.Ignore
        mask: Region {}
        WlrLayershell.keyboardFocus: WlrKeyboardFocus.None

        // The singleton has no window of its own and IdleInhibitor needs one.
        Component.onCompleted: Status.inhibitWindow = keepalive
    }

    Drawer {
        id: drawer
        settingsWindow: settings
        modules: [
            SoundModule { id: soundModule },
            NetworkModule {},
            BluetoothModule {},
            KdeConnectModule {},
            MailModule {},
            StatusModule {},
            PerfModule {},
            ClipboardModule {},
            UpdatesModule {},
            VmModule {},
            AiModule {},
            UserModule {},
            NotesModule {},
            WallpaperModule {},
            ThemeModule {},
            IconsModule {},
            SunsetModule {},
            IdleModule {},
            AutostartModule {},
            AssistantModule {},
            PresetsModule {},
            GitModule {},
        ]
    }

    // Pages set once and left alone, the modules marked `settings`, in a
    // window of their own. See Settings.qml.
    Settings {
        id: settings
        modules: drawer.modules
    }

    // unified-desktop-theme's manual steps, its own window on DP-3. See
    // modules/appearance/README.md.
    StepsWindow { id: stepsWindow }

    // The island on DP-1. It reads the sound module's service rather than
    // binding PipeWire a second time.
    Island {
        id: island
        sound: soundModule.service
        drawer: drawer
        asst: assistant
    }

    // The assistant canvas on SUPER+Home, a view over desktop-assistant's
    // socket. See assistant/README.md.
    Assistant { id: assistant }

    // The waybar launcher and the deep-link keybinds all reach this:
    //   qs -p <this dir> ipc call drawer toggle       -> the grid
    //   qs -p <this dir> ipc call drawer open mail    -> the mail page
    // Quickshell 0.3.1 IPC requires every declared argument to be present,
    // and a parameter with a JS default registers as QVariant, which IPC
    // rejects. So the page name cannot be optional: `open` always takes a
    // page, and the page-less grid is `toggle`, the zero-argument shape the
    // waybar launcher called.
    IpcHandler {
        target: "drawer"
        function open(page: string) { drawer.show(page); }
        function toggle() { drawer.toggle(""); }
        function close() { drawer.close(); }
    }

    //   qs -p <this dir> ipc call settings open autostart
    //   qs -p <this dir> ipc call settings toggle
    IpcHandler {
        target: "settings"
        function open(page: string) { settings.show(page); }
        function toggle() { if (settings.open) settings.close(); else settings.show(""); }
    }

    // The verbs of the appearance shell this replaced, so its callers only
    // change the path: udt-steps calls `steps`.
    //   qs -p <this dir> ipc call appearance wallpaper
    IpcHandler {
        target: "appearance"
        function toggle() { settings.show("wallpaper"); }
        function wallpaper() { settings.show("wallpaper"); }
        function theme() { settings.show("theme"); }
        function sunset() { settings.show("sunset"); }
        function idle() { settings.show("idle"); }
        function icons() { settings.show("icons"); }
        function steps() { stepsWindow.poke(); }
        function selftest(): string {
            return Hyprsunset.selftest() + "\n" + Hypridle.selftest() + "\n" + Icons.selftest() + "\n" + Steps.selftest();
        }
    }

    //   qs -p <this dir> ipc call assistant toggle    -> SUPER+Home
    IpcHandler {
        target: "assistant"
        function toggle() { assistant.toggle(); }
    }
}