pwr_tray 1.0.2__tar.gz → 1.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/PKG-INFO +35 -22
  2. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/README.md +34 -21
  3. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/SwayIdleMgr.py +24 -16
  4. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/main.py +82 -49
  5. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pyproject.toml +1 -1
  6. pwr_tray-1.0.4/runner +19 -0
  7. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/.gitignore +0 -0
  8. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/LICENSE +0 -0
  9. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/images/pwr-tray-screenshot.png +0 -0
  10. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/IniTool.py +0 -0
  11. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/Utils.py +0 -0
  12. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/YamlDump.py +0 -0
  13. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/__init__.py +0 -0
  14. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/FullSun-v03.svg +0 -0
  15. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/GoingDown-v03.svg +0 -0
  16. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/PlayingNow-v03.svg +0 -0
  17. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/RisingMoon-v03.svg +0 -0
  18. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/SetA/pwr-inh-v03.svg +0 -0
  19. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/SetA/pwr-no-sleep-v03.svg +0 -0
  20. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/SetA/pwr-uninh-v03.svg +0 -0
  21. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/SetB/LoBattery-v03.svg +0 -0
  22. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/SetB/LockOnlyMode-v03.svg +0 -0
  23. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/SetB/NormMode-v03.svg +0 -0
  24. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/SetC/New-LockOnly-v03.svg +0 -0
  25. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/SetC/New-LowBattery-v03.svg +0 -0
  26. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/SetC/New-NormMode-v03.svg +0 -0
  27. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/SetC/New-PresMode-v03.svg +0 -0
  28. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/SettingSun-v03.svg +0 -0
  29. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/StopSign-v03.svg +0 -0
  30. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/Unlocked-v03.svg +0 -0
  31. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/UnlockedMoon-v03.svg +0 -0
  32. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/__init__.py +0 -0
  33. {pwr_tray-1.0.2 → pwr_tray-1.0.4}/pwr_tray/resources/lockpaper.png +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pwr_tray
3
- Version: 1.0.2
3
+ Version: 1.0.4
4
4
  Summary: A GTK tray applet for power management for i3/sway/KDE
5
5
  Keywords: power,energy,GTK,applet,tray,kde,i3wm,sway
6
6
  Author-email: Joe Defen <joedef@google.com>
@@ -18,7 +18,7 @@ Project-URL: Homepage, https://github.com/joedefen/pwr-tray
18
18
 
19
19
  # pwr-tray
20
20
 
21
- `pwr-tray` is a GTK5 Tray Applet for Power/Energy Saving and System/DE Controls; currently supported/tested DEs are: i3wm, swaywm, and KDE on X11. `systemd` is required. The `pwr-tray` menu will look similar to:
21
+ `pwr-tray` is a PyQt5 Tray Applet for Power/Energy Saving and System/DE Controls; currently supported/tested DEs are: i3wm, swaywm, and KDE (X11 and Wayland). `systemd` is required. The `pwr-tray` menu will look similar to:
22
22
 
23
23
  <p align="center">
24
24
  <img src="https://github.com/joedefen/pwr-tray/blob/main/images/pwr-tray-screenshot.png?raw=true" alt="screenshot">
@@ -27,14 +27,14 @@ Project-URL: Homepage, https://github.com/joedefen/pwr-tray
27
27
 
28
28
  With just a right-click and a left-click, you can do most operations such as change to Presentation Mode, change screen lock and sleep timeouts, log off, lock and blank your monitors, and more. The `pwr-tray` icon changes based on state:
29
29
 
