File indexing completed on 2024-05-19 05:35:17
0001 0002 ////////////////////////////////////////////////////////////////////////////// 0003 // oxygendetectwidget.cpp 0004 // Note: this class is a stripped down version of 0005 // /kdebase/workspace/kwin/kcmkwin/kwinrules/detectwidget.cpp 0006 // SPDX-FileCopyrightText: 2004 Lubos Lunak <l.lunak@kde.org> 0007 // ------------------- 0008 // 0009 // SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr> 0010 // 0011 // SPDX-License-Identifier: MIT 0012 ////////////////////////////////////////////////////////////////////////////// 0013 0014 #include "oxygendetectwidget.h" 0015 0016 #include "oxygen.h" 0017 0018 #include <KWindowInfo> 0019 0020 #include <QMouseEvent> 0021 #include <QPushButton> 0022 #include <config-oxygen.h> 0023 #if OXYGEN_HAVE_X11 0024 #include <private/qtx11extras_p.h> 0025 #include <xcb/xcb.h> 0026 #endif 0027 0028 namespace Oxygen 0029 { 0030 //_________________________________________________________ 0031 DetectDialog::DetectDialog(QWidget *parent) 0032 : QDialog(parent) 0033 { 0034 // setup 0035 m_ui.setupUi(this); 0036 0037 connect(m_ui.buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(close())); 0038 m_ui.windowClassCheckBox->setChecked(true); 0039 0040 #if OXYGEN_HAVE_X11 0041 if (QX11Info::isPlatformX11()) { 0042 // create atom 0043 xcb_connection_t *connection(QX11Info::connection()); 0044 const QString atomName(QStringLiteral("WM_STATE")); 0045 xcb_intern_atom_cookie_t cookie(xcb_intern_atom(connection, false, atomName.size(), qPrintable(atomName))); 0046 QScopedPointer<xcb_intern_atom_reply_t, QScopedPointerPodDeleter> reply(xcb_intern_atom_reply(connection, cookie, nullptr)); 0047 m_wmStateAtom = reply ? reply->atom : 0; 0048 } 0049 #endif 0050 } 0051 0052 //_________________________________________________________ 0053 void DetectDialog::detect(WId window) 0054 { 0055 if (window == 0) 0056 selectWindow(); 0057 else 0058 readWindow(window); 0059 } 0060 0061 //_________________________________________________________ 0062 void DetectDialog::readWindow(WId window) 0063 { 0064 if (window == 0) { 0065 emit detectionDone(false); 0066 return; 0067 } 0068 0069 m_info.reset(new KWindowInfo(window, NET::WMAllProperties, NET::WM2AllProperties)); 0070 if (!m_info->valid()) { 0071 emit detectionDone(false); 0072 return; 0073 } 0074 0075 const QString wmClassClass(QString::fromUtf8(m_info->windowClassClass())); 0076 const QString wmClassName(QString::fromUtf8(m_info->windowClassName())); 0077 0078 m_ui.windowClass->setText(QStringLiteral("%1 (%2 %3)").arg(wmClassClass).arg(wmClassName).arg(wmClassClass)); 0079 m_ui.windowTitle->setText(m_info->name()); 0080 emit detectionDone(exec() == QDialog::Accepted); 0081 0082 return; 0083 } 0084 0085 //_________________________________________________________ 0086 void DetectDialog::selectWindow() 0087 { 0088 // use a dialog, so that all user input is blocked 0089 // use WX11BypassWM and moving away so that it's not actually visible 0090 // grab only mouse, so that keyboard can be used e.g. for switching windows 0091 m_grabber = new QDialog(nullptr, Qt::X11BypassWindowManagerHint); 0092 m_grabber->move(-1000, -1000); 0093 m_grabber->setModal(true); 0094 m_grabber->show(); 0095 0096 // need to explicitly override cursor for Qt5 0097 qApp->setOverrideCursor(Qt::CrossCursor); 0098 m_grabber->grabMouse(Qt::CrossCursor); 0099 m_grabber->installEventFilter(this); 0100 } 0101 0102 //_________________________________________________________ 0103 bool DetectDialog::eventFilter(QObject *o, QEvent *e) 0104 { 0105 // check object and event type 0106 if (o != m_grabber) 0107 return false; 0108 if (e->type() != QEvent::MouseButtonRelease) 0109 return false; 0110 0111 // need to explicitely release cursor for Qt5 0112 qApp->restoreOverrideCursor(); 0113 0114 // delete old m_grabber 0115 delete m_grabber; 0116 m_grabber = nullptr; 0117 0118 // check button 0119 if (static_cast<QMouseEvent *>(e)->button() != Qt::LeftButton) 0120 return true; 0121 0122 // read window information 0123 readWindow(findWindow()); 0124 0125 return true; 0126 } 0127 0128 //_________________________________________________________ 0129 WId DetectDialog::findWindow() 0130 { 0131 #if OXYGEN_HAVE_X11 0132 if (!QX11Info::isPlatformX11()) { 0133 return 0; 0134 } 0135 // check atom 0136 if (!m_wmStateAtom) 0137 return 0; 0138 0139 xcb_connection_t *connection(QX11Info::connection()); 0140 xcb_window_t parent(QX11Info::appRootWindow()); 0141 0142 // why is there a loop of only 10 here 0143 for (int i = 0; i < 10; ++i) { 0144 // query pointer 0145 xcb_query_pointer_cookie_t pointerCookie(xcb_query_pointer(connection, parent)); 0146 QScopedPointer<xcb_query_pointer_reply_t, QScopedPointerPodDeleter> pointerReply(xcb_query_pointer_reply(connection, pointerCookie, nullptr)); 0147 if (!(pointerReply && pointerReply->child)) 0148 return 0; 0149 0150 const xcb_window_t child(pointerReply->child); 0151 xcb_get_property_cookie_t cookie(xcb_get_property(connection, 0, child, m_wmStateAtom, XCB_GET_PROPERTY_TYPE_ANY, 0, 0)); 0152 QScopedPointer<xcb_get_property_reply_t, QScopedPointerPodDeleter> reply(xcb_get_property_reply(connection, cookie, nullptr)); 0153 if (reply && reply->type) 0154 return child; 0155 else 0156 parent = child; 0157 } 0158 #endif 0159 0160 return 0; 0161 } 0162 }