summaryrefslogtreecommitdiff
path: root/accounts/gkleen@sif/shell/quickshell
diff options
context:
space:
mode:
Diffstat (limited to 'accounts/gkleen@sif/shell/quickshell')
-rw-r--r--accounts/gkleen@sif/shell/quickshell/Clock.qml65
-rw-r--r--accounts/gkleen@sif/shell/quickshell/KeyboardLayout.qml53
-rw-r--r--accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml6
-rw-r--r--accounts/gkleen@sif/shell/quickshell/Services/WallpaperSelector.qml8
-rw-r--r--accounts/gkleen@sif/shell/quickshell/SystemTray.qml10
-rw-r--r--accounts/gkleen@sif/shell/quickshell/WallpaperBackground.qml85
-rw-r--r--accounts/gkleen@sif/shell/quickshell/WorkspaceSwitcher.qml198
-rw-r--r--accounts/gkleen@sif/shell/quickshell/shell.qml23
8 files changed, 356 insertions, 92 deletions
diff --git a/accounts/gkleen@sif/shell/quickshell/Clock.qml b/accounts/gkleen@sif/shell/quickshell/Clock.qml
index 55fabd1c..edce57e3 100644
--- a/accounts/gkleen@sif/shell/quickshell/Clock.qml
+++ b/accounts/gkleen@sif/shell/quickshell/Clock.qml
@@ -7,6 +7,8 @@ import QtQuick.Layouts
7import Quickshell.Widgets 7import Quickshell.Widgets
8 8
9Item { 9Item {
10 id: clockItem
11
10 width: clock.contentWidth 12 width: clock.contentWidth
11 height: parent.height 13 height: parent.height
12 anchors.verticalCenter: parent.verticalCenter 14 anchors.verticalCenter: parent.verticalCenter
@@ -30,22 +32,25 @@ Item {
30 32
31 onWheel: event => scrollYear(event) 33 onWheel: event => scrollYear(event)
32 34
33 Text { 35 Item {
34 id: clock 36 anchors.fill: parent
35 color: "white"
36 37
37 anchors.verticalCenter: parent.verticalCenter 38 Text {
39 id: clock
40 color: "white"
38 41
39 Custom.Chrono { 42 anchors.verticalCenter: parent.verticalCenter
40 id: chrono
41 format: "W{0:%V-%u} {0:%F} {0:%H:%M:%S%Ez}"
42 }
43 43
44 text: chrono.date 44 Custom.Chrono {
45 id: chrono
46
47 onDateChanged: clock.text = format("W{0:%V-%u} {0:%F} {0:%H:%M:%S%Ez}")
48 }
45 49
46 font.pointSize: 10 50 font.pointSize: 10
47 font.family: "Fira Sans" 51 font.family: "Fira Sans"
48 font.features: { "tnum": 1 } 52 font.features: { "tnum": 1 }
53 }
49 } 54 }
50 } 55 }
51 56
@@ -73,8 +78,7 @@ Item {
73 color: "black" 78 color: "black"
74 79
75 onVisibleChanged: { 80 onVisibleChanged: {
76 const d = new Date(); 81 yearCalendar.year = chrono.date.getFullYear();
77 yearCalendar.year = d.getFullYear();
78 clockMouseArea.angleRem = 0; 82 clockMouseArea.angleRem = 0;
79 } 83 }
80 84
@@ -112,7 +116,7 @@ Item {
112 } 116 }
113 117
114 GridLayout { 118 GridLayout {
115 property int year: { const d = new Date(); return d.getFullYear(); } 119 property int year: chrono.date.getFullYear()
116 120
117 id: yearCalendar 121 id: yearCalendar
118 122
@@ -146,10 +150,7 @@ Item {
146 font.pointSize: 10 150 font.pointSize: 10
147 font.family: "Fira Sans" 151 font.family: "Fira Sans"
148 152
149 text: { 153 text: new Date(yearCalendar.year, monthCalendar.month, 1).toLocaleString(Qt.locale("en_DK"), "MMMM")
150 const date = Date.fromLocaleDateString(Qt.locale(), `${yearCalendar.year}-${monthCalendar.month + 1}-01`, "yyyy-M-dd");
151 return date.toLocaleString(Qt.locale("en_DK"), "MMMM")
152 }
153 154
154 color: "#ffead3" 155 color: "#ffead3"
155 } 156 }
@@ -161,17 +162,25 @@ Item {
161 Layout.column: 1 162 Layout.column: 1
162 Layout.fillWidth: true 163 Layout.fillWidth: true
163 164
164 delegate: Text { 165 delegate: WrapperItem {
165 required property string shortName 166 required property string shortName
166 167
167 font.pointSize: 10 168 width: dowLabel.contentWidth + 6
168 font.family: "Fira Mono"
169 169
170 text: shortName 170 Text {
171 color: "#ffcc66" 171 id: dowLabel
172 172
173 horizontalAlignment: Text.AlignRight 173 anchors.fill: parent
174 verticalAlignment: Text.AlignVCenter 174
175 font.pointSize: 10
176 font.family: "Fira Sans"
177
178 text: parent.shortName
179 color: "#ffcc66"
180
181 horizontalAlignment: Text.AlignHCenter
182 verticalAlignment: Text.AlignVCenter
183 }
175 } 184 }
176 } 185 }
177 186
@@ -236,8 +245,10 @@ Item {
236 font.family: "Fira Sans" 245 font.family: "Fira Sans"
237 font.features: { "tnum": 1 } 246 font.features: { "tnum": 1 }
238 247
248 property bool today: chrono.date.getFullYear() == model.year && chrono.date.getMonth() == model.month && chrono.date.getDate() == model.day
249
239 text: model.day 250 text: model.day
240 color: model.today ? "#ff6699" : "white" 251 color: today ? "#ff6699" : "white"
241 252
242 horizontalAlignment: Text.AlignRight 253 horizontalAlignment: Text.AlignRight
243 verticalAlignment: Text.AlignVCenter 254 verticalAlignment: Text.AlignVCenter
diff --git a/accounts/gkleen@sif/shell/quickshell/KeyboardLayout.qml b/accounts/gkleen@sif/shell/quickshell/KeyboardLayout.qml
index 4a6b8390..bc3750f9 100644
--- a/accounts/gkleen@sif/shell/quickshell/KeyboardLayout.qml
+++ b/accounts/gkleen@sif/shell/quickshell/KeyboardLayout.qml
@@ -3,18 +3,8 @@ import QtQuick
3import qs.Services 3import qs.Services
4import Quickshell.Widgets 4import Quickshell.Widgets
5 5
6Rectangle { 6Item {
7 id: kbdWidget
8
9 property var keyboardAbbrev: { "English (programmer Dvorak)": "dvp", "English (US)": "us" }
10
11 width: kbdLabel.contentWidth + 8 7 width: kbdLabel.contentWidth + 8
12 color: {
13 if (kbdMouseArea.containsMouse) {
14 return "#33808080";
15 }
16 return "transparent";
17 }
18 height: parent.height 8 height: parent.height
19 anchors.verticalCenter: parent.verticalCenter 9 anchors.verticalCenter: parent.verticalCenter
20 10
@@ -22,6 +12,7 @@ Rectangle {
22 id: kbdMouseArea 12 id: kbdMouseArea
23 13
24 anchors.fill: parent 14 anchors.fill: parent
15
25 hoverEnabled: true 16 hoverEnabled: true
26 cursorShape: Qt.PointingHandCursor 17 cursorShape: Qt.PointingHandCursor
27 enabled: true 18 enabled: true
@@ -32,23 +23,37 @@ Rectangle {
32 NiriService.sendCommand({ "Action": { "SwitchLayout": { "layout": event.angleDelta > 0 ? "Next" : "Prev" } } }, _ => {}) 23 NiriService.sendCommand({ "Action": { "SwitchLayout": { "layout": event.angleDelta > 0 ? "Next" : "Prev" } } }, _ => {})
33 } 24 }
34 25
35 Text { 26 Rectangle {
36 id: kbdLabel 27 id: kbdWidget
37 28
38 font.pointSize: 10 29 property var keyboardAbbrev: { "English (programmer Dvorak)": "dvp", "English (US)": "us" }
39 font.family: "Fira Sans" 30
31 anchors.fill: parent
40 color: { 32 color: {
41 if (NiriService.keyboardLayouts?.current_idx === 0) 33 if (kbdMouseArea.containsMouse) {
42 return "#555"; 34 return "#33808080";
43 return "white"; 35 }
36 return "transparent";
44 } 37 }
45 anchors.centerIn: parent
46 38
47 text: { 39 Text {
48 const currentLayout = NiriService.keyboardLayouts?.names?.[NiriService.keyboardLayouts.current_idx]; 40 id: kbdLabel
49 if (!currentLayout) 41
50 return ""; 42 font.pointSize: 10
51 return kbdWidget.keyboardAbbrev[currentLayout] ? kbdWidget.keyboardAbbrev[currentLayout] : currentLayout; 43 font.family: "Fira Sans"
44 color: {
45 if (NiriService.keyboardLayouts?.current_idx === 0)
46 return "#555";
47 return "white";
48 }
49 anchors.centerIn: parent
50
51 text: {
52 const currentLayout = NiriService.keyboardLayouts?.names?.[NiriService.keyboardLayouts.current_idx];
53 if (!currentLayout)
54 return "";
55 return kbdWidget.keyboardAbbrev[currentLayout] ? kbdWidget.keyboardAbbrev[currentLayout] : currentLayout;
56 }
52 } 57 }
53 } 58 }
54 } 59 }
diff --git a/accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml b/accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml
index 179b55e0..af522ec4 100644
--- a/accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml
+++ b/accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml
@@ -160,7 +160,11 @@ Singleton {
160 }); 160 });
161 } 161 }
162 function eventWindowOpenedOrChanged(data) { 162 function eventWindowOpenedOrChanged(data) {
163 root.windows = Array.from(root.windows).filter(win => win.id !== data.window.id).concat([data.window]); 163 root.windows = Array.from(root.windows).map(win => {
164 if (data.window.is_focused)
165 win.is_focused = false;
166 return win;
167 }).filter(win => win.id !== data.window.id).concat([data.window]);
164 } 168 }
165 function eventWindowClosed(data) { 169 function eventWindowClosed(data) {
166 root.windows = Array.from(root.windows).filter(win => win.id !== data.id); 170 root.windows = Array.from(root.windows).filter(win => win.id !== data.id);
diff --git a/accounts/gkleen@sif/shell/quickshell/Services/WallpaperSelector.qml b/accounts/gkleen@sif/shell/quickshell/Services/WallpaperSelector.qml
new file mode 100644
index 00000000..3c524955
--- /dev/null
+++ b/accounts/gkleen@sif/shell/quickshell/Services/WallpaperSelector.qml
@@ -0,0 +1,8 @@
1import Custom as Custom
2
3Custom.FileSelector {
4 id: root
5
6 directory: @wallpapers@
7 epoch: 72000000
8}
diff --git a/accounts/gkleen@sif/shell/quickshell/SystemTray.qml b/accounts/gkleen@sif/shell/quickshell/SystemTray.qml
index 024026a3..55b1690e 100644
--- a/accounts/gkleen@sif/shell/quickshell/SystemTray.qml
+++ b/accounts/gkleen@sif/shell/quickshell/SystemTray.qml
@@ -17,10 +17,12 @@ Item {
17 spacing: 0 17 spacing: 0
18 18
19 Repeater { 19 Repeater {
20 model: { 20 model: ScriptModel {
21 var trayItems = Array.from(SystemTray.items.values).filter(item => item.status !== Status.Passive); 21 values: {
22 trayItems.sort((a, b) => a.category !== b.category ? b.category - a.category : a.id.localeCompare(b.id)) 22 var trayItems = Array.from(SystemTray.items.values).filter(item => item.status !== Status.Passive);
23 return trayItems; 23 trayItems.sort((a, b) => a.category !== b.category ? b.category - a.category : a.id.localeCompare(b.id))
24 return trayItems;
25 }
24 } 26 }
25 27
26 delegate: Item { 28 delegate: Item {
diff --git a/accounts/gkleen@sif/shell/quickshell/WallpaperBackground.qml b/accounts/gkleen@sif/shell/quickshell/WallpaperBackground.qml
new file mode 100644
index 00000000..de31915f
--- /dev/null
+++ b/accounts/gkleen@sif/shell/quickshell/WallpaperBackground.qml
@@ -0,0 +1,85 @@
1import QtQuick
2import Quickshell
3import qs.Services
4
5Item {
6 id: root
7
8 anchors.fill: parent
9
10 required property string screen
11
12 property Img current: one
13 property string source: selector.selected
14
15 WallpaperSelector {
16 id: selector
17 seed: screen
18 }
19
20 onSourceChanged: {
21 if (!source)
22 current = null;
23 else if (current === one)
24 two.update()
25 else
26 one.update()
27 }
28
29 Img { id: one }
30 Img { id: two }
31
32 component Img: Image {
33 id: img
34
35 function update() {
36 source = root.source || ""
37 }
38
39 anchors.fill: parent
40 fillMode: Image.PreserveAspectCrop
41 smooth: true
42 asynchronous: true
43 cache: false
44
45 opacity: 0
46
47 onStatusChanged: {
48 if (status === Image.Ready) {
49 root.current = this
50 }
51 }
52
53 states: State {
54 name: "visible"
55 when: root.current === img
56
57 PropertyChanges {
58 img.opacity: 1
59 }
60 StateChangeScript {
61 name: "unloadOther"
62 script: {
63 if (img === one)
64 two.source = ""
65 if (img === two)
66 one.source = ""
67 }
68 }
69 }
70
71 transitions: Transition {
72 SequentialAnimation {
73 NumberAnimation {
74 target: img
75 properties: "opacity"
76 duration: 5000
77 easing.type: Easing.OutCubic
78 }
79 ScriptAction {
80 scriptName: "unloadOther"
81 }
82 }
83 }
84 }
85}
diff --git a/accounts/gkleen@sif/shell/quickshell/WorkspaceSwitcher.qml b/accounts/gkleen@sif/shell/quickshell/WorkspaceSwitcher.qml
index 153c56bb..c8c017c3 100644
--- a/accounts/gkleen@sif/shell/quickshell/WorkspaceSwitcher.qml
+++ b/accounts/gkleen@sif/shell/quickshell/WorkspaceSwitcher.qml
@@ -1,5 +1,8 @@
1import Quickshell
1import QtQuick 2import QtQuick
2import qs.Services 3import qs.Services
4import Quickshell.Widgets
5import QtQuick.Layouts
3 6
4Row { 7Row {
5 id: workspaces 8 id: workspaces
@@ -11,61 +14,188 @@ Row {
11 spacing: 0 14 spacing: 0
12 15
13 Repeater { 16 Repeater {
14 model: { 17 model: ScriptModel {
15 let currWorkspaces = NiriService.workspaces; 18 values: {
16 const ignoreWorkspaces = Array.from(workspaces.ignoreWorkspaces); 19 let currWorkspaces = NiriService.workspaces;
17 currWorkspaces = currWorkspaces.filter(ws => ws.is_active || ignoreWorkspaces.every(iws => iws !== ws.name)); 20 const ignoreWorkspaces = Array.from(workspaces.ignoreWorkspaces);
18 currWorkspaces.sort((a, b) => { 21 currWorkspaces = currWorkspaces.filter(ws => ws.is_active || ignoreWorkspaces.every(iws => iws !== ws.name));
19 if (NiriService.outputs?.[a.output]?.logical?.x !== NiriService.outputs?.[b.output]?.logical?.x) 22 currWorkspaces.sort((a, b) => {
20 return NiriService.outputs?.[a.output]?.logical?.x - NiriService.outputs?.[b.output]?.logical?.x 23 if (NiriService.outputs?.[a.output]?.logical?.x !== NiriService.outputs?.[b.output]?.logical?.x)
21 if (NiriService.outputs?.[a.output]?.logical?.y !== NiriService.outputs?.[b.output]?.logical?.y) 24 return NiriService.outputs?.[a.output]?.logical?.x - NiriService.outputs?.[b.output]?.logical?.x
22 return NiriService.outputs?.[a.output]?.logical?.y - NiriService.outputs?.[b.output]?.logical?.y 25 if (NiriService.outputs?.[a.output]?.logical?.y !== NiriService.outputs?.[b.output]?.logical?.y)
23 return a.idx - b.idx; 26 return NiriService.outputs?.[a.output]?.logical?.y - NiriService.outputs?.[b.output]?.logical?.y
24 }); 27 return a.idx - b.idx;
25 return currWorkspaces; 28 });
29 return currWorkspaces;
30 }
26 } 31 }
27 32
28 Rectangle { 33 Item {
34 id: wsItem
35
29 property var workspaceData: modelData 36 property var workspaceData: modelData
30 37
31 width: wsLabel.contentWidth + 8 38 width: wsLabel.contentWidth + 8
32 color: {
33 if (mouseArea.containsMouse) {
34 return "#33808080";
35 }
36 return "transparent";
37 }
38 height: parent.height 39 height: parent.height
39 anchors.verticalCenter: parent.verticalCenter 40 anchors.verticalCenter: parent.verticalCenter
40 41
41 MouseArea { 42 WrapperMouseArea {
42 id: mouseArea 43 id: mouseArea
43 44
44 anchors.fill: parent 45 anchors.fill: parent
46
45 hoverEnabled: true 47 hoverEnabled: true
46 cursorShape: Qt.PointingHandCursor 48 cursorShape: Qt.PointingHandCursor
47 enabled: true 49 enabled: true
48 onClicked: { 50 onClicked: {
49 NiriService.sendCommand({ "Action": { "FocusWorkspace": { "reference": { "Id": workspaceData.id } } } }, _ => {}) 51 NiriService.sendCommand({ "Action": { "FocusWorkspace": { "reference": { "Id": workspaceData.id } } } }, _ => {})
50 } 52 }
53
54 Rectangle {
55 anchors.fill: parent
56
57 color: {
58 if (mouseArea.containsMouse) {
59 return "#33808080";
60 }
61 return "transparent";
62 }
63
64 Text {
65 id: wsLabel
66
67 anchors.centerIn: parent
68
69 font.pointSize: 10
70 font.family: "Fira Sans"
71 color: {
72 if (workspaceData.is_active)
73 return "#23fd00";
74 if (workspaceData.active_window_id === null)
75 return "#555";
76 return "white";
77 }
78
79 text: workspaceData.name ? workspaceData.name : workspaceData.idx
80 }
81 }
51 } 82 }
52 83
53 Text { 84 PopupWindow {
54 id: wsLabel 85 id: tooltip
55 86
56 font.pointSize: 10 87 property bool nextVisible: (mouseArea.containsMouse || tooltipMouseArea.containsMouse) && [...windowsModel.values].length > 0
57 font.family: "Fira Sans" 88
58 color: { 89 anchor {
59 if (workspaceData.is_active) 90 item: mouseArea
60 return "#23fd00"; 91 edges: Edges.Bottom | Edges.Left
61 if (workspaceData.active_window_id === null) 92 }
62 return "#555"; 93 visible: false
63 return "white"; 94
95 onNextVisibleChanged: hangTimer.restart()
96
97 Timer {
98 id: hangTimer
99 interval: 100
100 onTriggered: tooltip.visible = tooltip.nextVisible
64 } 101 }
65 anchors.centerIn: parent
66 102
67 text: workspaceData.name ? workspaceData.name : workspaceData.idx 103 implicitWidth: tooltipContent.implicitWidth
104 implicitHeight: tooltipContent.implicitHeight
105 color: "black"
106
107 WrapperMouseArea {
108 id: tooltipMouseArea
109
110 hoverEnabled: true
111 enabled: true
112
113 anchors.fill: parent
114
115 WrapperItem {
116 id: tooltipContent
117
118 margin: 0
119
120 ColumnLayout {
121 spacing: 0
122
123 Repeater {
124 model: ScriptModel {
125 id: windowsModel
126
127 values: {
128 let currWindows = Array.from(NiriService.windows).filter(win => win.workspace_id == wsItem.workspaceData.id);
129 currWindows.sort((a, b) => {
130 if (a.is_floating !== b.is_floating)
131 return b.is_floating - a.is_floating;
132 if (a.layout.tile_pos_in_workspace_view?.[0] !== b.layout.tile_pos_in_workspace_view?.[0])
133 return a.layout.tile_pos_in_workspace_view?.[0] - b.layout.tile_pos_in_workspace_view?.[0]
134 if (a.layout.tile_pos_in_workspace_view?.[1] !== b.layout.tile_pos_in_workspace_view?.[1])
135 return a.layout.tile_pos_in_workspace_view?.[1] - b.layout.tile_pos_in_workspace_view?.[1]
136 if (a.layout.pos_in_scrolling_layout?.[0] !== b.layout.pos_in_scrolling_layout?.[0])
137 return a.layout.pos_in_scrolling_layout?.[0] - b.layout.pos_in_scrolling_layout?.[0]
138 if (a.layout.pos_in_scrolling_layout?.[1] !== b.layout.pos_in_scrolling_layout?.[1])
139 return a.layout.pos_in_scrolling_layout?.[1] - b.layout.pos_in_scrolling_layout?.[1]
140 if (a.app_id !== b.app_id)
141 return a.app_id.localeCompare(b.app_id);
142
143 return a.title.localeCompare(b.title);
144 });
145 return currWindows;
146 }
147 }
148
149 WrapperMouseArea {
150 id: windowMouseArea
151
152 property var windowData: modelData
153
154 hoverEnabled: true
155 cursorShape: Qt.PointingHandCursor
156 enabled: true
157
158 Layout.fillWidth: true
159
160 onClicked: {
161 NiriService.sendCommand({ "Action": { "FocusWindow": { "id": windowData.id } } }, _ => {})
162 }
163
164 WrapperRectangle {
165 color: windowMouseArea.containsMouse ? "#33808080" : "transparent";
166
167 anchors.fill: parent
168
169 WrapperItem {
170 anchors.fill: parent
171
172 margin: 4
173
174 Text {
175 id: windowLabel
176
177 font.pointSize: 10
178 font.family: "Fira Sans"
179 color: {
180 if (windowData.is_focused)
181 return "#23fd00";
182 if (NiriService.workspaces.find(ws => ws.id == windowData.workspace_id)?.active_window_id == windowData.id)
183 return "white";
184 return "#555";
185 }
186
187 text: windowData.title
188
189 horizontalAlignment: Text.AlignLeft
190 }
191 }
192 }
193 }
194 }
195 }
196 }
197 }
68 } 198 }
69 } 199 }
70 } 200 }
71} \ No newline at end of file 201}
diff --git a/accounts/gkleen@sif/shell/quickshell/shell.qml b/accounts/gkleen@sif/shell/quickshell/shell.qml
index 4934cd4d..2ddecad9 100644
--- a/accounts/gkleen@sif/shell/quickshell/shell.qml
+++ b/accounts/gkleen@sif/shell/quickshell/shell.qml
@@ -1,6 +1,7 @@
1//@ pragma UseQApplication 1//@ pragma UseQApplication
2 2
3import Quickshell 3import Quickshell
4import Quickshell.Wayland
4 5
5ShellRoot { 6ShellRoot {
6 settings.watchFiles: false 7 settings.watchFiles: false
@@ -13,9 +14,27 @@ ShellRoot {
13 14
14 required property var modelData 15 required property var modelData
15 16
16 Bar { 17 PanelWindow {
17 id: bar 18 id: bgWindow
19
20 screen: screenScope.modelData
21
22 WlrLayershell.layer: WlrLayer.Background
23 WlrLayershell.exclusionMode: ExclusionMode.Ignore
24
25 anchors.top: true
26 anchors.bottom: true
27 anchors.left: true
28 anchors.right: true
18 29
30 color: "black"
31
32 WallpaperBackground {
33 screen: bgWindow.screen.name
34 }
35 }
36
37 Bar {
19 screen: screenScope.modelData 38 screen: screenScope.modelData
20 } 39 }
21 } 40 }