30
- * <img src="https://github.com/joedefen/pwr-tray/blob/main/src/pwr_tray/resources/FullSun-v03.svg?raw=true" alt="FullSun" width="24" height="24"> Presentation Mode (i.e., the full sun)
31
- * <img src="https://github.com/joedefen/pwr-tray/blob/main/src/pwr_tray/resources/SettingSun-v03.svg?raw=true" alt="SettingSun" width="24" height="24"> SleepAfterLock Mode (i.e., the setting sun)
32
- * <img src="https://github.com/joedefen/pwr-tray/blob/main/src/pwr_tray/resources/RisingMoon-v03.svg?raw=true" alt="RisingMoon" width="24" height="24"> SleepAfterLock Mode and Locking Screen Soon
33
- * <img src="https://github.com/joedefen/pwr-tray/blob/main/src/pwr_tray/resources/Unlocked-v03.svg?raw=true" alt="Unlocked" width="24" height="24"> LockOnly Mode (i.e., the unlocked lock)
34
- * <img src="https://github.com/joedefen/pwr-tray/blob/main/src/pwr_tray/resources/UnlockedMoon-v03.svg?raw=true" alt="UnlockedMoon" width="24" height="24"> LockOnly Mode and Locking Screen Soon
35
- * <img src="https://github.com/joedefen/pwr-tray/blob/main/src/pwr_tray/resources/GoingDown-v03.svg?raw=true" alt="GoingDown" width="24" height="24"> LowBattery State (going down).
36
- * <img src="https://github.com/joedefen/pwr-tray/blob/main/src/pwr_tray/resources/PlayingNow-v03.svg?raw=true" alt="PlayingNow" width="24" height="24"> Inhibited by playing media.
37
- * <img src="https://github.com/joedefen/pwr-tray/blob/main/src/pwr_tray/resources/StopSign-v03.svg?raw=true" alt="StopSign" width="24" height="24"> Inhibited by systemd inhibitors.
30
+ * <img src="https://github.com/joedefen/pwr-tray/blob/main/pwr_tray/resources/FullSun-v03.svg?raw=true" alt="FullSun" width="24" height="24"> Presentation Mode (i.e., the full sun)
31
+ * <img src="https://github.com/joedefen/pwr-tray/blob/main/pwr_tray/resources/SettingSun-v03.svg?raw=true" alt="SettingSun" width="24" height="24"> SleepAfterLock Mode (i.e., the setting sun)
32
+ * <img src="https://github.com/joedefen/pwr-tray/blob/main/pwr_tray/resources/RisingMoon-v03.svg?raw=true" alt="RisingMoon" width="24" height="24"> SleepAfterLock Mode and Locking Screen Soon
33
+ * <img src="https://github.com/joedefen/pwr-tray/blob/main/pwr_tray/resources/Unlocked-v03.svg?raw=true" alt="Unlocked" width="24" height="24"> LockOnly Mode (i.e., the unlocked lock)
34
+ * <img src="https://github.com/joedefen/pwr-tray/blob/main/pwr_tray/resources/UnlockedMoon-v03.svg?raw=true" alt="UnlockedMoon" width="24" height="24"> LockOnly Mode and Locking Screen Soon
35
+ * <img src="https://github.com/joedefen/pwr-tray/blob/main/pwr_tray/resources/GoingDown-v03.svg?raw=true" alt="GoingDown" width="24" height="24"> LowBattery State (going down).
36
+ * <img src="https://github.com/joedefen/pwr-tray/blob/main/pwr_tray/resources/PlayingNow-v03.svg?raw=true" alt="PlayingNow" width="24" height="24"> Inhibited by playing media.
37
+ * <img src="https://github.com/joedefen/pwr-tray/blob/main/pwr_tray/resources/StopSign-v03.svg?raw=true" alt="StopSign" width="24" height="24"> Inhibited by systemd inhibitors.
38
38
 
39
39
  ---
40
40
 
@@ -45,31 +45,40 @@ With just a right-click and a left-click, you can do most operations such as cha
45
45
  * Shows system-level commands (DE dependent) that must be installed if missing. Note:
46
46
  * `systemctl` is always required.
47
47
  * Optionally, install `playerctl` if you wish playing media to inhibit screen saving and sleeping.
48
- * If you find you are missing the QT5 foundation, then you'll need to install that; examples:
49
- * `sudo apt install qt5-default` # if debian based
50
- * `sudo pacman -S qt5-base` # if arch based
51
- * `sudo dnf install qt5-qtbase` # if fedora based
48
+ * If you find you are missing PyQt5, then you'll need to install it; examples:
49
+ * `sudo apt install python3-pyqt5` # if debian based
50
+ * `sudo pacman -S python-pyqt5` # if arch based
51
+ * `sudo dnf install python3-qt5` # if fedora based
52
52
 
53
53
  * Then, follow the "Per-DE Specific Notes" below to ensure proper operation. To just kick the tires, you can defer this until ready to go forward.
54
54
  * Read the other sections for customization and everyday use.
55
55
  * From the CLI, you can start/restart pwr-tray in the background with `setsid pwr-tray`; typically, you will "autostart" `pwr-tray` when you log in however your DE/WM manages autostarts.
56
- * `pwr-tray -e` edits the config file (`~/.config/pwr-ini/config.ini`)
57
- * `pwr-tray -f` tails the log file (`~/.config/pwr-ini/debug.log`)
56
+
57
+ ### Command Line Options
58
+ | Option | Description |
59
+ |--------|-------------|
60
+ | `-o`, `--stdout` | Log to stdout (in addition to the log file); useful for debugging from a terminal. |
61
+ | `-D`, `--debug` | Enable debug mode (more frequent/elaborate logging); overrides the `debug_mode` config setting. |
62
+ | `-q`, `--quick` | Quick mode: sets lock and sleep timeouts to 1 minute and runs double-time (timers expire in 30s wall clock). Useful for testing. |
63
+ | `-e`, `--edit-config` | Open `~/.config/pwr-tray/config.ini` in `$EDITOR` (default: `vim`). |
64
+ | `-f`, `--follow-log` | Tail the log file (`~/.config/pwr-tray/debug.log`). |
65
+
66
+ For initial setup and troubleshooting, `pwr-tray -D -o` is a good starting point.
58
67
 
59
68
  ---
60
69
 
61
70
  ### HowTo Use pwr-tray
