pwr_tray 1.0.2__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 (32) hide show
  1. pwr_tray-1.0.2/.gitignore +8 -0
  2. pwr_tray-1.0.2/LICENSE +21 -0
  3. pwr_tray-1.0.2/PKG-INFO +169 -0
  4. pwr_tray-1.0.2/README.md +150 -0
  5. pwr_tray-1.0.2/images/pwr-tray-screenshot.png +0 -0
  6. pwr_tray-1.0.2/pwr_tray/IniTool.py +193 -0
  7. pwr_tray-1.0.2/pwr_tray/SwayIdleMgr.py +139 -0
  8. pwr_tray-1.0.2/pwr_tray/Utils.py +162 -0
  9. pwr_tray-1.0.2/pwr_tray/YamlDump.py +163 -0
  10. pwr_tray-1.0.2/pwr_tray/__init__.py +0 -0
  11. pwr_tray-1.0.2/pwr_tray/main.py +974 -0
  12. pwr_tray-1.0.2/pwr_tray/resources/FullSun-v03.svg +81 -0
  13. pwr_tray-1.0.2/pwr_tray/resources/GoingDown-v03.svg +79 -0
  14. pwr_tray-1.0.2/pwr_tray/resources/PlayingNow-v03.svg +63 -0
  15. pwr_tray-1.0.2/pwr_tray/resources/RisingMoon-v03.svg +75 -0
  16. pwr_tray-1.0.2/pwr_tray/resources/SetA/pwr-inh-v03.svg +1 -0
  17. pwr_tray-1.0.2/pwr_tray/resources/SetA/pwr-no-sleep-v03.svg +1 -0
  18. pwr_tray-1.0.2/pwr_tray/resources/SetA/pwr-uninh-v03.svg +1 -0
  19. pwr_tray-1.0.2/pwr_tray/resources/SetB/LoBattery-v03.svg +698 -0
  20. pwr_tray-1.0.2/pwr_tray/resources/SetB/LockOnlyMode-v03.svg +18 -0
  21. pwr_tray-1.0.2/pwr_tray/resources/SetB/NormMode-v03.svg +645 -0
  22. pwr_tray-1.0.2/pwr_tray/resources/SetC/New-LockOnly-v03.svg +13 -0
  23. pwr_tray-1.0.2/pwr_tray/resources/SetC/New-LowBattery-v03.svg +13 -0
  24. pwr_tray-1.0.2/pwr_tray/resources/SetC/New-NormMode-v03.svg +13 -0
  25. pwr_tray-1.0.2/pwr_tray/resources/SetC/New-PresMode-v03.svg +13 -0
  26. pwr_tray-1.0.2/pwr_tray/resources/SettingSun-v03.svg +71 -0
  27. pwr_tray-1.0.2/pwr_tray/resources/StopSign-v03.svg +90 -0
  28. pwr_tray-1.0.2/pwr_tray/resources/Unlocked-v03.svg +116 -0
  29. pwr_tray-1.0.2/pwr_tray/resources/UnlockedMoon-v03.svg +121 -0
  30. pwr_tray-1.0.2/pwr_tray/resources/__init__.py +0 -0
  31. pwr_tray-1.0.2/pwr_tray/resources/lockpaper.png +0 -0
  32. pwr_tray-1.0.2/pyproject.toml +35 -0
