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,23 @@ 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+ if self ._r_channel in read :
82+ break
83+
84+ if display_fd in read :
85+ self ._display .dispatch (block = True )
6286
6387 self ._display .disconnect ()
6488
0 commit comments