62
- Open the `pwr-tray' menu with a right-click. Then left-click a line to have an effect ...
71
+ Open the `pwr-tray` menu with a right-click. Then left-click a line to have an effect ...
63
72
 
64
73
  Choose from three *major power modes* (to control the effects of timeouts):
65
74
  - **🅟 Presentation ⮜** - Keeps the screen unlocked/on and system up.
66
75
  - **🅛 LockOnly ⮜** - Keeps the system up, but the screen may lock.
67
76
  - **🅢 SleepAfterLock ⮜** - Allows screen locking and system to go down (the "normal" mode).
68
77
 
69
- Ory choose from various locking/blanking/DE operations:
78
+ Or choose from various locking/blanking/DE operations:
70
79
  - **▷ Lock Screen** - locks the screen immediately.
71
80
  - **▷ Blank Monitors** - blanks the screen after locking the screen.
72
- - **▷ Reload i3** - various DE-dependent actions.
81
+ - **▷ Reload** - various DE-dependent actions (reload WM config, etc.).
73
82
  - **▷ Log Off** - terminate your user session.
74
83
 
75
84
  Or choose a new *system state*:
@@ -110,7 +119,8 @@ Or act on the applet itself:
110
119
  Here are the current 'Settings' defaults with explanation.
111
120
  ```
112
121
  [Settings]
113
- i3lock_args = -t -i ./lockpaper.png # arguments when running i3lock for wallpaper
122
+ i3lock_args = -t -i ./lockpaper.png # extra arguments for i3lock
123
+ swaylock_args = -i ./lockpaper.png # extra arguments for swaylock
114
124
  debug_mode = False # more frequent and elaborate logging
115
125
  power_down = False # power down (rather than suspend)
116
126
  turn_off_monitors = False # turn off monitors after locking screen
@@ -159,11 +169,14 @@ bindsym $mod+Escape exec --no-startup-id $screenlock # create shortcut to lock
159
169
  ### sway Specific Notes
160
170
  * Uninstall or disable all competing energy saving programs (e.g., `swayidle`, `xfce4-power-manager`, etc.) when running `sway` whether started by `systemd` or `sway/config` or whatever.
161
171
  * **NOTE**: on `sway`, `pwr-tray` cannot read the idle time and do its usual micromanagement; instead, it runs a `swayidle` command whose arguments may vary with your settings.
162
- * Edit `/etc/system/logind.conf` and uncomment `HandlePowerKey=` and `HandleLidSwitch=`, and set each action to `suspend`; then either reboot or restart `systemd-logind`. That enables the ever-running `swayidle` to handle the suspend / resume events.
172
+ * Edit `/etc/systemd/logind.conf` and uncomment `HandlePowerKey=` and `HandleLidSwitch=`, and set each action to `suspend`; then either reboot or restart `systemd-logind`. That enables the ever-running `swayidle` to handle the suspend / resume events.
163
173
  * Again, find a way to start `pwr-tray`; perhaps adding to sway's config: `exec_always --no-startup-id sleep 2 && ~/.local/bin/pwr-tray`; a delay may be required to let the tray initialize.
164
174
 
165
- ### KDE (X11) Specific Notes
175
+ ### KDE Specific Notes
166
176
  * In Settings/Energy Saving, disable "Screen Energy Saving", "Suspend session", etc., except keep the "Button events handling" and make it as you wish (e.g., "When power button pressed", "Sleep").
167
177
  * In Settings/AutoStart, add the full path of `~/.local/bin/pwr-tray`.
178
+ * `qdbus` (or `qdbus6` on Plasma 6) is required; `pwr-tray` auto-detects which is available.
179
+ * On **KDE Wayland**, `swayidle` is required (install it if missing). `pwr-tray` manages `swayidle` for idle timeout handling since KDE Wayland does not expose idle time via D-Bus. Locking uses `loginctl lock-session`.
180
+ * On **KDE X11**, idle time is read via `xprintidle` and screen locking uses `loginctl lock-session`.
168
181
 
169
182
 
@@ -1,6 +1,6 @@
1
1
  # pwr-tray
2
2
 
3
- `pwr-tray` is a GTK5 Tray Applet for Power/Energy Saving and System/DE Controls; currently supported/tested DEs are: i3wm, swaywm, and KDE on X11. `systemd` is required. The `pwr-tray` menu will look similar to:
3
+ `pwr-tray` is a PyQt5 Tray Applet for Power/Energy Saving and System/DE Controls; currently supported/tested DEs are: i3wm, swaywm, and KDE (X11 and Wayland). `systemd` is required. The `pwr-tray` menu will look similar to:
4
4
 
5
5
  <p align="center">
6
6
  <img src="https://github.com/joedefen/pwr-tray/blob/main/images/pwr-tray-screenshot.png?raw=true" alt="screenshot">
@@ -9,14 +9,14 @@
9
9
 
10
10
  With just a right-click and a left-click, you can do most operations such as change to Presentation Mode, change screen lock and sleep timeouts, log off, lock and blank your monitors, and more. The `pwr-tray` icon changes based on state:
11
11
 
