summaryrefslogtreecommitdiff
path: root/accounts
diff options
context:
space:
mode:
Diffstat (limited to 'accounts')
-rw-r--r--accounts/gkleen@sif/niri/default.nix44
-rw-r--r--accounts/gkleen@sif/niri/waybar.nix358
-rw-r--r--accounts/gkleen@sif/shell/default.nix1
-rw-r--r--accounts/gkleen@sif/shell/quickshell-plugins/Systemd.cpp27
-rw-r--r--accounts/gkleen@sif/shell/quickshell-plugins/Systemd.hpp3
-rw-r--r--accounts/gkleen@sif/shell/quickshell/ActiveWindowDisplay.qml20
-rw-r--r--accounts/gkleen@sif/shell/quickshell/Bar.qml7
-rw-r--r--accounts/gkleen@sif/shell/quickshell/BatteryWidget.qml72
-rw-r--r--accounts/gkleen@sif/shell/quickshell/BrightnessWidget.qml20
-rw-r--r--accounts/gkleen@sif/shell/quickshell/Clock.qml17
-rw-r--r--accounts/gkleen@sif/shell/quickshell/KeyboardLayout.qml24
-rw-r--r--accounts/gkleen@sif/shell/quickshell/LidSwitchInhibitorWidget.qml1
-rw-r--r--accounts/gkleen@sif/shell/quickshell/Lockscreen.qml7
-rw-r--r--accounts/gkleen@sif/shell/quickshell/PipewireWidget.qml40
-rw-r--r--accounts/gkleen@sif/shell/quickshell/Services/MprisProxy.qml8
-rw-r--r--accounts/gkleen@sif/shell/quickshell/SystemTray.qml43
-rw-r--r--accounts/gkleen@sif/shell/quickshell/UnixIPC.qml18
-rw-r--r--accounts/gkleen@sif/shell/quickshell/WaylandInhibitorWidget.qml1
-rw-r--r--accounts/gkleen@sif/shell/quickshell/WorkspaceSwitcher.qml11
-rw-r--r--accounts/gkleen@sif/shell/quickshell/WorktimeWidget.qml120
-rw-r--r--accounts/gkleen@sif/shell/quickshell/shell.qml3
21 files changed, 348 insertions, 497 deletions
diff --git a/accounts/gkleen@sif/niri/default.nix b/accounts/gkleen@sif/niri/default.nix
index 32d55f97..3c29b83c 100644
--- a/accounts/gkleen@sif/niri/default.nix
+++ b/accounts/gkleen@sif/niri/default.nix
@@ -165,7 +165,6 @@ let
165 with-focused-window-action = config.lib.niri.actions.spawn (lib.getExe (with_predicate_window ".is_focused")); 165 with-focused-window-action = config.lib.niri.actions.spawn (lib.getExe (with_predicate_window ".is_focused"));
166in { 166in {
167 imports = [ 167 imports = [
168 ./waybar.nix
169 ./mako.nix 168 ./mako.nix
170 ]; 169 ];
171 170
@@ -716,7 +715,7 @@ in {
716 715
717 (plain "layer-rule" [ 716 (plain "layer-rule" [
718 (sleaf "match" { namespace = "^notifications$"; }) 717 (sleaf "match" { namespace = "^notifications$"; })
719 (sleaf "match" { namespace = "^waybar$"; }) 718 (sleaf "match" { namespace = "^bar$"; })
720 (sleaf "match" { namespace = "^launcher$"; }) 719 (sleaf "match" { namespace = "^launcher$"; })
721 (sleaf "block-out-from" "screencast") 720 (sleaf "block-out-from" "screencast")
722 ]) 721 ])
@@ -908,23 +907,23 @@ in {
908 "Mod+Right".action = set-column-width "+10%"; 907 "Mod+Right".action = set-column-width "+10%";
909 908
910 "Mod+Shift+Z" = { 909 "Mod+Shift+Z" = {
911 action = spawn (lib.getExe niri) "msg" "action" "power-off-monitors"; 910 action = power-off-monitors;
912 allow-when-locked = true; 911 allow-when-locked = true;
913 }; 912 };
914 "Mod+Shift+L".action = spawn loginctl "lock-session"; 913 # "Mod+Shift+L".action = spawn loginctl "lock-session";
915 "Mod+Shift+E".action = quit; 914 "Mod+Shift+E".action = quit;
916 "Mod+Shift+Minus" = { 915 # "Mod+Shift+Minus" = {
917 action = spawn systemctl "suspend"; 916 # action = spawn systemctl "suspend";
918 allow-when-locked = true; 917 # allow-when-locked = true;
919 }; 918 # };
920 "Mod+Shift+Control+Minus" = { 919 # "Mod+Shift+Control+Minus" = {
921 action = spawn systemctl "hibernate"; 920 # action = spawn systemctl "hibernate";
922 allow-when-locked = true; 921 # allow-when-locked = true;
923 }; 922 # };
924 "Mod+Shift+P" = { 923 # "Mod+Shift+P" = {
925 action = spawn (lib.getExe pkgs.playerctl) "-a" "pause"; 924 # action = spawn (lib.getExe pkgs.playerctl) "-a" "pause";
926 allow-when-locked = true; 925 # allow-when-locked = true;
927 }; 926 # };
928 927
929 "Mod+Semicolon".action = spawn makoctl "dismiss" "--group"; 928 "Mod+Semicolon".action = spawn makoctl "dismiss" "--group";
930 "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all"; 929 "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all";
@@ -974,6 +973,19 @@ in {
974 action = shell { Brightness = "down"; }; 973 action = shell { Brightness = "down"; };
975 allow-when-locked = true; 974 allow-when-locked = true;
976 }; 975 };
976 "Mod+Shift+L".action = shell { LockSession = {}; };
977 "Mod+Shift+Minus" = {
978 action = shell { Suspend = {}; };
979 allow-when-locked = true;
980 };
981 "Mod+Shift+Control+Minus" = {
982 action = shell { Hibernate = {}; };
983 allow-when-locked = true;
984 };
985 "Mod+Shift+P" = {
986 action = shell { Mpris = { PauseAll = {}; }; };
987 allow-when-locked = true;
988 };
977 })) 989 }))
978 (map ({ name, selector, spawn, key, ...}: if key != null && selector != null && spawn != null then bind key { action = focus-or-spawn-action selector name spawn; } else null) cfg.scratchspaces) 990 (map ({ name, selector, spawn, key, ...}: if key != null && selector != null && spawn != null then bind key { action = focus-or-spawn-action selector name spawn; } else null) cfg.scratchspaces)
979 (map ({ name, moveKey, ...}: if moveKey != null then bind moveKey { action = kdl.magic-leaf "move-column-to-workspace" name; } else null) cfg.scratchspaces) 991 (map ({ name, moveKey, ...}: if moveKey != null then bind moveKey { action = kdl.magic-leaf "move-column-to-workspace" name; } else null) cfg.scratchspaces)
diff --git a/accounts/gkleen@sif/niri/waybar.nix b/accounts/gkleen@sif/niri/waybar.nix
deleted file mode 100644
index 04e255da..00000000
--- a/accounts/gkleen@sif/niri/waybar.nix
+++ /dev/null
@@ -1,358 +0,0 @@
1{ lib, config, pkgs, ... }:
2let
3 swayosd-client = lib.getExe' config.services.swayosd.package "swayosd-client";
4in {
5 config = {
6 programs.waybar = {
7 enable = false; # true;
8 systemd = {
9 enable = true;
10 target = "graphical-session.target";
11 };
12 settings = let
13 windowRewrites = {
14 "(.*) — Mozilla Firefox" = "$1";
15 "(.*) - Mozilla Thunderbird" = "$1";
16 "(.*) - mpv" = "$1";
17 };
18 iconSize = 11;
19 in [
20 {
21 layer = "top";
22 position = "top";
23 height = 21;
24 output = [ "eDP-1" "DP-2" "DP-3" ];
25 modules-left = [ "niri/workspaces" ];
26 modules-center = [ "niri/window" ];
27 modules-right = [ "custom/worktime" "custom/worktime-today"
28 "custom/weather"
29 "custom/keymap"
30 "privacy" "tray" "wireplumber" "backlight" "battery" "idle_inhibitor" "custom/mako" "custom/lid_inhibitor" "clock" ];
31
32 "custom/lid_inhibitor" = {
33 format = "{}";
34 return-type = "json";
35 exec = lib.getExe pkgs.waybar-systemd-inhibit;
36 on-click = lib.getExe' pkgs.waybar-systemd-inhibit "waybar-systemd-inhibit-toggle";
37 };
38 "custom/mako" = {
39 format = "{}";
40 return-type = "json";
41 exec = pkgs.writers.writePython3 "mako-silent" { libraries = [ pkgs.python3Packages.dbus-next ]; } ''
42 from dbus_next.aio import MessageBus
43
44 import asyncio
45
46 import json
47
48
49 loop = asyncio.new_event_loop()
50 asyncio.set_event_loop(loop)
51
52
53 async def main():
54 bus = await MessageBus().connect()
55 # the introspection xml would normally be included in your project, but
56 # this is convenient for development
57 introspection = await bus.introspect('org.freedesktop.Notifications', '/fr/emersion/Mako') # noqa: E501
58
59 obj = bus.get_proxy_object('org.freedesktop.Notifications', '/fr/emersion/Mako', introspection) # noqa: E501
60 mako = obj.get_interface('fr.emersion.Mako')
61 properties = obj.get_interface('org.freedesktop.DBus.Properties')
62
63 async def print_mode():
64 modes = await mako.get_modes()
65 is_silent = "silent" in modes
66 icon = "󰂛" if is_silent else "󰂚"
67 text = f"<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>" # noqa: E501
68 if is_silent:
69 text = f"<span color=\"#ffffff\">{text}</span>"
70 print(json.dumps({'text': text, 'tooltip': ', '.join(modes)}, separators=(',', ':')), flush=True) # noqa: E501
71
72 async def on_properties_changed(interface_name, changed_properties, invalidated_properties): # noqa: E501
73 if "Modes" not in invalidated_properties:
74 return
75
76 await print_mode()
77
78 properties.on_properties_changed(on_properties_changed)
79 await print_mode()
80
81 await loop.create_future()
82
83
84 loop.run_until_complete(main())
85 '';
86 on-click = "makoctl mode -t silent";
87 };
88 "custom/weather" = {
89 format = "{}";
90 tooltip = true;
91 interval = 3600;
92 exec = "${lib.getExe pkgs.wttrbar} --hide-conditions --nerd --custom-indicator \"<span font=\\\"Symbols Nerd Font Mono\\\" size=\\\"100%\\\">{ICON}</span> {FeelsLikeC}°\"";
93 return-type = "json";
94 };
95 "custom/keymap" = {
96 format = "{}";
97 tooltip = true;
98 return-type = "json";
99 exec = pkgs.writers.writePython3 "keymap" {} ''
100 import os
101 import socket
102 import json
103
104
105 def output(keymap):
106 short = keymap
107 if keymap == "English (programmer Dvorak)":
108 short = "dvp"
109 elif keymap == "English (US)":
110 short = "<span color=\"#ffffff\">us</span>"
111 print(json.dumps({'text': short, 'tooltip': keymap}, separators=(',', ':')), flush=True) # noqa: E501
112
113
114 keyboard_layouts = []
115
116 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
117 sock.connect(os.environ["NIRI_SOCKET"])
118 sock.send(b"\"EventStream\"\n")
119 for line in sock.makefile(buffering=1, encoding='utf-8'):
120 if line_json := json.loads(line):
121 if "KeyboardLayoutsChanged" in line_json:
122 keyboard_layouts = line_json["KeyboardLayoutsChanged"]["keyboard_layouts"]["names"] # noqa: E501
123 output(keyboard_layouts[line_json["KeyboardLayoutsChanged"]["keyboard_layouts"]["current_idx"]]) # noqa: E501
124 if "KeyboardLayoutSwitched" in line_json:
125 output(keyboard_layouts[line_json["KeyboardLayoutSwitched"]["idx"]]) # noqa: E501
126 '';
127 on-click = "niri msg action switch-layout next";
128 };
129 "custom/worktime" = {
130 interval = 60;
131 exec = "${lib.getExe pkgs.worktime} time --waybar";
132 return-type = "json";
133 };
134 "custom/worktime-today" = {
135 interval = 60;
136 exec = "${lib.getExe pkgs.worktime} today --waybar";
137 return-type = "json";
138 };
139 "niri/workspaces" = {
140 ignore = map ({ name, ... }: name) config.programs.niri.scratchspaces;
141 };
142 "niri/window" = {
143 separate-outputs = true;
144 icon = true;
145 icon-size = 14;
146 rewrite = windowRewrites;
147 };
148 clock = {
149 interval = 1;
150 # timezone = "Europe/Berlin";
151 format = "W{:%V-%u %F %H:%M:%S%Ez}";
152 tooltip-format = "<tt><small>{calendar}</small></tt>";
153 calendar = {
154 mode = "year";
155 mode-mon-col = 3;
156 weeks-pos = "left";
157 on-scroll = 1;
158 format = {
159 months = "<span color='#ffead3'><b>{}</b></span>";
160 days = "{}";
161 weeks = "<span color='#99ffdd'><b>{}</b></span>";
162 weekdays = "<span color='#ffcc66'><b>{}</b></span>";
163 today = "<span color='#ff6699'><b>{}</b></span>";
164 };
165 };
166 };
167 battery = {
168 format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>";
169 icon-size = iconSize - 2;
170 states = { warning = 30; critical = 15; };
171 format-icons = ["&#xf008e;" "&#xf007a;" "&#xf007b;" "&#xf007c;" "&#xf007d;" "&#xf007e;" "&#xf007f;" "&#xf0080;" "&#xf0081;" "&#xf0082;" "&#xf0079;" ];
172 format-charging = "&#xf0084;";
173 format-plugged = "&#xf06a5;";
174 tooltip-format = "{capacity}% {timeTo}";
175 interval = 20;
176 };
177 tray = {
178 icon-size = 16;
179 # show-passive-items = true;
180 spacing = 1;
181 };
182 privacy = {
183 icon-spacing = 7;
184 icon-size = iconSize;
185 modules = [
186 { type = "screenshare"; }
187 { type = "audio-in"; }
188 ];
189 };
190 idle_inhibitor = {
191 format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>";
192 icon-size = iconSize;
193 format-icons = { activated = "&#xf0208;"; deactivated = "&#xf0209;"; };
194 timeout = 120;
195 };
196 backlight = {
197 format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>";
198 icon-size = iconSize;
199 tooltip-format = "{percent}%";
200 format-icons = ["&#xf00da;" "&#xf00db;" "&#xf00dc;" "&#xf00dd;" "&#xf00de;" "&#xf00df;" "&#xf00e0;"];
201 on-scroll-up = "${swayosd-client} --brightness raise";
202 on-scroll-down = "${swayosd-client} --brightness lower";
203 };
204 wireplumber = {
205 format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>";
206 icon-size = iconSize;
207 tooltip-format = "{volume}% {node_name}";
208 format-icons = ["&#xf057f;" "&#xf0580;" "&#xf057e;"];
209 format-muted = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">&#xf075f;</span>";
210 # ignored-sinks = ["Easy Effects Sink"];
211 on-scroll-up = "${swayosd-client} --output-volume raise";
212 on-scroll-down = "${swayosd-client} --output-volume lower";
213 on-click = "${swayosd-client} --output-volume mute-toggle";
214 };
215 }
216 {
217 layer = "top";
218 position = "top";
219 height = 14;
220 output = [ "!eDP-1" "!DP-2" "!DP-3" "*" ];
221 modules-left = [ "niri/workspaces" ];
222 modules-center = [ "niri/window" ];
223 modules-right = [ "clock" ];
224
225 "niri/workspaces" = {
226 ignore = map ({ name, ... }: name) config.programs.niri.scratchspaces;
227 };
228 "niri/window" = {
229 separate-outputs = true;
230 icon = true;
231 icon-size = 14;
232 rewrite = windowRewrites;
233 };
234 clock = {
235 interval = 1;
236 # timezone = "Europe/Berlin";
237 format = "{:%H:%M}";
238 tooltip-format = "W{:%V-%u %F %H:%M:%S%Ez}";
239 };
240 }
241 ];
242 style = ''
243 @define-color white #ffffff;
244 @define-color grey #555555;
245 @define-color blue #1a8fff;
246 @define-color green #23fd00;
247 @define-color orange #f28a21;
248 @define-color red #f2201f;
249
250 * {
251 border: none;
252 font-family: "Fira Sans";
253 font-size: 10pt;
254 min-height: 0;
255 }
256
257 window#waybar {
258 background-color: rgba(0, 0, 0, 0.66);
259 color: @white;
260 }
261
262 .modules-left {
263 margin-left: 38px;
264 }
265 .modules-right {
266 margin-right: 38px;
267 }
268
269 .module {
270 margin: 0 5px;
271 }
272
273 #workspaces button {
274 color: @white;
275 padding: 2px 5px;
276 }
277 #workspaces button.empty {
278 color: @grey;
279 }
280 #workspaces button.active {
281 color: @green;
282 }
283 #workspaces button.urgent {
284 color: @red;
285 }
286
287 #custom-weather, #custom-keymap, #custom-worktime, #custom-worktime-today {
288 color: @grey;
289 margin: 0 5px;
290 }
291 #custom-weather {
292 margin-right: 3px;
293 }
294 #custom-keymap {
295 margin-left: 3px;
296 margin-right: 3px;
297 }
298
299 #tray {
300 margin: 0;
301 }
302 #battery, #idle_inhibitor, #backlight, #wireplumber, #custom-mako, #custom-lid_inhibitor {
303 color: @grey;
304 margin: 0 5px 0 2px;
305 }
306 #idle_inhibitor {
307 margin-right: 4px;
308 margin-left: 6px;
309 }
310 #custom-mako {
311 margin-right: 4px;
312 margin-left: 3px;
313 }
314 #custom-lid_inhibitor {
315 margin-right: 3px;
316 margin-left: 3px;
317 }
318 #battery {
319 margin-right: 3px;
320 }
321 #battery.discharging {
322 color: @white;
323 }
324 #battery.warning {
325 color: @orange;
326 }
327 #battery.critical {
328 color: @red;
329 }
330 #battery.charging {
331 color: @white;
332 }
333 #idle_inhibitor.activated {
334 color: @white;
335 }
336 #custom-worktime.running, #custom-worktime-today.running {
337 color: @white;
338 }
339 #custom-worktime.over, #custom-worktime-today.over {
340 color: @orange;
341 }
342
343 #idle_inhibitor, #custom-lid_inhibitor {
344 padding-top: 1px;
345 }
346
347 #privacy {
348 color: @red;
349 margin: -1px 4px 0px 3px;
350 }
351 #clock {
352 /* margin-right: 5px; */
353 font-feature-settings: "tnum";
354 }
355 '';
356 };
357 };
358}
diff --git a/accounts/gkleen@sif/shell/default.nix b/accounts/gkleen@sif/shell/default.nix
index 5025dd90..44462865 100644
--- a/accounts/gkleen@sif/shell/default.nix
+++ b/accounts/gkleen@sif/shell/default.nix
@@ -102,6 +102,7 @@
102 rev = "2424e748e0cc63ab7b9c095a099b9fe239b737c0"; 102 rev = "2424e748e0cc63ab7b9c095a099b9fe239b737c0";
103 hash = "sha256-QMGl7soAhErrrnY3aKOZpt49yebkSNzy10p/v5OaqQ0="; 103 hash = "sha256-QMGl7soAhErrrnY3aKOZpt49yebkSNzy10p/v5OaqQ0=";
104 }); 104 });
105 worktime = builtins.toJSON (lib.getExe pkgs.worktime);
105 }; 106 };
106 }; 107 };
107 }; 108 };
diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.cpp b/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.cpp
index 884ea17f..308659e9 100644
--- a/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.cpp
+++ b/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.cpp
@@ -51,26 +51,17 @@ void Systemd::onLogindSessionPropertiesChanged(const QString& interface_name, co
51 emit this->lockedHintChanged(); 51 emit this->lockedHintChanged();
52} 52}
53 53
54void Systemd::stopUserUnit(const QString& unit, const QString& mode) { 54void Systemd::stopUserUnit(const QString& unit, const QString& mode) { this->systemdManager->StopUnit(unit, mode); }
55 this->systemdManager->StopUnit(unit, mode);
56}
57 55
58void Systemd::setBrightness(const QString& subsystem, const QString& name, quint32 brightness) { 56void Systemd::setBrightness(const QString& subsystem, const QString& name, quint32 brightness) { this->logindSession->SetBrightness(subsystem, name, brightness); }
59 this->logindSession->SetBrightness(subsystem, name, brightness);
60}
61 57
62bool Systemd::idleHint() { 58bool Systemd::idleHint() { return this->logindSession->idleHint(); }
63 return this->logindSession->idleHint(); 59void Systemd::setIdleHint(bool idle) { this->logindSession->SetIdleHint(idle); }
64} 60bool Systemd::lockedHint() { return this->logindSession->lockedHint(); }
65void Systemd::setIdleHint(bool idle) { 61void Systemd::setLockedHint(bool locked) { this->logindSession->SetLockedHint(locked); }
66 this->logindSession->SetIdleHint(idle); 62void Systemd::lockSession() { this->logindSession->call("Lock"); }
67} 63void Systemd::suspend() { this->logindManager->Suspend(true); }
68bool Systemd::lockedHint() { 64void Systemd::hibernate() { this->logindManager->Hibernate(true); }
69 return this->logindSession->lockedHint();
70}
71void Systemd::setLockedHint(bool locked) {
72 this->logindSession->SetLockedHint(locked);
73}
74 65
75std::string SystemdInhibitorParams::toString(SystemdInhibitorParams::WhatItem what) { 66std::string SystemdInhibitorParams::toString(SystemdInhibitorParams::WhatItem what) {
76 if (what == SystemdInhibitorParams::Shutdown) 67 if (what == SystemdInhibitorParams::Shutdown)
diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.hpp b/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.hpp
index 84752d76..615024d2 100644
--- a/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.hpp
+++ b/accounts/gkleen@sif/shell/quickshell-plugins/Systemd.hpp
@@ -28,6 +28,9 @@ public:
28 Q_INVOKABLE void setBrightness(const QString& subsystem, const QString& name, quint32 brightness); 28 Q_INVOKABLE void setBrightness(const QString& subsystem, const QString& name, quint32 brightness);
29 Q_INVOKABLE void setIdleHint(bool idle); 29 Q_INVOKABLE void setIdleHint(bool idle);
30 Q_INVOKABLE void setLockedHint(bool locked); 30 Q_INVOKABLE void setLockedHint(bool locked);
31 Q_INVOKABLE void lockSession();
32 Q_INVOKABLE void suspend();
33 Q_INVOKABLE void hibernate();
31 34
32 bool idleHint(); 35 bool idleHint();
33 bool lockedHint(); 36 bool lockedHint();
diff --git a/accounts/gkleen@sif/shell/quickshell/ActiveWindowDisplay.qml b/accounts/gkleen@sif/shell/quickshell/ActiveWindowDisplay.qml
index 883f9001..dcc23279 100644
--- a/accounts/gkleen@sif/shell/quickshell/ActiveWindowDisplay.qml
+++ b/accounts/gkleen@sif/shell/quickshell/ActiveWindowDisplay.qml
@@ -149,16 +149,22 @@ Item {
149 hoverEnabled: true 149 hoverEnabled: true
150 enabled: true 150 enabled: true
151 151
152 anchors.centerIn: parent 152 anchors.fill: parent
153 153
154 Text { 154 Item {
155 id: widgetTooltipText 155 anchors.fill: parent
156 156
157 font.pointSize: 10 157 Text {
158 font.family: "Fira Mono" 158 id: widgetTooltipText
159 color: "white" 159
160 anchors.centerIn: parent
160 161
161 text: JSON.stringify(Object.assign({}, activeWindowDisplay.activeWindow), null, 2) 162 font.pointSize: 10
163 font.family: "Fira Mono"
164 color: "white"
165
166 text: JSON.stringify(Object.assign({}, activeWindowDisplay.activeWindow), null, 2)
167 }
162 } 168 }
163 } 169 }
164 } 170 }
diff --git a/accounts/gkleen@sif/shell/quickshell/Bar.qml b/accounts/gkleen@sif/shell/quickshell/Bar.qml
index f8092604..7f97bd75 100644
--- a/accounts/gkleen@sif/shell/quickshell/Bar.qml
+++ b/accounts/gkleen@sif/shell/quickshell/Bar.qml
@@ -1,4 +1,5 @@
1import Quickshell 1import Quickshell
2import Quickshell.Wayland
2import QtQuick 3import QtQuick
3 4
4PanelWindow { 5PanelWindow {
@@ -6,6 +7,8 @@ PanelWindow {
6 7
7 required property var screen 8 required property var screen
8 9
10 WlrLayershell.namespace: "bar"
11
9 anchors { 12 anchors {
10 top: true 13 top: true
11 left: true 14 left: true
@@ -63,6 +66,10 @@ PanelWindow {
63 anchors.verticalCenter: parent.verticalCenter 66 anchors.verticalCenter: parent.verticalCenter
64 spacing: 0 67 spacing: 0
65 68
69 WorktimeWidget { command: "time"; }
70
71 WorktimeWidget { command: "today"; }
72
66 KeyboardLayout {} 73 KeyboardLayout {}
67 74
68 Item { 75 Item {
diff --git a/accounts/gkleen@sif/shell/quickshell/BatteryWidget.qml b/accounts/gkleen@sif/shell/quickshell/BatteryWidget.qml
index fd031627..da17df2a 100644
--- a/accounts/gkleen@sif/shell/quickshell/BatteryWidget.qml
+++ b/accounts/gkleen@sif/shell/quickshell/BatteryWidget.qml
@@ -87,42 +87,48 @@ Item {
87 hoverEnabled: true 87 hoverEnabled: true
88 enabled: true 88 enabled: true
89 89
90 anchors.centerIn: parent 90 anchors.fill: parent
91
92 Text {
93 id: widgetTooltipText
94
95 font.pointSize: 10
96 font.family: "Fira Sans"
97 color: "white"
98 91
99 text: { 92 Item {
100 const stateStr = UPowerDeviceState.toString(root.batteryDevice.state); 93 anchors.fill: parent
101 var outStr = stateStr; 94
102 if (root.batteryDevice.state != UPowerDeviceState.FullyCharged) 95 Text {
103 outStr += ` ${Math.round(root.batteryDevice.percentage * 100)}%`; 96 id: widgetTooltipText
104 97
105 function formatTime(t) { 98 anchors.centerIn: parent
106 var res = ""; 99
107 for (const unit of [{ "s": "h", "v": 3600 }, { "s": "m", "v": 60 }, { "s": "s", "v": 1 }]) { 100 font.pointSize: 10
108 if (t < unit.v) 101 font.family: "Fira Sans"
109 continue; 102 color: "white"
110 res += Math.floor(t / unit.v) + unit.s; 103
111 t %= unit.v; 104 text: {
105 const stateStr = UPowerDeviceState.toString(root.batteryDevice.state);
106 var outStr = stateStr;
107 if (root.batteryDevice.state != UPowerDeviceState.FullyCharged)
108 outStr += ` ${Math.round(root.batteryDevice.percentage * 100)}%`;
109
110 function formatTime(t) {
111 var res = "";
112 for (const unit of [{ "s": "h", "v": 3600 }, { "s": "m", "v": 60 }, { "s": "s", "v": 1 }]) {
113 if (t < unit.v)
114 continue;
115 res += Math.floor(t / unit.v) + unit.s;
116 t %= unit.v;
117 }
118 return res;
119 }
120 if (root.batteryDevice.timeToEmpty != 0) {
121 const tStr = formatTime(Math.floor(root.batteryDevice.timeToEmpty / 60) * 60);
122 if (tStr)
123 outStr += " " + tStr;
124 } else if (root.batteryDevice.timeToFull != 0) {
125 const tStr = formatTime(Math.ceil(root.batteryDevice.timeToFull / 60) * 60);
126 if (tStr)
127 outStr += " " + tStr;
112 } 128 }
113 return res;
114 }
115 if (root.batteryDevice.timeToEmpty != 0) {
116 const tStr = formatTime(Math.floor(root.batteryDevice.timeToEmpty / 60) * 60);
117 if (tStr)
118 outStr += " " + tStr;
119 } else if (root.batteryDevice.timeToFull != 0) {
120 const tStr = formatTime(Math.ceil(root.batteryDevice.timeToFull / 60) * 60);
121 if (tStr)
122 outStr += " " + tStr;
123 }
124 129
125 return outStr; 130 return outStr;
131 }
126 } 132 }
127 } 133 }
128 } 134 }
diff --git a/accounts/gkleen@sif/shell/quickshell/BrightnessWidget.qml b/accounts/gkleen@sif/shell/quickshell/BrightnessWidget.qml
index 7f9c1ad0..3bb5a80e 100644
--- a/accounts/gkleen@sif/shell/quickshell/BrightnessWidget.qml
+++ b/accounts/gkleen@sif/shell/quickshell/BrightnessWidget.qml
@@ -62,16 +62,22 @@ Item {
62 hoverEnabled: true 62 hoverEnabled: true
63 enabled: true 63 enabled: true
64 64
65 anchors.centerIn: parent 65 anchors.fill: parent
66
67 Item {
68 anchors.fill: parent
69
70 Text {
71 id: widgetTooltipText
66 72
67 Text { 73 anchors.centerIn: parent
68 id: widgetTooltipText
69 74
70 font.pointSize: 10 75 font.pointSize: 10
71 font.family: "Fira Sans" 76 font.family: "Fira Sans"
72 color: "white" 77 color: "white"
73 78
74 text: `${Math.round(Brightness.currBrightness * 100)}%` 79 text: `${Math.round(Brightness.currBrightness * 100)}%`
80 }
75 } 81 }
76 } 82 }
77 } 83 }
diff --git a/accounts/gkleen@sif/shell/quickshell/Clock.qml b/accounts/gkleen@sif/shell/quickshell/Clock.qml
index bb618f6a..b7004528 100644
--- a/accounts/gkleen@sif/shell/quickshell/Clock.qml
+++ b/accounts/gkleen@sif/shell/quickshell/Clock.qml
@@ -80,8 +80,8 @@ Item {
80 } 80 }
81 } 81 }
82 82
83 implicitWidth: clockTooltipContent.width 83 implicitWidth: tooltipLayout.childrenRect.width + 16
84 implicitHeight: clockTooltipContent.height 84 implicitHeight: tooltipLayout.childrenRect.height + 16
85 color: "black" 85 color: "black"
86 86
87 onVisibleChanged: { 87 onVisibleChanged: {
@@ -99,13 +99,20 @@ Item {
99 99
100 anchors.fill: parent 100 anchors.fill: parent
101 101
102 WrapperItem { 102 Item {
103 id: clockTooltipContent 103 id: clockTooltipContent
104 104
105 margin: 8 105 anchors.fill: parent
106 106
107 ColumnLayout { 107 ColumnLayout {
108 anchors.centerIn: parent 108 id: tooltipLayout
109
110 anchors {
111 left: parent.left
112 top: parent.top
113 leftMargin: 8
114 topMargin: 8
115 }
109 116
110 Text { 117 Text {
111 id: yearLabel 118 id: yearLabel
diff --git a/accounts/gkleen@sif/shell/quickshell/KeyboardLayout.qml b/accounts/gkleen@sif/shell/quickshell/KeyboardLayout.qml
index bc3750f9..46302e54 100644
--- a/accounts/gkleen@sif/shell/quickshell/KeyboardLayout.qml
+++ b/accounts/gkleen@sif/shell/quickshell/KeyboardLayout.qml
@@ -87,18 +87,24 @@ Item {
87 hoverEnabled: true 87 hoverEnabled: true
88 enabled: true 88 enabled: true
89 89
90 anchors.centerIn: parent 90 anchors.fill: parent
91 91
92 Text { 92 Item {
93 id: kbdTooltipText 93 anchors.fill: parent
94 94
95 font.pointSize: 10 95 Text {
96 font.family: "Fira Sans" 96 id: kbdTooltipText
97 color: "white"
98 97
99 text: { 98 anchors.centerIn: parent
100 const currentLayout = NiriService.keyboardLayouts?.names?.[NiriService.keyboardLayouts.current_idx]; 99
101 return currentLayout || ""; 100 font.pointSize: 10
101 font.family: "Fira Sans"
102 color: "white"
103
104 text: {
105 const currentLayout = NiriService.keyboardLayouts?.names?.[NiriService.keyboardLayouts.current_idx];
106 return currentLayout || "";
107 }
102 } 108 }
103 } 109 }
104 } 110 }
diff --git a/accounts/gkleen@sif/shell/quickshell/LidSwitchInhibitorWidget.qml b/accounts/gkleen@sif/shell/quickshell/LidSwitchInhibitorWidget.qml
index 2be0692a..8410dcda 100644
--- a/accounts/gkleen@sif/shell/quickshell/LidSwitchInhibitorWidget.qml
+++ b/accounts/gkleen@sif/shell/quickshell/LidSwitchInhibitorWidget.qml
@@ -16,6 +16,7 @@ Item {
16 anchors.fill: parent 16 anchors.fill: parent
17 17
18 hoverEnabled: true 18 hoverEnabled: true
19 cursorShape: Qt.PointingHandCursor
19 20
20 onClicked: InhibitorState.lidSwitchInhibited = !InhibitorState.lidSwitchInhibited 21 onClicked: InhibitorState.lidSwitchInhibited = !InhibitorState.lidSwitchInhibited
21 22
diff --git a/accounts/gkleen@sif/shell/quickshell/Lockscreen.qml b/accounts/gkleen@sif/shell/quickshell/Lockscreen.qml
index 456baa98..f983388c 100644
--- a/accounts/gkleen@sif/shell/quickshell/Lockscreen.qml
+++ b/accounts/gkleen@sif/shell/quickshell/Lockscreen.qml
@@ -70,11 +70,6 @@ Scope {
70 mode: Custom.SystemdInhibitorParams.Delay 70 mode: Custom.SystemdInhibitorParams.Delay
71 } 71 }
72 72
73 Scope {
74 id: mprisProxy
75 property list<var> players: Mpris.players.values
76 }
77
78 WlSessionLock { 73 WlSessionLock {
79 id: lock 74 id: lock
80 75
@@ -85,7 +80,7 @@ Scope {
85 if (locked) { 80 if (locked) {
86 NiriService.sendCommand({ "Action": { "PowerOffMonitors": {} } }); 81 NiriService.sendCommand({ "Action": { "PowerOffMonitors": {} } });
87 Custom.KeePassXC.lockAllDatabases(); 82 Custom.KeePassXC.lockAllDatabases();
88 Array.from(mprisProxy.players).forEach(player => { 83 Array.from(MprisProxy.players).forEach(player => {
89 if (player.canPause && player.isPlaying) 84 if (player.canPause && player.isPlaying)
90 player.pause(); 85 player.pause();
91 }); 86 });
diff --git a/accounts/gkleen@sif/shell/quickshell/PipewireWidget.qml b/accounts/gkleen@sif/shell/quickshell/PipewireWidget.qml
index 3e0b8fd9..9c6b65a4 100644
--- a/accounts/gkleen@sif/shell/quickshell/PipewireWidget.qml
+++ b/accounts/gkleen@sif/shell/quickshell/PipewireWidget.qml
@@ -272,16 +272,22 @@ Item {
272 272
273 onWheel: event => defaultSinkMouseArea.scrollVolume(event); 273 onWheel: event => defaultSinkMouseArea.scrollVolume(event);
274 274
275 anchors.centerIn: parent 275 anchors.fill: parent
276
277 Item {
278 anchors.fill: parent
276 279
277 Text { 280 Text {
278 id: volumeTooltipText 281 id: volumeTooltipText
279 282
280 font.pointSize: 10 283 anchors.centerIn: parent
281 font.family: "Fira Sans"
282 color: "white"
283 284
284 text: `${Math.round(defaultSinkItem.modelData?.audio?.volume * 100)}%` 285 font.pointSize: 10
286 font.family: "Fira Sans"
287 color: "white"
288
289 text: `${Math.round(defaultSinkItem.modelData?.audio?.volume * 100)}%`
290 }
285 } 291 }
286 } 292 }
287 } 293 }
@@ -391,16 +397,22 @@ Item {
391 397
392 onWheel: event => defaultSourceMouseArea.scrollVolume(event); 398 onWheel: event => defaultSourceMouseArea.scrollVolume(event);
393 399
394 anchors.centerIn: parent 400 anchors.fill: parent
401
402 Item {
403 anchors.fill: parent
395 404
396 Text { 405 Text {
397 id: volumeTooltipText 406 id: volumeTooltipText
398 407
399 font.pointSize: 10 408 anchors.centerIn: parent
400 font.family: "Fira Sans"
401 color: "white"
402 409
403 text: `${Math.round(defaultSourceItem.modelData?.audio?.volume * 100)}%` 410 font.pointSize: 10
411 font.family: "Fira Sans"
412 color: "white"
413
414 text: `${Math.round(defaultSourceItem.modelData?.audio?.volume * 100)}%`
415 }
404 } 416 }
405 } 417 }
406 } 418 }
diff --git a/accounts/gkleen@sif/shell/quickshell/Services/MprisProxy.qml b/accounts/gkleen@sif/shell/quickshell/Services/MprisProxy.qml
new file mode 100644
index 00000000..e3ab9755
--- /dev/null
+++ b/accounts/gkleen@sif/shell/quickshell/Services/MprisProxy.qml
@@ -0,0 +1,8 @@
1pragma Singleton
2
3import Quickshell
4import Quickshell.Services.Mpris
5
6Scope {
7 property list<var> players: Mpris.players.values
8}
diff --git a/accounts/gkleen@sif/shell/quickshell/SystemTray.qml b/accounts/gkleen@sif/shell/quickshell/SystemTray.qml
index 351e74ee..f7b4ed96 100644
--- a/accounts/gkleen@sif/shell/quickshell/SystemTray.qml
+++ b/accounts/gkleen@sif/shell/quickshell/SystemTray.qml
@@ -155,32 +155,39 @@ Item {
155 hoverEnabled: true 155 hoverEnabled: true
156 enabled: true 156 enabled: true
157 157
158 margin: 8 158 margin: 4
159 159
160 Column { 160 anchors.fill: parent
161 Text {
162 id: tooltipTitle
163 161
164 enabled: trayItem.tooltipTitle 162 Item {
163 anchors.fill: parent
165 164
166 font.pointSize: 10 165 Column {
167 font.family: "Fira Sans" 166 anchors.centerIn: parent
168 font.bold: true 167 Text {
169 color: "white" 168 id: tooltipTitle
170 169
171 text: trayItem.tooltipTitle 170 enabled: trayItem.tooltipTitle
172 }
173 171
174 Text { 172 font.pointSize: 10
175 id: tooltipDescription 173 font.family: "Fira Sans"
174 font.bold: true
175 color: "white"
176 176
177 enabled: trayItem.tooltipDescription 177 text: trayItem.tooltipTitle
178 }
179
180 Text {
181 id: tooltipDescription
178 182
179 font.pointSize: 10 183 enabled: trayItem.tooltipDescription
180 font.family: "Fira Sans"
181 color: "white"
182 184
183 text: trayItem.tooltipDescription 185 font.pointSize: 10
186 font.family: "Fira Sans"
187 color: "white"
188
189 text: trayItem.tooltipDescription
190 }
184 } 191 }
185 } 192 }
186 } 193 }
diff --git a/accounts/gkleen@sif/shell/quickshell/UnixIPC.qml b/accounts/gkleen@sif/shell/quickshell/UnixIPC.qml
index 742ef4f5..e7b7b673 100644
--- a/accounts/gkleen@sif/shell/quickshell/UnixIPC.qml
+++ b/accounts/gkleen@sif/shell/quickshell/UnixIPC.qml
@@ -1,7 +1,9 @@
1import Quickshell 1import Quickshell
2import Quickshell.Io 2import Quickshell.Io
3import Quickshell.Services.Pipewire 3import Quickshell.Services.Pipewire
4import Quickshell.Services.Mpris
4import qs.Services 5import qs.Services
6import Custom as Custom
5 7
6Scope { 8Scope {
7 id: root 9 id: root
@@ -19,6 +21,14 @@ Scope {
19 root.onCommandVolume(command.Volume); 21 root.onCommandVolume(command.Volume);
20 else if (command.Brightness) 22 else if (command.Brightness)
21 root.onCommandBrightness(command.Brightness); 23 root.onCommandBrightness(command.Brightness);
24 else if (command.LockSession)
25 Custom.Systemd.lockSession();
26 else if (command.Suspend)
27 Custom.Systemd.suspend();
28 else if (command.Hibernate)
29 Custom.Systemd.hibernate();
30 else if (command.Mpris)
31 root.onCommandMpris(command.Mpris);
22 else 32 else
23 console.warn("UnixIPC: Command not handled:", JSON.stringify(command)); 33 console.warn("UnixIPC: Command not handled:", JSON.stringify(command));
24 } catch (e) { 34 } catch (e) {
@@ -56,4 +66,12 @@ Scope {
56 if (command === "down") 66 if (command === "down")
57 Brightness.currBrightness -= 0.02 67 Brightness.currBrightness -= 0.02
58 } 68 }
69
70 function onCommandMpris(command) {
71 if (command.PauseAll)
72 Array.from(MprisProxy.players).forEach(player => {
73 if (player.canPause && player.isPlaying)
74 player.pause();
75 });
76 }
59} 77}
diff --git a/accounts/gkleen@sif/shell/quickshell/WaylandInhibitorWidget.qml b/accounts/gkleen@sif/shell/quickshell/WaylandInhibitorWidget.qml
index 0633f350..0512ff51 100644
--- a/accounts/gkleen@sif/shell/quickshell/WaylandInhibitorWidget.qml
+++ b/accounts/gkleen@sif/shell/quickshell/WaylandInhibitorWidget.qml
@@ -25,6 +25,7 @@ Item {
25 anchors.fill: parent 25 anchors.fill: parent
26 26
27 hoverEnabled: true 27 hoverEnabled: true
28 cursorShape: Qt.PointingHandCursor
28 29
29 onClicked: InhibitorState.waylandIdleInhibited = !InhibitorState.waylandIdleInhibited 30 onClicked: InhibitorState.waylandIdleInhibited = !InhibitorState.waylandIdleInhibited
30 31
diff --git a/accounts/gkleen@sif/shell/quickshell/WorkspaceSwitcher.qml b/accounts/gkleen@sif/shell/quickshell/WorkspaceSwitcher.qml
index 4cbebcc9..2d3aca1b 100644
--- a/accounts/gkleen@sif/shell/quickshell/WorkspaceSwitcher.qml
+++ b/accounts/gkleen@sif/shell/quickshell/WorkspaceSwitcher.qml
@@ -149,6 +149,8 @@ Row {
149 WrapperMouseArea { 149 WrapperMouseArea {
150 id: windowMouseArea 150 id: windowMouseArea
151 151
152 required property int index
153 required property var modelData
152 property var windowData: modelData 154 property var windowData: modelData
153 155
154 hoverEnabled: true 156 hoverEnabled: true
@@ -164,12 +166,11 @@ Row {
164 WrapperRectangle { 166 WrapperRectangle {
165 color: windowMouseArea.containsMouse ? "#33808080" : "transparent"; 167 color: windowMouseArea.containsMouse ? "#33808080" : "transparent";
166 168
167 anchors.fill: parent
168
169 WrapperItem { 169 WrapperItem {
170 anchors.fill: parent 170 rightMargin: 8
171 171 leftMargin: 8
172 margin: 4 172 topMargin: windowMouseArea.index == 0 ? 8 : 4
173 bottomMargin: windowMouseArea.index == windowsModel.values.length - 1 ? 8 : 4
173 174
174 Text { 175 Text {
175 id: windowLabel 176 id: windowLabel
diff --git a/accounts/gkleen@sif/shell/quickshell/WorktimeWidget.qml b/accounts/gkleen@sif/shell/quickshell/WorktimeWidget.qml
new file mode 100644
index 00000000..04bcc581
--- /dev/null
+++ b/accounts/gkleen@sif/shell/quickshell/WorktimeWidget.qml
@@ -0,0 +1,120 @@
1import QtQml
2import Quickshell
3import Quickshell.Io
4import QtQuick
5import Quickshell.Widgets
6
7Item {
8 id: root
9
10 required property string command
11 property var state: null
12
13 height: parent.height
14 width: label.contentWidth + 8
15 anchors.verticalCenter: parent.verticalCenter
16
17 Process {
18 id: process
19 running: true
20 command: [ @worktime@, root.command, "--waybar" ]
21 stdout: StdioCollector {
22 id: processCollector
23 onStreamFinished: {
24 try {
25 root.state = JSON.parse(processCollector.text);
26 } catch (e) {
27 console.warn("Worktime: Failed to parse output:", processCollector.text, e);
28 }
29 }
30 }
31 }
32
33 Timer {
34 running: true
35 interval: 60
36 repeat: true
37 onTriggered: process.running = true
38 }
39
40 WrapperMouseArea {
41 id: mouseArea
42
43 anchors.fill: parent
44
45 enabled: true
46 hoverEnabled: true
47
48 Item {
49 anchors.fill: parent
50
51 Text {
52 id: label
53
54 anchors.centerIn: parent
55
56 visible: root.state?.text ?? false
57 text: root.state?.text ?? ""
58
59 font.pointSize: 10
60 font.family: "Fira Sans"
61 color: {
62 if (root.state?.class == "running")
63 return "white";
64 if (root.state?.class == "over")
65 return "#f28a21";
66 return "#555";
67 }
68 }
69 }
70 }
71
72 PopupWindow {
73 id: tooltip
74
75 property bool nextVisible: Boolean(root.state?.tooltip ?? false) && (mouseArea.containsMouse || tooltipMouseArea.containsMouse)
76
77 anchor {
78 item: mouseArea
79 edges: Edges.Bottom | Edges.Left
80 }
81 visible: false
82
83 onNextVisibleChanged: hangTimer.restart()
84
85 Timer {
86 id: hangTimer
87 interval: 100
88 onTriggered: tooltip.visible = tooltip.nextVisible
89 }
90
91 implicitWidth: tooltipText.contentWidth + 16
92 implicitHeight: tooltipText.contentHeight + 16
93 color: "black"
94
95 WrapperMouseArea {
96 id: tooltipMouseArea
97
98 enabled: true
99 hoverEnabled: true
100
101 anchors.fill: parent
102
103 Item {
104 anchors.fill: parent
105
106 Text {
107 id: tooltipText
108
109 anchors.centerIn: parent
110
111 font.pointSize: 10
112 font.family: "Fira Sans"
113 color: "white"
114
115 text: root.state?.tooltip ?? ""
116 }
117 }
118 }
119 }
120}
diff --git a/accounts/gkleen@sif/shell/quickshell/shell.qml b/accounts/gkleen@sif/shell/quickshell/shell.qml
index 693d741f..10c2eff6 100644
--- a/accounts/gkleen@sif/shell/quickshell/shell.qml
+++ b/accounts/gkleen@sif/shell/quickshell/shell.qml
@@ -20,7 +20,8 @@ ShellRoot {
20 screen: screenScope.modelData 20 screen: screenScope.modelData
21 21
22 WlrLayershell.layer: WlrLayer.Background 22 WlrLayershell.layer: WlrLayer.Background
23 WlrLayershell.exclusionMode: ExclusionMode.Ignore 23 WlrLayershell.namespace: "background"
24 exclusionMode: ExclusionMode.Ignore
24 25
25 anchors.top: true 26 anchors.top: true
26 anchors.bottom: true 27 anchors.bottom: true