user1766555
user1766555

Reputation: 57

How to add your own loop to Qt?

I'm stuck on what to do. I have a while loop for xlib to read key presses when my Qt application isn't in focus. This is a copy paste from the ubuntu 16.04 python3-xlib package /usr/share/doc/python3-xlib/examples/record_demo.py. But this disrupts the functionality of the Qt application since it's only reading key presses and not handling Qt's event loops. Should I make my Qt application have a 2nd thread for this? Or can I hook xlib's loop onto Qt's loops?

I am working with python3, pyqt5, and python3-xlib.

Below is the file /usr/share/doc/python3-xlib/examples/record_demo.py

#!/usr/bin/python3
#
# examples/record_demo.py -- demonstrate record extension
#
#    Copyright (C) 2006 Alex Badea <[email protected]>
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

# Simple demo for the RECORD extension
# Not very much unlike the xmacrorec2 program in the xmacro package.

import sys
import os

# Change path so we find Xlib
sys.path.insert(1, os.path.join(sys.path[0], '..'))

from Xlib import X, XK, display
from Xlib.ext import record
from Xlib.protocol import rq

local_dpy = display.Display()
record_dpy = display.Display()

def lookup_keysym(keysym):
    for name in dir(XK):
        if name[:3] == "XK_" and getattr(XK, name) == keysym:
            return name[3:]
    return "[%d]" % keysym

def record_callback(reply):
    if reply.category != record.FromServer:
        return
    if reply.client_swapped:
        print("* received swapped protocol data, cowardly ignored")
        return
    if not len(reply.data) or reply.data[0] < 2:
        # not an event
        return

    data = reply.data
    while len(data):
        event, data = rq.EventField(None).parse_binary_value(data, record_dpy.display, None, None)

        if event.type in [X.KeyPress, X.KeyRelease]:
            pr = event.type == X.KeyPress and "Press" or "Release"

            keysym = local_dpy.keycode_to_keysym(event.detail, 0)
            if not keysym:
                print("KeyCode%s %s" % (pr, event.detail))
            else:
                print("KeyStr%s %s" % (pr, lookup_keysym(keysym)))

            if event.type == X.KeyPress and keysym == XK.XK_Escape:
                local_dpy.record_disable_context(ctx)
                local_dpy.flush()
                return
        elif event.type == X.ButtonPress:
            print("ButtonPress %s" % event.detail)
        elif event.type == X.ButtonRelease:
            print("ButtonRelease %s" % event.detail)
        elif event.type == X.MotionNotify:
            print("MotionNotify %i %i" % (event.root_x, event.root_y))


# Check if the extension is present
if not record_dpy.has_extension("RECORD"):
    print("RECORD extension not found")
    sys.exit(1)
r = record_dpy.record_get_version(0, 0)
print("RECORD extension version %d.%d" % (r.major_version, r.minor_version))

# Create a recording context; we only want key and mouse events
ctx = record_dpy.record_create_context(
        0,
        [record.AllClients],
        [{
                'core_requests': (0, 0),
                'core_replies': (0, 0),
                'ext_requests': (0, 0, 0, 0),
                'ext_replies': (0, 0, 0, 0),
                'delivered_events': (0, 0),
                'device_events': (X.KeyPress, X.MotionNotify),
                'errors': (0, 0),
                'client_started': False,
                'client_died': False,
        }])

# Enable the context; this only returns after a call to record_disable_context,
# while calling the callback function in the meantime
record_dpy.record_enable_context(ctx, record_callback)

# Finally free the context
record_dpy.record_free_context(ctx)

Upvotes: 0

Views: 412

Answers (1)

Qt's event loop is an X event loop. You don't need another.

Since you're getting the information as callbacks from the event loop, this will "just work": as long as you use the same xcb library that Qt uses, and register the callback there, your callback will be invoked.

If you are getting the information as events, you can filter all native X events arriving to your application: use QCoreApplication::installNativeEventFilter. Your concrete implementation of QAbstractNativeEventFilter will receive native events as pointers to xcb_generic_event_t, see the documentation.

Interoperating with Python will be a bit complicated in case of events, though. You might need to implement the event filter in C++ and expose it to Python.

Upvotes: 2

Related Questions