12
- * <img src="https://github.com/joedefen/pwr-tray/blob/main/src/pwr_tray/resources/FullSun-v03.svg?raw=true" alt="FullSun" width="24" height="24"> Presentation Mode (i.e., the full sun)
13
- * <img src="https://github.com/joedefen/pwr-tray/blob/main/src/pwr_tray/resources/SettingSun-v03.svg?raw=true" alt="SettingSun" width="24" height="24"> SleepAfterLock Mode (i.e., the setting sun)
14
- * <img src="https://github.com/joedefen/pwr-tray/blob/main/src/pwr_tray/resources/RisingMoon-v03.svg?raw=true" alt="RisingMoon" width="24" height="24"> SleepAfterLock Mode and Locking Screen Soon
15
- * <img src="https://github.com/joedefen/pwr-tray/blob/main/src/pwr_tray/resources/Unlocked-v03.svg?raw=true" alt="Unlocked" width="24" height="24"> LockOnly Mode (i.e., the unlocked lock)
16
- * <img src="https://github.com/joedefen/pwr-tray/blob/main/src/pwr_tray/resources/UnlockedMoon-v03.svg?raw=true" alt="UnlockedMoon" width="24" height="24"> LockOnly Mode and Locking Screen Soon
17
- * <img src="https://github.com/joedefen/pwr-tray/blob/main/src/pwr_tray/resources/GoingDown-v03.svg?raw=true" alt="GoingDown" width="24" height="24"> LowBattery State (going down).
18
- * <img src="https://github.com/joedefen/pwr-tray/blob/main/src/pwr_tray/resources/PlayingNow-v03.svg?raw=true" alt="PlayingNow" width="24" height="24"> Inhibited by playing media.
19
- * <img src="https://github.com/joedefen/pwr-tray/blob/main/src/pwr_tray/resources/StopSign-v03.svg?raw=true" alt="StopSign" width="24" height="24"> Inhibited by systemd inhibitors.
12
+ * <img src="https://github.com/joedefen/pwr-tray/blob/main/pwr_tray/resources/FullSun-v03.svg?raw=true" alt="FullSun" width="24" height="24"> Presentation Mode (i.e., the full sun)
13
+ * <img src="https://github.com/joedefen/pwr-tray/blob/main/pwr_tray/resources/SettingSun-v03.svg?raw=true" alt="SettingSun" width="24" height="24"> SleepAfterLock Mode (i.e., the setting sun)
14
+ * <img src="https://github.com/joedefen/pwr-tray/blob/main/pwr_tray/resources/RisingMoon-v03.svg?raw=true" alt="RisingMoon" width="24" height="24"> SleepAfterLock Mode and Locking Screen Soon
15
+ * <img src="https://github.com/joedefen/pwr-tray/blob/main/pwr_tray/resources/Unlocked-v03.svg?raw=true" alt="Unlocked" width="24" height="24"> LockOnly Mode (i.e., the unlocked lock)
16
+ * <img src="https://github.com/joedefen/pwr-tray/blob/main/pwr_tray/resources/UnlockedMoon-v03.svg?raw=true" alt="UnlockedMoon" width="24" height="24"> LockOnly Mode and Locking Screen Soon
17
+ * <img src="https://github.com/joedefen/pwr-tray/blob/main/pwr_tray/resources/GoingDown-v03.svg?raw=true" alt="GoingDown" width="24" height="24"> LowBattery State (going down).
18
+ * <img src="https://github.com/joedefen/pwr-tray/blob/main/pwr_tray/resources/PlayingNow-v03.svg?raw=true" alt="PlayingNow" width="24" height="24"> Inhibited by playing media.
19
+ * <img src="https://github.com/joedefen/pwr-tray/blob/main/pwr_tray/resources/StopSign-v03.svg?raw=true" alt="StopSign" width="24" height="24"> Inhibited by systemd inhibitors.
20
20
 
21
21
  ---
22
22
 
@@ -27,31 +27,40 @@ With just a right-click and a left-click, you can do most operations such as cha
27
27
  * Shows system-level commands (DE dependent) that must be installed if missing. Note:
28
28
  * `systemctl` is always required.
29
29
  * Optionally, install `playerctl` if you wish playing media to inhibit screen saving and sleeping.
30
- * If you find you are missing the QT5 foundation, then you'll need to install that; examples:
31
- * `sudo apt install qt5-default` # if debian based
32
- * `sudo pacman -S qt5-base` # if arch based
33
- * `sudo dnf install qt5-qtbase` # if fedora based
30
+ * If you find you are missing PyQt5, then you'll need to install it; examples:
31
+ * `sudo apt install python3-pyqt5` # if debian based
32
+ * `sudo pacman -S python-pyqt5` # if arch based
33
+ * `sudo dnf install python3-qt5` # if fedora based
34
34
 
35
35
  * Then, follow the "Per-DE Specific Notes" below to ensure proper operation. To just kick the tires, you can defer this until ready to go forward.
36
36
  * Read the other sections for customization and everyday use.
37
37
  * From the CLI, you can start/restart pwr-tray in the background with `setsid pwr-tray`; typically, you will "autostart" `pwr-tray` when you log in however your DE/WM manages autostarts.
