Skip to content

Commit

Permalink
new option py3status.stop_signal to disable i3bar stop/resume (ultrab…
Browse files Browse the repository at this point in the history
  • Loading branch information
ultrabug committed Jan 31, 2022
1 parent 0f228a7 commit 5e2a3c1
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 21 deletions.
9 changes: 9 additions & 0 deletions docs/user-guide/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ This special section holds py3status specific configuration. Settings
here will affect all py3status modules. Many settings e.g. colors can
still be overridden by also defining in the individual module.

- `stop_signal`. Specify a signal number to be used by i3bar to stop/resume the bar refresh. This is useful if you want to prevent i3bar from stopping py3status when the bar is not visible (hidden/fullscreen).

```
# prevent i3bar from stopping py3status when hidden/fullscreen
py3status {
stop_signal = 0
}
```

- `nagbar_font`. Specify a font for `i3-nagbar -f <font>`.

```
Expand Down
16 changes: 8 additions & 8 deletions py3status/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,21 @@ def main():

try:
locale.setlocale(locale.LC_ALL, "")
except locale.Error:
print("No locale available")
except locale.Error as err:
print(f"No locale available ({err})")
sys.exit(2)

py3 = None
try:
py3 = Py3statusWrapper(options)
py3.setup()
except (BrokenPipeError, KeyboardInterrupt):
except (BrokenPipeError, KeyboardInterrupt) as err:
if py3:
py3.notify_user("Setup interrupted")
py3.notify_user(f"Setup interrupted ({err})")
sys.exit(0)
except Exception:
except Exception as err:
if py3:
py3.report_exception("Setup error")
py3.report_exception(f"Setup error ({err})")
else:
# we cannot report this Exception
raise
Expand All @@ -52,8 +52,8 @@ def main():
py3.run()
except (BrokenPipeError, KeyboardInterrupt):
pass
except Exception:
py3.report_exception("Runtime error")
except Exception as err:
py3.report_exception(f"Runtime error ({err})")
sys.exit(3)
finally:
py3.stop()
Expand Down
48 changes: 35 additions & 13 deletions py3status/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from json import dumps
from pathlib import Path
from pprint import pformat
from signal import signal, SIGTERM, SIGUSR1, SIGTSTP, SIGCONT
from signal import signal, Signals, SIGTERM, SIGUSR1, SIGTSTP, SIGCONT
from subprocess import Popen
from threading import Event, Thread
from syslog import syslog, LOG_ERR, LOG_INFO, LOG_WARNING
Expand Down Expand Up @@ -260,6 +260,7 @@ def __init__(self, options):
self.output_modules = {}
self.py3_modules = []
self.running = True
self.stop_signal = SIGTSTP
self.update_queue = deque()
self.update_request = Event()

Expand Down Expand Up @@ -527,14 +528,6 @@ def setup(self):
Setup py3status and spawn i3status/events/modules threads.
"""

# SIGTSTP will be received from i3bar indicating that all output should
# stop and we should consider py3status suspended. It is however
# important that any processes using i3 ipc should continue to receive
# those events otherwise it can lead to a stall in i3.
signal(SIGTSTP, self.i3bar_stop)
# SIGCONT indicates output should be resumed.
signal(SIGCONT, self.i3bar_start)

# log py3status and python versions
self.log("=" * 8)
msg = "Starting py3status version {version} python {python_version}"
Expand Down Expand Up @@ -641,6 +634,35 @@ def setup(self):
sys.stdout = Path("/dev/null").open("w")
sys.stderr = Path("/dev/null").open("w")

# make sure we honor custom i3bar protocol stop/resume signals
# while providing users a way to opt out from that feature
# using the 0 value as specified by the i3bar protocol
custom_stop_signal = (
self.config["py3_config"].get("py3status", {}).get("stop_signal")
)
if custom_stop_signal is not None:
try:
# 0 is a special value for i3bar protocol, use it as-is
if custom_stop_signal == 0:
self.stop_signal = custom_stop_signal
else:
self.stop_signal = Signals(custom_stop_signal)
except ValueError:
error = (
f"py3status.stop_signal '{custom_stop_signal}' is invalid "
f"and should be a number between 0 (disable) and 31"
)
self.log(error, level="error")
raise Exception(error)

# SIGTSTP can be received and indicates that all output should
# stop and we should consider py3status suspended. It is however
# important that any processes using i3 ipc should continue to receive
# those events otherwise it can lead to a stall in i3.
signal(SIGTSTP, self.i3bar_stop)
# SIGCONT indicates output should be resumed.
signal(SIGCONT, self.i3bar_start)

# get the list of py3status configured modules
self.py3_modules = self.config["py3_config"]["py3_modules"]

Expand Down Expand Up @@ -952,16 +974,16 @@ def process_module_output(self, module):

def i3bar_stop(self, signum, frame):
if time.time() - self.i3bar_inhibit_stp > 1:
self.log("received SIGTSTP")
self.log(f"received stop_signal {Signals(signum).name}")
self.i3bar_running = False
# i3status should be stopped
self.i3status_thread.suspend_i3status()
self.sleep_modules()
else:
self.log("received inhibited SIGTSTP")
self.log(f"inhibited stop_signal {Signals(signum).name}")

def i3bar_start(self, signum, frame):
self.log("received SIGCONT")
self.log(f"received resume signal {Signals(signum).name}")
self.i3bar_inhibit_stp = time.time()
self.i3bar_running = True
self.wake_modules()
Expand Down Expand Up @@ -1016,7 +1038,7 @@ def run(self):
header = {
"version": 1,
"click_events": self.config["click_events"],
"stop_signal": SIGTSTP,
"stop_signal": self.stop_signal or 0,
}
write(dumps(header))
write("\n[[]\n")
Expand Down

0 comments on commit 5e2a3c1

Please sign in to comment.