File indexing completed on 2024-04-28 16:44:48

0001 /*
0002     SPDX-License-Identifier: GPL-2.0-only
0003     SPDX-FileCopyrightText: 2003 Lubos Lunak <l.lunak@kde.org>
0004  */
0005 
0006 #include "helper_widgets/window_selector.h"
0007 
0008 #include <QApplication>
0009 #include <QDebug>
0010 #include <QDesktopWidget>
0011 #include <QX11Info>
0012 
0013 #include <X11/Xlib.h>
0014 #include <fixx11h.h>
0015 #include <xcb/xcb.h>
0016 
0017 namespace KHotKeys
0018 {
0019 WindowSelector::WindowSelector(QObject *receiver_P, const char *slot_P)
0020 {
0021     connect(this, SIGNAL(selected_signal(WId)), receiver_P, slot_P);
0022 }
0023 
0024 WindowSelector::~WindowSelector()
0025 {
0026     qApp->desktop()->releaseMouse();
0027     QApplication::instance()->removeNativeEventFilter(this);
0028 }
0029 
0030 void WindowSelector::select()
0031 {
0032     qApp->desktop()->grabMouse(QCursor(Qt::CrossCursor));
0033     QApplication::instance()->installNativeEventFilter(this);
0034 }
0035 
0036 bool WindowSelector::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
0037 {
0038     Q_UNUSED(result)
0039     if (eventType != QByteArrayLiteral("xcb_generic_event_t")) {
0040         return false;
0041     }
0042     xcb_generic_event_t *event = reinterpret_cast<xcb_generic_event_t *>(message);
0043     if ((event->response_type & ~0x80) == XCB_BUTTON_PRESS) {
0044         xcb_button_press_event_t *e = reinterpret_cast<xcb_button_press_event_t *>(event);
0045         if (e->detail == XCB_BUTTON_INDEX_1) {
0046             if (WId window = findRealWindow(e->child)) {
0047                 emit selected_signal(window);
0048             }
0049             deleteLater();
0050             return true;
0051         }
0052     }
0053     return false;
0054 }
0055 
0056 WId WindowSelector::findRealWindow(WId w, int depth)
0057 {
0058     if (depth > 5)
0059         return None;
0060     static Atom wm_state = XInternAtom(QX11Info::display(), "WM_STATE", False);
0061     Atom type;
0062     int format;
0063     unsigned long nitems, after;
0064     unsigned char *prop;
0065     if (XGetWindowProperty(QX11Info::display(), w, wm_state, 0, 0, False, AnyPropertyType, &type, &format, &nitems, &after, &prop) == Success) {
0066         if (prop != nullptr)
0067             XFree(prop);
0068         if (type != None)
0069             return w;
0070     }
0071     Window root, parent;
0072     Window *children;
0073     unsigned int nchildren;
0074     Window ret = None;
0075     if (XQueryTree(QX11Info::display(), w, &root, &parent, &children, &nchildren) != 0) {
0076         for (unsigned int i = 0; i < nchildren && ret == None; ++i)
0077             ret = findRealWindow(children[i], depth + 1);
0078         if (children != nullptr)
0079             XFree(children);
0080     }
0081     return ret;
0082 }
0083 
0084 } // namespace KHotKeys