38
- * `pwr-tray -e` edits the config file (`~/.config/pwr-ini/config.ini`)
39
- * `pwr-tray -f` tails the log file (`~/.config/pwr-ini/debug.log`)
38
+
39
+ ### Command Line Options
40
+ | Option | Description |
41
+ |--------|-------------|
42
+ | `-o`, `--stdout` | Log to stdout (in addition to the log file); useful for debugging from a terminal. |
43
+ | `-D`, `--debug` | Enable debug mode (more frequent/elaborate logging); overrides the `debug_mode` config setting. |
44
+ | `-q`, `--quick` | Quick mode: sets lock and sleep timeouts to 1 minute and runs double-time (timers expire in 30s wall clock). Useful for testing. |
45
+ | `-e`, `--edit-config` | Open `~/.config/pwr-tray/config.ini` in `$EDITOR` (default: `vim`). |
46
+ | `-f`, `--follow-log` | Tail the log file (`~/.config/pwr-tray/debug.log`). |
47
+
48
+ For initial setup and troubleshooting, `pwr-tray -D -o` is a good starting point.
40
49
 
41
50
  ---
42
51
 
43
52
  ### HowTo Use pwr-tray
44
- Open the `pwr-tray' menu with a right-click. Then left-click a line to have an effect ...
53
+ Open the `pwr-tray` menu with a right-click. Then left-click a line to have an effect ...
45
54
 
46
55
  Choose from three *major power modes* (to control the effects of timeouts):
47
56
  - **🅟 Presentation ⮜** - Keeps the screen unlocked/on and system up.
48
57
  - **🅛 LockOnly ⮜** - Keeps the system up, but the screen may lock.
49
58
  - **🅢 SleepAfterLock ⮜** - Allows screen locking and system to go down (the "normal" mode).
50
59
 
51
- Ory choose from various locking/blanking/DE operations:
60
+ Or choose from various locking/blanking/DE operations:
52
61
  - **▷ Lock Screen** - locks the screen immediately.
53
62
  - **▷ Blank Monitors** - blanks the screen after locking the screen.
54
- - **▷ Reload i3** - various DE-dependent actions.
63
+ - **▷ Reload** - various DE-dependent actions (reload WM config, etc.).
55
64
  - **▷ Log Off** - terminate your user session.
56
65
 
57
66
  Or choose a new *system state*:
@@ -92,7 +101,8 @@ Or act on the applet itself:
92
101
  Here are the current 'Settings' defaults with explanation.
93
102
  ```
94
103
  [Settings]
95
- i3lock_args = -t -i ./lockpaper.png # arguments when running i3lock for wallpaper
104
+ i3lock_args = -t -i ./lockpaper.png # extra arguments for i3lock
105
+ swaylock_args = -i ./lockpaper.png # extra arguments for swaylock
96
106
  debug_mode = False # more frequent and elaborate logging
97
107
  power_down = False # power down (rather than suspend)
98
108
  turn_off_monitors = False # turn off monitors after locking screen
@@ -141,10 +151,13 @@ bindsym $mod+Escape exec --no-startup-id $screenlock # create shortcut to lock
141
151
  ### sway Specific Notes
142
152
  * Uninstall or disable all competing energy saving programs (e.g., `swayidle`, `xfce4-power-manager`, etc.) when running `sway` whether started by `systemd` or `sway/config` or whatever.
143
153
  * **NOTE**: on `sway`, `pwr-tray` cannot read the idle time and do its usual micromanagement; instead, it runs a `swayidle` command whose arguments may vary with your settings.
144
- * Edit `/etc/system/logind.conf` and uncomment `HandlePowerKey=` and `HandleLidSwitch=`, and set each action to `suspend`; then either reboot or restart `systemd-logind`. That enables the ever-running `swayidle` to handle the suspend / resume events.
154
+ * Edit `/etc/systemd/logind.conf` and uncomment `HandlePowerKey=` and `HandleLidSwitch=`, and set each action to `suspend`; then either reboot or restart `systemd-logind`. That enables the ever-running `swayidle` to handle the suspend / resume events.
145
155
  * Again, find a way to start `pwr-tray`; perhaps adding to sway's config: `exec_always --no-startup-id sleep 2 && ~/.local/bin/pwr-tray`; a delay may be required to let the tray initialize.
146
156
 
147
- ### KDE (X11) Specific Notes
157
+ ### KDE Specific Notes
148
158
  * In Settings/Energy Saving, disable "Screen Energy Saving", "Suspend session", etc., except keep the "Button events handling" and make it as you wish (e.g., "When power button pressed", "Sleep").
149
159
  * In Settings/AutoStart, add the full path of `~/.local/bin/pwr-tray`.
160
+ * `qdbus` (or `qdbus6` on Plasma 6) is required; `pwr-tray` auto-detects which is available.
161
+ * On **KDE Wayland**, `swayidle` is required (install it if missing). `pwr-tray` manages `swayidle` for idle timeout handling since KDE Wayland does not expose idle time via D-Bus. Locking uses `loginctl lock-session`.
162
+ * On **KDE X11**, idle time is read via `xprintidle` and screen locking uses `loginctl lock-session`.
150
163
 
