4

I am using QThread (pyside) for handling global hot-keys on X11. I have some simple while loop which looks like:

while self.doRun:                
      event=root.display.next_event()
      if event.type==X.KeyPress:
      ....

But next_event() is known for waiting for actual event. So how do I stop that loop without waiting for another keystroke? I was thinking about sending fake event with keypress via Xlib but I don't think that's a right way. Also .terminate() on that event is not an option... with pyside it crashes whole app with:

Fatal Python error: This thread state must be current when releasing

Any ideas?

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
middleofdreams
  • 353
  • 3
  • 13

2 Answers2

3

It's a late answer, but I had the same issue, so maybe it's still helpful for someone.

Based on the documentation, you can use Python's select module to receive events with a time-out.

A solution using select basically consists of two steps: 1) work off all pending events, and 2) wait with a select call until new I/O-events arrive. If no events arrive, the method will timeout after a certain time.

Such an event loop could look like this:


# Main loop, handling events
def loop(self):
  self.loop_cond = True
  timeout=5 # timeout in seconds

  while self.loop_cond:
    # handle all available events
    i = self.d.pending_events()
    while i > 0:
      event = self.display.next_event()
      self.handle_event(event)
      i = i - 1

    # Wait for display to send something, or a timeout of one second
    readable, w, e = select.select([self.display], [], [], timeout)

    # if no files are ready to be read, it's an timeout
    if not readable:
      self.handle_timeout()

I've created a gist with a small example.

Stefan
  • 1,029
  • 9
  • 21
0

You can send a close event (in X11 a destroy event perhaps?), to be more explicit. Another idea is to check if there are any events pending first:

if root.display.pending_events():
    event = root.display.next_event()
    # process event

However this constitutes busy-waiting, so I'd go for the first option.

BartoszKP
  • 34,786
  • 15
  • 102
  • 130
  • I was trying that `pending_events` already but as I expected it's terrible for app performance. Adding sleep (which is stupid itself) makes it even worse. Do you have some example how to send that close event? Do I need to register it somehow? I haven't found much info about that... – middleofdreams Nov 23 '14 at 17:46
  • @middleofdreams Yeah, documentation on Qt's bindings is quite sparse. I'm guessing that you should be able to send this event in the same manner as a simulated keypress event, just with the [appropriate event type](http://pyside.github.io/docs/pyside/PySide/QtCore/QEvent.html#PySide.QtCore.PySide.QtCore.QEvent.Type). Also you might want to checkout native Qt's documentation - it contains more information, and most of it applies also to Qt's bindings. – BartoszKP Nov 23 '14 at 17:53
  • OK I was thinking you're talking about Xlib events... Actually QThread's close event doesn't work like I wanted to. – middleofdreams Nov 23 '14 at 18:17
  • @middleofdreams No, sorry, I got these two confused. Qt's close event won't affect `QThread` of course. In this case you would need something like that in X11 - maybe a destroy event (I've added a link in the answer)? – BartoszKP Nov 23 '14 at 21:02