@@ -0,0 +1,8 @@
1
+ .vscode/
2
+ __pycache__/
3
+ dist/
4
+ *.egg-info/
5
+ env/
6
+ pi-venv/
7
+ build/
8
+ pwr-tray-exe
pwr_tray-1.0.2/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Joe D
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,169 @@
1
+ Metadata-Version: 2.4
2
+ Name: pwr_tray
3
+ Version: 1.0.2
4
+ Summary: A GTK tray applet for power management for i3/sway/KDE
5
+ Keywords: power,energy,GTK,applet,tray,kde,i3wm,sway
6
+ Author-email: Joe Defen <joedef@google.com>
7
+ Requires-Python: >=3.8
8
+ Description-Content-Type: text/markdown
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: POSIX :: Linux
12
+ License-File: LICENSE
13
+ Requires-Dist: importlib-metadata; python_version<"3.8"
14
+ Requires-Dist: psutil>=5.9
15
+ Requires-Dist: PyQt5>=5.15
16
+ Project-URL: Bug Tracker, https://github.com/joedefen/pwr-tray/issues
17
+ Project-URL: Homepage, https://github.com/joedefen/pwr-tray
18
+
19
+ # pwr-tray
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:
22
+
23
+ <p align="center">
24
+ <img src="https://github.com/joedefen/pwr-tray/blob/main/images/pwr-tray-screenshot.png?raw=true" alt="screenshot">
25
+ </p>
26
+
27
+
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
+
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.
38
+
39
+ ---
40
+
41
+ ### HowTo Install and Start pwr-tray
42
+ * Basically: `pipx install pwr-tray` (exactly how depends on your installation and its state)
43
+ * Manually run as `pwr-tray -o`:
44
+ * Creates config (in `~/.config/pwr-tray/config.ini`).
45
+ * Shows system-level commands (DE dependent) that must be installed if missing. Note:
46
+ * `systemctl` is always required.
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
52
+
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
+ * Read the other sections for customization and everyday use.
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`)
58
+
59
+ ---
60
+
61
+ ### HowTo Use pwr-tray
62
+ Open the `pwr-tray' menu with a right-click. Then left-click a line to have an effect ...
63
+
64
+ Choose from three *major power modes* (to control the effects of timeouts):
65
+ - **🅟 Presentation ⮜** - Keeps the screen unlocked/on and system up.
66
+ - **🅛 LockOnly ⮜** - Keeps the system up, but the screen may lock.
67
+ - **🅢 SleepAfterLock ⮜** - Allows screen locking and system to go down (the "normal" mode).
68
+
69
+ Ory choose from various locking/blanking/DE operations:
70
+ - **▷ Lock Screen** - locks the screen immediately.
71
+ - **▷ Blank Monitors** - blanks the screen after locking the screen.
72
+ - **▷ Reload i3** - various DE-dependent actions.
73
+ - **▷ Log Off** - terminate your user session.
74
+
75
+ Or choose a new *system state*:
76
+ - **▼ Suspend System** - suspends the system immediately.
77
+ - **▼ Reboot System** - reboots the system immediately.
78
+ - **▼ Poweroff System** - power down the system immediately.
79
+
80
+ Next, you may see:
81
+ - **🗲 Plugged In** (or HiBattery or LoBattery). Shows the state of the battery.
82
+ - **♺ Chg Screen Idle: 15m->30m** - change the time to start the screen saver; each time clicked, it changes to the next choice.
83
+ - **♺ Chg System Idle: 5m->30m** - change the time to take the system down; clicking selects the next choice.
84
+ - **🎝 PlayerCtl** - shows the state (not installed, enabled, disabled); if installed, a click toggles whether playing media inhibits screen locking and sleeping.
85
+
86
+ Or act on the applet itself:
87
+ - **🖹 Edit Applet Config** - edit the applet's .ini file.
88
+ - **☓ Quit this Applet** - exit applet.
89
+ - **↺ Restart this Applet** - restart applet.
90
+
91
+
92
+ ---
93
+
94
+ ### Testing pwr-tray
95
+ - Running `pwr-tray --quick` reduces the lock and sleep timeout to 1 minute (although you can 'click' the current value to try others), and `--quick` runs double-time (so 1 minute timers expire in 30s per the wall clock).
96
+ - You can run in various modes, but the default, `SleepAfterLock`, exercises the most code paths.
97
+ - Then, ensure closing the lid, hitting the power button, etc., have the desired effects.
98
+ - To test systemd inhibits: create a test inhibit with `systemd-inhibit --why="Prevent sleep for demonstration" sleep infinity`
99
+ - To test Hi/Lo Battery states (only on a system w/o a battery), click the battery state which artificially changes to HiBattery or LoBattery states for testing behaviors in those states.
100
+
101
+ ---
102
+
103
+ ### HowTo Configure pwr-tray
104
+ - When the program is started w/o a `config.ini`, that file is created with defaults.
105
+ - It has three sections:
106
+ * **Settings**: The settings for when plugged in. Missing/invalid settings are inherited from the defaults. Here are the defaults:
107
+ * **HiBattery**: The settings for when on battery on and not a low battery condition. Missing/invalid settings are inherited from 'Settings'.
108
+ * **LoBattery**: The settings for when on battery in a low battery condition. Missing/invalid settings are inherited from 'Settings'.
109
+
110
+ Here are the current 'Settings' defaults with explanation.
111
+ ```
112
+ [Settings]
113
+ i3lock_args = -t -i ./lockpaper.png # arguments when running i3lock for wallpaper
114
+ debug_mode = False # more frequent and elaborate logging
115
+ power_down = False # power down (rather than suspend)
116
+ turn_off_monitors = False # turn off monitors after locking screen
117
+ lock_min_list = [15, 30] # lock minutes choices
118
+ sleep_min_list = [5, 30] # sleep minutes choices (after lock)
119
+ lo_battery_pct = 10 # define "low battery" state
120
+ gui_editor = geany # gui editor for .ini file
121
+ ```
122
+ **NOTES**:
123
+ * If you have issues with monitors failing to sleep or the system cannot wake when the monitors are off, then disable the `turn_off_monitors` feature.
124
+ * You can set `gui_editor = konsole -e vim`, for example, to use vim in a terminal window. If you don't have `geany` installed, then be sure to change `gui_editor`.
125
+ * `pwr-tray` changes directory to `~/.config/pwr-tray`.
126
+ * If its .ini file is missing, it is created and `lockpaper.png` is copied there too.
127
+ * Your picks of mode, timeouts, etc. are saved to disk when changed, and restored on the next start.
128
+ * Items may be absent depending on the mode and battery state.
129
+ - **NOTE**: when in LoBattery, SleepAfterLock becomes the effective mode. The icon will change per your selection and the battery state.
130
+
131
+ ---
132
+
133
+ ## Per-DE Specific Notes
134
+
135
+ ### i3wm Specific Notes
136
+ * Uninstall or disable all competing energy saving programs (e.g., `xscreensaver`, `xfce4-power-manager`, etc.) when running `i3` whether started by `systemd` or `i3/config` or whatever; defeat the X11 defaults somehow such as in `~/.config/i3/config`:
137
+ ```
138
+ exec --no-startup-id xset s off ; xset s noblank ; xset -dpms
139
+ ```
140
+ * Edit `/etc/systemd/logind.conf` and uncomment `HandlePowerKey=` and `HandleLidSwitch=`, set each action to `suspend`, and then either reboot or restart `systemd-logind`. That enables `xss-lock` to handle those keys.
141
+ * In your config, arrange for the power key (when set to suspend) to also have the system locked on power up with:
142
+ ```
143
+ set $screenlock i3lock -t -i ~/.config/pwr-tray/lockpaper.png --ignore-empty-password --show-failed-attempts
144
+ exec --no-startup-id xss-lock --transfer-sleep-lock -- $screenlock --nofork
145
+ bindsym XF86PowerOff exec --no-startup-id $screenlock && systemctl suspend
146
+ bindsym $mod+Escape exec --no-startup-id $screenlock # create shortcut to lock screen only
147
+
148
+ ```
149
+ * Finally, start your pwr-tray somehow. Below is a simplest case using `i3status`, but it may depend on your status bar:
150
+ ```
151
+ bar {
152
+ status_command i3status
153
+ tray_output primary
154
+ }
155
+ exec_always --no-startup-id ~/.local/bin/pwr-tray
156
+ ```
157
+ * If you use `polybar` for status, then it may be best to run `pwr-tray` from polybar's 'launch' script; e.g., `sleep 1.5 && setsid ~/.local/bin/pwr-tray &`; the delay may be need to allow time for the tray to become ready.
158
+
159
+ ### sway Specific Notes
160
+ * 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
+ * **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.
163
+ * 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
+
165
+ ### KDE (X11) Specific Notes
166
+ * 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
+ * In Settings/AutoStart, add the full path of `~/.local/bin/pwr-tray`.
168
+
169
+
@@ -0,0 +1,150 @@
1
+ # pwr-tray
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:
4
+
5
+ <p align="center">
6
+ <img src="https://github.com/joedefen/pwr-tray/blob/main/images/pwr-tray-screenshot.png?raw=true" alt="screenshot">
7
+ </p>
8
+
9
+
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
+
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.
20
+
21
+ ---
22
+
23
+ ### HowTo Install and Start pwr-tray
24
+ * Basically: `pipx install pwr-tray` (exactly how depends on your installation and its state)
25
+ * Manually run as `pwr-tray -o`:
26
+ * Creates config (in `~/.config/pwr-tray/config.ini`).
27
+ * Shows system-level commands (DE dependent) that must be installed if missing. Note:
28
+ * `systemctl` is always required.
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
34
+
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
+ * Read the other sections for customization and everyday use.
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`)
40
+
41
+ ---
42
+
43
+ ### HowTo Use pwr-tray
44
+ Open the `pwr-tray' menu with a right-click. Then left-click a line to have an effect ...
45
+
46
+ Choose from three *major power modes* (to control the effects of timeouts):
47
+ - **🅟 Presentation ⮜** - Keeps the screen unlocked/on and system up.
48
+ - **🅛 LockOnly ⮜** - Keeps the system up, but the screen may lock.
49
+ - **🅢 SleepAfterLock ⮜** - Allows screen locking and system to go down (the "normal" mode).
50
+
51
+ Ory choose from various locking/blanking/DE operations:
52
+ - **▷ Lock Screen** - locks the screen immediately.
53
+ - **▷ Blank Monitors** - blanks the screen after locking the screen.
54
+ - **▷ Reload i3** - various DE-dependent actions.
55
+ - **▷ Log Off** - terminate your user session.
56
+
57
+ Or choose a new *system state*:
58
+ - **▼ Suspend System** - suspends the system immediately.
59
+ - **▼ Reboot System** - reboots the system immediately.
60
+ - **▼ Poweroff System** - power down the system immediately.
61
+
62
+ Next, you may see:
63
+ - **🗲 Plugged In** (or HiBattery or LoBattery). Shows the state of the battery.
64
+ - **♺ Chg Screen Idle: 15m->30m** - change the time to start the screen saver; each time clicked, it changes to the next choice.
65
+ - **♺ Chg System Idle: 5m->30m** - change the time to take the system down; clicking selects the next choice.
66
+ - **🎝 PlayerCtl** - shows the state (not installed, enabled, disabled); if installed, a click toggles whether playing media inhibits screen locking and sleeping.
67
+
68
+ Or act on the applet itself:
69
+ - **🖹 Edit Applet Config** - edit the applet's .ini file.
70
+ - **☓ Quit this Applet** - exit applet.
71
+ - **↺ Restart this Applet** - restart applet.
72
+
73
+
74
+ ---
75
+
76
+ ### Testing pwr-tray
77
+ - Running `pwr-tray --quick` reduces the lock and sleep timeout to 1 minute (although you can 'click' the current value to try others), and `--quick` runs double-time (so 1 minute timers expire in 30s per the wall clock).
78
+ - You can run in various modes, but the default, `SleepAfterLock`, exercises the most code paths.
79
+ - Then, ensure closing the lid, hitting the power button, etc., have the desired effects.
80
+ - To test systemd inhibits: create a test inhibit with `systemd-inhibit --why="Prevent sleep for demonstration" sleep infinity`
81
+ - To test Hi/Lo Battery states (only on a system w/o a battery), click the battery state which artificially changes to HiBattery or LoBattery states for testing behaviors in those states.
82
+
83
+ ---
84
+
85
+ ### HowTo Configure pwr-tray
86
+ - When the program is started w/o a `config.ini`, that file is created with defaults.
87
+ - It has three sections:
88
+ * **Settings**: The settings for when plugged in. Missing/invalid settings are inherited from the defaults. Here are the defaults:
89
+ * **HiBattery**: The settings for when on battery on and not a low battery condition. Missing/invalid settings are inherited from 'Settings'.
90
+ * **LoBattery**: The settings for when on battery in a low battery condition. Missing/invalid settings are inherited from 'Settings'.
91
+
92
+ Here are the current 'Settings' defaults with explanation.
93
+ ```
94
+ [Settings]
95
+ i3lock_args = -t -i ./lockpaper.png # arguments when running i3lock for wallpaper
96
+ debug_mode = False # more frequent and elaborate logging
97
+ power_down = False # power down (rather than suspend)
98
+ turn_off_monitors = False # turn off monitors after locking screen
99
+ lock_min_list = [15, 30] # lock minutes choices
100
+ sleep_min_list = [5, 30] # sleep minutes choices (after lock)
101
+ lo_battery_pct = 10 # define "low battery" state
102
+ gui_editor = geany # gui editor for .ini file
103
+ ```
104
+ **NOTES**:
105
+ * If you have issues with monitors failing to sleep or the system cannot wake when the monitors are off, then disable the `turn_off_monitors` feature.
106
+ * You can set `gui_editor = konsole -e vim`, for example, to use vim in a terminal window. If you don't have `geany` installed, then be sure to change `gui_editor`.
107
+ * `pwr-tray` changes directory to `~/.config/pwr-tray`.
108
+ * If its .ini file is missing, it is created and `lockpaper.png` is copied there too.
109
+ * Your picks of mode, timeouts, etc. are saved to disk when changed, and restored on the next start.
110
+ * Items may be absent depending on the mode and battery state.
111
+ - **NOTE**: when in LoBattery, SleepAfterLock becomes the effective mode. The icon will change per your selection and the battery state.
112
+
113
+ ---
114
+
115
+ ## Per-DE Specific Notes
116
+
117
+ ### i3wm Specific Notes
118
+ * Uninstall or disable all competing energy saving programs (e.g., `xscreensaver`, `xfce4-power-manager`, etc.) when running `i3` whether started by `systemd` or `i3/config` or whatever; defeat the X11 defaults somehow such as in `~/.config/i3/config`:
119
+ ```
120
+ exec --no-startup-id xset s off ; xset s noblank ; xset -dpms
121
+ ```
122
+ * Edit `/etc/systemd/logind.conf` and uncomment `HandlePowerKey=` and `HandleLidSwitch=`, set each action to `suspend`, and then either reboot or restart `systemd-logind`. That enables `xss-lock` to handle those keys.
123
+ * In your config, arrange for the power key (when set to suspend) to also have the system locked on power up with:
124
+ ```
125
+ set $screenlock i3lock -t -i ~/.config/pwr-tray/lockpaper.png --ignore-empty-password --show-failed-attempts
126
+ exec --no-startup-id xss-lock --transfer-sleep-lock -- $screenlock --nofork
127
+ bindsym XF86PowerOff exec --no-startup-id $screenlock && systemctl suspend
128
+ bindsym $mod+Escape exec --no-startup-id $screenlock # create shortcut to lock screen only
129
+
130
+ ```
131
+ * Finally, start your pwr-tray somehow. Below is a simplest case using `i3status`, but it may depend on your status bar:
132
+ ```
133
+ bar {
134
+ status_command i3status
135
+ tray_output primary
136
+ }
137
+ exec_always --no-startup-id ~/.local/bin/pwr-tray
138
+ ```
139
+ * If you use `polybar` for status, then it may be best to run `pwr-tray` from polybar's 'launch' script; e.g., `sleep 1.5 && setsid ~/.local/bin/pwr-tray &`; the delay may be need to allow time for the tray to become ready.
140
+
141
+ ### sway Specific Notes
142
+ * 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
+ * **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.
145
+ * 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
+
147
+ ### KDE (X11) Specific Notes
148
+ * 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
+ * In Settings/AutoStart, add the full path of `~/.local/bin/pwr-tray`.
150
+
@@ -0,0 +1,193 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ TBD
5
+ """
6
+ # pylint: disable=invalid-name, broad-exception-caught
7
+ # pylint: disable=too-many-branches,too-many-statements
8
+ # pylint: disable=too-many-instance-attributes
9
+ # pylint: disable=consider-using-from-import
10
+ # pylint: disable=
11
+ # pylint: disable=
12
+
13
+ import os
14
+ import configparser
15
+ from types import SimpleNamespace
16
+ import copy
17
+ import json
18
+ from pwr_tray.Utils import prt
19
+
20
+ class IniTool:
21
+ """ Configued Params for this class"""
22
+ def __init__(self, paths_only=False):
23
+ self.defaults = {
24
+ 'Settings': {
25
+ 'i3lock_args': '-t -i ./lockpaper.png',
26
+ 'swaylock_args': '-i ./lockpaper.png',
27
+ 'debug_mode': False,
28
+ 'power_down': False,
29
+ 'turn_off_monitors': False,
30
+ 'lock_min_list': '[15, 30]',
31
+ 'sleep_min_list': '[5, 30]',
32
+ 'lo_battery_pct': 10,
33
+ 'gui_editor': 'geany',
34
+ # 'dim_pct_brightness': 100,
35
+ # 'dim_pct_lock_min': 100,
36
+
37
+ }, 'HiBattery': { #was OnBattery
38
+ 'power_down': False,
39
+ 'lock_min_list': '[10, 20]',
40
+ 'sleep_min_list': '[1, 10]',
41
+ # 'dim_pct_brightness': 50,
42
+ # 'dim_pct_lock_min': 70,
43
+
44
+ }, 'LoBattery': {
45
+ 'power_down': True,
46
+ 'lock_min_list': '[1]',
47
+ 'sleep_min_list': '[1]',
48
+ # 'dim_pct_brightness': 50,
49
+ # 'dim_pct_lock_min': 70,
50
+ }
51
+ }
52
+ self.folder = os.path.expanduser("~/.config/pwr-tray")
53
+ self.ini_path = os.path.join(self.folder, "config.ini")
54
+ self.log_path = os.path.join(self.folder, "debug.log")
55
+ self.picks_path = os.path.join(self.folder, "picks.json")
56
+ self.config = configparser.ConfigParser()
57
+ self.last_mod_time = None
58
+ self.section_params = {'Settings': {}, 'HiBattery': {}, 'LoBattery': {}, }
59
+ self.params_by_selector = {}
60
+ if not paths_only:
61
+ self.ensure_ini_file()
62
+ os.chdir(self.folder)
63
+
64
+ @staticmethod
65
+ def get_selectors():
66
+ """ Returns the in right "order" """
67
+ return 'Settings HiBattery LoBattery'.split()
68
+
69
+ def the_default(self, selector, key):
70
+ """ return the default value given the selector and key """
71
+ return self.defaults[selector][key]
72
+
73
+ def get_current_vals(self, selector, list_name):
74
+ """ Expecting a list of two or more non-zero ints """
75
+ if selector in self.params_by_selector and hasattr(self.params_by_selector[selector], list_name):
76
+ vals = getattr(self.params_by_selector[selector], list_name)
77
+ if isinstance(vals, list) and len(vals) >= 2:
78
+ return vals
79
+ return self.the_default(selector, list_name) # should not get here
80
+
81
+ def get_rotated_vals(self, selector, list_name, first):
82
+ """ TBD """
83
+ vals = self.get_current_vals(selector, list_name)
84
+ if first in vals:
85
+ while vals[0] != first:
86
+ vals = vals[1:] + vals[:1]
87
+ setattr(self.params_by_selector[selector], list_name, vals)
88
+ return vals
89
+
90
+ def ensure_ini_file(self):
91
+ """Check if the config file exists, create it if not."""
92
+ if not os.path.exists(self.folder):
93
+ os.makedirs(self.folder, exist_ok=True)
94
+ if not os.path.exists(self.ini_path):
95
+ self.config.read_dict(self.defaults)
96
+ with open(self.ini_path, 'w', encoding='utf-8') as configfile:
97
+ self.config.write(configfile)
98
+
99
+ def update_config(self):
100
+ """ Check if the file has been modified since the last read """
101
+ def to_array(val_str):
102
+ # Expecting string of form: "[1,2,...]" or just "20"
103
+ try:
104
+ vals = json.loads(val_str)
105
+ except Exception:
106
+ return None
107
+ if isinstance(vals, int):
108
+ vals = [vals]
109
+ if not isinstance(vals, list):
110
+ return None
111
+ rvs = []
112
+ for val in vals:
113
+ if isinstance(val, int) and val > 0:
114
+ rvs.append(val)
115
+ if not rvs:
116
+ return None
117
+ if len(rvs) == 1: # always want two
118
+ rvs.append(vals[0])
119
+ return rvs
120
+
121
+ current_mod_time = os.path.getmtime(self.ini_path)
122
+ if current_mod_time == self.last_mod_time:
123
+ return False # not updated
124
+ # Re-read the configuration file if it has changed
125
+ self.config.read(self.ini_path)
126
+ self.last_mod_time = current_mod_time
127
+
128
+ goldens = self.defaults['Settings']
129
+ running = goldens
130
+ all_params = {}
131
+
132
+ # Access the configuration values in order
133
+ prt('parsing config.ini...')
134
+ for selector in self.get_selectors():
135
+ all_params[selector] = params = copy.deepcopy(running)
136
+ if selector not in self.config:
137
+ all_params[selector] = SimpleNamespace(**params)
138
+ continue
139
+
140
+ # iterate the candidates
141
+ candidates = dict(self.config[selector])
142
+ for key, value in candidates.items():
143
+ if key not in goldens:
144
+ prt(f'skip {selector}.{key}: {value!r} [unknown key]')
145
+ continue
146
+
147
+ if key.endswith('_list'):
148
+ list_value = to_array(value)
149
+ if not value:
150
+ params[key] = self.the_default(selector, key)
151
+ prt(f'skip {selector}.{key}: {value!r} [bad list spec]')
152
+ else:
153
+ params[key] = list_value
154
+ continue
155
+
156
+ if isinstance(goldens[key], bool):
157
+ if isinstance(value, str):
158
+ if value.lower() == 'true':
159
+ value = True
160
+ elif value.lower() == 'false':
161
+ value = False
162
+ if isinstance(value, bool):
163
+ params[key] = value
164
+ else:
165
+ params[key] = self.the_default(selector, key)
166
+ prt(f'skip {selector}.{key}: {value!r} [expecting bool]')
167
+ continue
168
+
169
+ if isinstance(goldens[key], int):
170
+ try:
171
+ params[key] = int(value)
172
+ continue
173
+ except Exception:
174
+ params[key] = self.the_default(selector, key)
175
+ prt(f'skip {selector}.{key}: {value!r} [expecting int repr]')
176
+ continue
177
+
178
+ if isinstance(goldens[key], str):
179
+ if isinstance(value, str):
180
+ params[key] = value
181
+ else:
182
+ params[key] = self.the_default(selector, key)
183
+ prt(f'skip {selector}.{key}: {value!r} [expecting string]')
184
+ continue
185
+
186
+ assert False, f'unhandled goldens[{key}]: {value!r}'
187
+ all_params[selector] = SimpleNamespace(**params)
188
+
189
+ self.params_by_selector = all_params
190
+
191
+ prt('DONE parsing config.ini...')
192
+
193
+ return True # updated