@@ -16,28 +16,36 @@ from types import SimpleNamespace
16
16
  from pwr_tray.Utils import prt
17
17
 
18
18
  class SwayIdleManager:
19
- """ Class to manage 'swayidle' """
19
+ """ Class to manage 'swayidle' for sway and KDE Wayland """
20
20
  def __init__(self, applet):
21
21
  self.process = None
22
22
  self.applet = applet
23
23
  self.current_cmd = ''
24
24
  # we construct the sway idle from these clauses which various
25
25
  # substitutions.
26
- self.clauses = SimpleNamespace(
27
- leader="""exec swayidle""",
28
- locker=""" timeout [lock_s] '[screenlock] [lockopts]'""",
29
- blanker=""" timeout [blank_s] 'swaymsg "output * dpms off"'""",
30
- sleeper=""" timeout [sleep_s] 'systemctl suspend'""",
31
- # dimmer="""\\\n timeout [dim_s] 'brightnessctl set 50%'""", # perms?
32
- before_sleep=""" before-sleep '[screenlock] [lockopts]'""",
33
- after_resume=""" after-resume '[unblank]'""",
34
- # + """ 'pgrep -x copyq || copyq --start-server hide;"""
35
- # + """ pgrep -x nm-applet || nm-applet [undim][dpmsOn]'""",
36
- # + """ pgrep -x nm-applet || nm-applet [unblank]'""",
37
- # undim = """; brightnessctl set 100%""",
38
- screenlock = """pkill swaylock ; exec swaylock --ignore-empty-password --show-failed-attempts""",
39
- unblank='''; swaymsg "output * dpms on"''',
40
- )
26
+ if applet.graphical == 'kde-wayland':
27
+ locker = applet.variables.get('locker', 'loginctl lock-session')
28
+ self.clauses = SimpleNamespace(
29
+ leader="""exec swayidle""",
30
+ locker=f""" timeout [lock_s] '{locker}'""",
31
+ blanker="",
32
+ sleeper=""" timeout [sleep_s] 'systemctl suspend'""",
33
+ before_sleep=f""" before-sleep '{locker}'""",
34
+ after_resume="",
35
+ screenlock=locker,
36
+ unblank='',
37
+ )
38
+ else:
39
+ self.clauses = SimpleNamespace(
40
+ leader="""exec swayidle""",
41
+ locker=""" timeout [lock_s] '[screenlock] [lockopts]'""",
42
+ blanker=""" timeout [blank_s] 'swaymsg "output * dpms off"'""",
43
+ sleeper=""" timeout [sleep_s] 'systemctl suspend'""",
44
+ before_sleep=""" before-sleep '[screenlock] [lockopts]'""",
45
+ after_resume=""" after-resume '[unblank]'""",
46
+ screenlock = """pkill swaylock ; exec swaylock --ignore-empty-password --show-failed-attempts""",
47
+ unblank='''; swaymsg "output * dpms on"''',
48
+ )
41
49
  self.kill_other_swayidle()
42
50
 
43
51
  @staticmethod
@@ -71,7 +71,6 @@ class PwrTray:
71
71
  if is_wayland:
72
72
  env = 'kde-wayland'
73
73
  prt(f'ENV: {env} {desktop_session=} {wayland_display=}')
74
- assert False, f'unsupported env: {env}'
75
74
  return 'kde-wayland', is_wayland
76
75
  if display:
77
76
  env = 'kde-x11'
@@ -101,6 +100,7 @@ class PwrTray:
101
100
  'monitors_off': '',
102
101
  'locker': '',
103
102
  'get_idle_ms': '',
103
+ 'get_idle_s': '',
104
104
  'reset_idle': '',
105
105
  'reload_wm': '',
106
106
  'restart_wm': '',
@@ -137,29 +137,9 @@ class PwrTray:
137
137
  'restart_wm': 'killall plasmashell && kstart5 plasmashell && sleep 3 && pwr-tray',
138
138
  'must_haves': 'loginctl qdbus'.split(),
