2020
2121import threading
2222import datetime
23+ import os
24+ import select
2325
2426from pywayland .client import Display
2527from pywayland .protocol .wayland .wl_seat import WlSeat
@@ -33,19 +35,26 @@ class ExtIdleNotify:
3335 _notifier_set = False
3436 _running = True
3537 _thread = None
38+ _r_channel = None
39+ _w_channel = None
3640
3741 _idle_since = None
3842
3943 def __init__ (self ):
4044 self ._display = Display ()
4145 self ._display .connect ()
46+ self ._r_channel , self ._w_channel = os .pipe ()
4247
4348 def stop (self ):
4449 self ._running = False
50+ # write anything, just to wake up the channel
51+ os .write (self ._w_channel , b"!" )
4552 self ._notification .destroy ()
4653 self ._notification = None
4754 self ._seat = None
4855 self ._thread .join ()
56+ os .close (self ._r_channel )
57+ os .close (self ._w_channel )
4958
5059 def run (self ):
5160 self ._thread = threading .Thread (
@@ -57,8 +66,26 @@ def _run(self):
5766 reg = self ._display .get_registry ()
5867 reg .dispatcher ["global" ] = self ._global_handler
5968
69+ display_fd = self ._display .get_fd ()
70+
6071 while self ._running :
61- self ._display .dispatch (block = True )
72+ self ._display .flush ()
73+
74+ # this blocks until either there are new events in self._display
75+ # (retrieved using dispatch())
76+ # or until there are events in self._r_channel - which means that stop()
77+ # was called
78+ # unfortunately, this seems like the best way to make sure that dispatch
79+ # doesn't block potentially forever (up to multiple seconds in my usage)
80+ read , _w , _x = select .select ((display_fd , self ._r_channel ), (), ())
81+
82+ if self ._r_channel in read :
83+ # the channel was written to, which means stop() was called
84+ # at this point, self._running should be false as well
85+ break
86+
87+ if display_fd in read :
88+ self ._display .dispatch (block = True )
6289
6390 self ._display .disconnect ()
6491
0 commit comments