Skip to content

Commit

Permalink
Better framerate fix for Visualiser
Browse files Browse the repository at this point in the history
Use a threading.Lock object and only release lock once FPS interval has
elapsed.
  • Loading branch information
elParaguayo committed Nov 13, 2023
1 parent e6e4385 commit 87c94a5
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
2023-11-13: [BUGFIX] A neater fix for the `Visualiser` CPU bug
2023-11-13: [BUGFIX] Fix `fraction` KeyError in `UpowerWidget`
2023-11-13: [FEATURE] Add `invert` option to `Visualiser` to draw bars from top down
2023-11-12: [BUGFIX] (Trying to) fix increasing CPU with `Visualiser` widget
Expand Down
26 changes: 18 additions & 8 deletions qtile_extras/widget/visualiser.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import time
from contextlib import contextmanager
from pathlib import Path
from threading import Lock
from time import sleep

import cairocffi
Expand All @@ -51,6 +52,8 @@
bit_format = 8bit
"""

fps_lock = Lock()


class Visualiser(base._Widget):
"""
Expand Down Expand Up @@ -188,6 +191,9 @@ def _stop(self):
self._lock.close()
self._lockfile.close()

if fps_lock.locked():
fps_lock.release()

self._set_length()

def _open_shm(self):
Expand Down Expand Up @@ -228,14 +234,13 @@ def draw(self):
self.drawer.draw(offsetx=self.offsetx, offsety=self.offsety, width=self.length)
return

# We need to filter out calls that happen before the next interval
# If we don't do this, CPU usage increases horrifically
# Feels like there should be a better way though!
t = time.time()
diff = t - self._last_time
if diff < self._interval:
# We need to lock the redraw to our set framerate. We can't rely solely on timers
# as any call to bar.draw() by another widget will trigger a draw of the widget.
# We use a non-blocking lock and only allow the widget to draw if the lock was
# successfully acquired. The lock is only released after the required interval has
# elapsed.
if not fps_lock.acquire(blocking=False):
return
self._last_time = t

self._draw()

Expand All @@ -253,7 +258,12 @@ def _draw(self):
self.drawer.ctx.paint()
self.drawer.draw(offsetx=self.offsetx, offsety=self.offsety, width=self.length)

self._timer = self.timeout_add(self._interval, self.draw)
self._timer = self.timeout_add(self._interval, self.loop)

def loop(self):
# Release the lock and redraw.
fps_lock.release()
self.draw()

def finalize(self):
self._stop()
Expand Down

0 comments on commit 87c94a5

Please sign in to comment.