139
139
  }, 'kde-wayland': {
140
- # sudo apt-get install xdg-utils
141
- 'reset_idle': 'qdbus org.freedesktop.ScreenSaver /ScreenSaver SimulateUserActivity',
142
- # gdbus introspect --session --dest org.gnome.SessionManager
143
- # --object-path /org/gnome/SessionManager
144
- # gdbus call --session --dest org.gnome.SessionManager
145
- # --object-path /org/gnome/SessionManager
146
- # --method org.gnome.SessionManager.GetIdleTime
147
- # from pydbus import SessionBus
148
- # import time
149
- # def get_idle_time():
150
- # bus = SessionBus()
151
- # screensaver = bus.get("org.freedesktop.ScreenSaver")
152
- # # The GetSessionIdleTime method returns the idle time in seconds.
153
- # idle_time = screensaver.GetSessionIdleTime()
154
- # return idle_time
155
- # if __name__ == "__main__":
156
- # while True:
157
- # idle_time = get_idle_time()
158
- # print(f"Idle time in seconds: {idle_time}")
159
- # time.sleep(5)
160
140
  'locker': 'loginctl lock-session',
161
- 'must_haves': 'loginctl qdbus'.split(),
162
-
141
+ 'logoff': 'qdbus org.kde.ksmserver /KSMServer org.kde.KSMServerInterface.logout 0 0 0',
142
+ 'must_haves': 'loginctl swayidle'.split(),
163
143
  }, 'gnome-x11': {
164
144
 
165
145
  }, 'gnome-wayland': {
@@ -260,10 +240,21 @@ class PwrTray:
260
240
  if shutil.which(must_have) is None:
261
241
  dont_haves.append(must_have)
262
242
  assert not dont_haves, f'commands NOT on $PATH: {dont_haves}'
243
+
244
+ if self.graphical in ('kde-x11', 'kde-wayland'):
245
+ qdbus_cmd = shutil.which('qdbus') or shutil.which('qdbus6')
246
+ assert qdbus_cmd, 'neither qdbus nor qdbus6 found on $PATH'
247
+ qdbus_name = os.path.basename(qdbus_cmd)
248
+ if qdbus_name != 'qdbus':
249
+ for key, val in list(self.variables.items()):
250
+ if isinstance(val, str) and 'qdbus ' in val:
251
+ self.variables[key] = val.replace('qdbus ', f'{qdbus_name} ')
252
+
263
253
  self.has_playerctl = bool(shutil.which('playerctl'))
264
254
 
265
255
 
266
- self.idle_manager = SwayIdleManager(self) if self.graphical == 'sway' else None
256
+ self.idle_manager = (SwayIdleManager(self)
257
+ if self.graphical in ('sway', 'kde-wayland') else None)
267
258
 
268
259
  self.menu_items = []
269
260
  self.menu = None
@@ -271,6 +262,9 @@ class PwrTray:
271
262
  self.tray_icon.activated.connect(self.on_tray_icon_activated)
272
263
  if self.idle_manager:
273
264
  self.idle_manager_start()
265
+ self._resume_proc = self._start_resume_monitor()
266
+ self._resume_buf = b''
267
+
274
268
  self.timer = QTimer()
275
269
  self.timer.setInterval(100) # 100 is initial ... gets recomputed
276
270
  self.timer.timeout.connect(self.on_timeout)
@@ -362,10 +356,18 @@ class PwrTray:
362
356
  def update_running_idle_s(self):
363
357
  """ Update the running idle seconds (called after each regular timeout) """
364
358
  cmd = self.variables['get_idle_ms']
359
+ scale = 1
360
+ if not cmd:
361
+ cmd = self.variables.get('get_idle_s', '')
362
+ scale = 1000
365
363
  if cmd:
366
- xidle_ms = int(subprocess.check_output(cmd.split()).strip())
367
- xidle_ms *= 2 if self.quick else 1 # time warp
368
- self.running_idle_s = round(xidle_ms/1000, 3)
364
+ try:
365
+ xidle = int(subprocess.check_output(cmd.split()).strip())
366
+ xidle_ms = xidle * scale
367
+ xidle_ms *= 2 if self.quick else 1 # time warp
368
+ self.running_idle_s = round(xidle_ms/1000, 3)
369
+ except Exception as e:
370
+ prt(f'WARN: idle time command failed: {e}')
369
371
 
370
372
  def DB(self):
371
373
  """ is debug on? """
@@ -499,9 +501,10 @@ class PwrTray:
499
501
  if self.DB():
500
502
  prt('DB', f'on_timeout() {self.loop=}/{self.loop_sample} ...')
501
503
  if not QSystemTrayIcon.isSystemTrayAvailable():
502
- prt('SystemTray is gone ... exiting')
503
- self.exit_wm(None)
504
+ prt('SystemTray is gone ... restarting')
505
+ self.restart_self(None)
504
506
 
507
+ self._check_resume()
505
508
  self.reconfig()
506
509
  if self.idle_manager:
507
510
  self.idle_manager.checkup()
@@ -534,8 +537,8 @@ class PwrTray:
534
537
  prt(emit)
535
538
 
536
539
  if emode in ('Presentation',) or self.was_inhibited:
537
- if 'sway' in self.graphical:
538
- self.reset_xidle_ms() # we don't know when
540
+ if self.idle_manager:
541
+ self.reset_xidle_ms() # idle_manager handles timeouts
539
542
  elif self.running_idle_s > min(50, lock_secs*0.40):
540
543
  self.reset_xidle_ms() # we don't know when
541
544
 
@@ -645,7 +648,11 @@ class PwrTray:
645
648
  self.menu.addAction(item)
646
649
  self.menu_items.append(item)
647
650
 
648
- self.menu = QMenu()
651
+ first_menu = self.menu is None
652
+ if first_menu:
653
+ self.menu = QMenu()
654
+ else:
655
+ self.menu.clear()
649
656
  self.menu_items = []
650
657
 
651
658
  if rows:
@@ -703,8 +710,9 @@ class PwrTray:
703
710
 
704
711
  add_item('↺ Restart this Applet', self.restart_self)
705
712
 
706
- self.tray_icon.setContextMenu(self.menu)
707
-
713
+ if first_menu:
714
+ self.tray_icon.setContextMenu(self.menu)
715
+
708
716
  if not self.tray_icon.isVisible():
709
717
  prt('self.tray_icon.isVisible() is False ... restarting app')
710
718
  time.sleep(0.5)
@@ -770,7 +778,9 @@ class PwrTray:
770
778
  if this:
771
779
  this.tray_icon.hide()
772
780
  PwrTray.save_picks()
773
- subprocess.Popen([sys.executable] + sys.argv)
781
+ project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
782
+ args = [sys.executable, '-m', 'pwr_tray.main'] + sys.argv[1:]
783
+ subprocess.Popen(args, cwd=project_root)
774
784
  os._exit(0)
775
785
 
776
786
  @staticmethod
@@ -795,6 +805,9 @@ class PwrTray:
795
805
  if this.graphical in ('i3', ):
796
806
  PwrTray.run_command('locker')
797
807
  PwrTray.run_command('suspend')
808
+ # systemctl suspend blocks until resume; restart to restore tray icon
809
+ prt('suspend: resumed, restarting applet...')
810
+ PwrTray.restart_self(None)
798
811
 
799
812
  @staticmethod
800
813
  def poweroff(_):
@@ -888,20 +901,39 @@ class PwrTray:
888
901
  this.save_picks()
889
902
  this.idle_manager_start()
890
903
 
891
- # Function to check for ACPI events
892
- @staticmethod
893
- def acpi_event_listener():
894
- acpi_pipe = subprocess.Popen(["acpi_listen"], stdout=subprocess.PIPE)
895
- for line in acpi_pipe.stdout:
896
- this = PwrTray.singleton
897
- if this and b"resume" in line:
898
- prt('acpi event:', line)
899
- # Reset idle timer
900
- this.reset_xidle_ms()
901
- elif this:
902
- prt('UNSELECTED acpi event:', line)
903
- # Reset idle timer
904
- this.reset_xidle_ms()
904
+ def _start_resume_monitor(self):
905
+ """Start dbus-monitor subprocess for resume detection (non-blocking)."""
906
+ try:
907
+ proc = subprocess.Popen(
908
+ ['dbus-monitor', '--system',
909
+ "type='signal',interface='org.freedesktop.login1.Manager',"
910
+ "member='PrepareForSleep'"],
911
+ stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
912
+ os.set_blocking(proc.stdout.fileno(), False)
913
+ prt('resume monitor: started')
914
+ return proc
915
+ except FileNotFoundError:
916
+ prt('WARN: dbus-monitor not found; resume detection disabled')
917
+ return None
918
+
919
+ def _check_resume(self):
920
+ """Poll dbus-monitor for resume signal (called from on_timeout)."""
921
+ if not self._resume_proc:
922
+ return
923
+ try:
924
+ chunk = os.read(self._resume_proc.stdout.fileno(), 4096)
925
+ if chunk:
926
+ self._resume_buf += chunk
927
+ if b'boolean false' in self._resume_buf:
928
+ prt('resume detected, restarting...')
929
+ self.restart_self(None)
930
+ # Prevent unbounded growth; keep tail for partial matches
931
+ if len(self._resume_buf) > 1024:
932
+ self._resume_buf = self._resume_buf[-512:]
933
+ except BlockingIOError:
934
+ pass
935
+ except OSError:
936
+ pass
905
937
  @staticmethod
906
938
  def goodbye(message=''):
907
939
  prt(f'ENDED {message}')
@@ -950,6 +982,7 @@ def main():
950
982
  atexit.register(PwrTray.goodbye)
951
983
 
952
984
 
985
+ ini_tool.update_config()
953
986
  if opts.debug:
954
987
  for selector in ini_tool.get_selectors():
955
988
  ini_tool.params_by_selector[selector].debug_mode = True # one-time override
@@ -4,7 +4,7 @@ build-backend = "flit_core.buildapi"
4
4
 
5
5
  [project]
6
6
  name = "pwr_tray"
7
- version = "1.0.2"
7
+ version = "1.0.4"
8
8
  description = "A GTK tray applet for power management for i3/sway/KDE"
9
9
  authors = [
10
10
  { name = "Joe Defen", email = "joedef@google.com" }
pwr_tray-1.0.4/runner ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ runner - Development wrapper for app
4
+ Located in the top-level app directory.
5
+ Allows running app from source for debugging with support for command-line arguments.
6
+
7
+ Usage:
8
+ ./runner {options-and-args}
9
+ ./runner --help (show all available options)
10
+ """
11
+
12
+ import runpy
13
+ import sys
14
+
15
+ if __name__ == '__main__':
16
+ # Set program name but preserve all command-line arguments
17
+ sys.argv[0] = 'pwr-tray'
18
+ # Run the dwipe.main module with alter_sys=True to propagate sys.argv
19
+ runpy.run_module('pwr_tray.main', run_name='__main__', alter_sys=True)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes