diff --git a/plugins/application-tray/util.cpp b/plugins/application-tray/util.cpp index a3fe55b50..6ca2bf699 100644 --- a/plugins/application-tray/util.cpp +++ b/plugins/application-tray/util.cpp @@ -2,26 +2,31 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -#include +#include #include "util.h" -#include "xcbthread.h" #include #include #include #include #include +#include +#include +#include #include #include #include #include +#include #include #include #include +Q_LOGGING_CATEGORY(TRAYUTIL, "org.deepin.dde.trayloader.util") + namespace tray { void clean_xcb_image(void *data) { @@ -36,7 +41,29 @@ Util* Util::instance() return _instance; } +void Util::dispatchEvents(DispatchEventsMode mode) +{ + xcb_connection_t *connection = m_x11connection; + if (!connection) { + qCWarning(TRAYUTIL, "Attempting to dispatch X11 events with no connection"); + return; + } + + auto pollEventFunc = mode == DispatchEventsMode::Poll ? xcb_poll_for_event : xcb_poll_for_queued_event; + + while (xcb_generic_event_t *event = pollEventFunc(connection)) { + qintptr result = 0; + + QAbstractEventDispatcher *dispatcher = QCoreApplication::eventDispatcher(); + dispatcher->filterNativeEvent(QByteArrayLiteral("xcb_generic_event_t"), event, &result); + free(event); + } + + xcb_flush(connection); +} + Util::Util() + : QObject() { m_x11connection = xcb_connect(nullptr, nullptr); m_display = XOpenDisplay(""); @@ -50,8 +77,20 @@ Util::Util() m_rootWindow = screen->root; xcb_ewmh_init_atoms_replies(&m_ewmh, xcb_ewmh_init_atoms(m_x11connection, &m_ewmh), nullptr); - m_xcbThread = new XcbThread(m_x11connection); - m_xcbThread->start(); + + const int fd = xcb_get_file_descriptor(m_x11connection); + QSocketNotifier * qfd = new QSocketNotifier(fd, QSocketNotifier::Read, this); + connect(qfd, &QSocketNotifier::activated, this, [this](){ + dispatchEvents(DispatchEventsMode::Poll); + }); + + QAbstractEventDispatcher *dispatcher = QCoreApplication::eventDispatcher(); + connect(dispatcher, &QAbstractEventDispatcher::aboutToBlock, this, [this]() { + dispatchEvents(DispatchEventsMode::EventQueue); + }); + connect(dispatcher, &QAbstractEventDispatcher::awake, this, [this]() { + dispatchEvents(DispatchEventsMode::EventQueue); + }); } Util::~Util() @@ -143,6 +182,11 @@ QString Util::getNameByAtom(const xcb_atom_t& atom) return name; } +xcb_atom_t Util::getAtomFromDisplay(const char * name) +{ + return getAtomByName(xcb_atom_name_by_screen(name, DefaultScreen(getDisplay()))); +} + void Util::moveX11Window(const xcb_window_t& window, const uint32_t& x, const uint32_t& y) { const uint32_t windowMoveConfigVals[2] = {x, y}; diff --git a/plugins/application-tray/util.h b/plugins/application-tray/util.h index d3e4186f6..8b0c1595c 100644 --- a/plugins/application-tray/util.h +++ b/plugins/application-tray/util.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -20,8 +21,7 @@ struct _XDisplay; namespace tray { #define UTIL Util::instance() -class XcbThread; -class Util +class Util : public QObject { public: @@ -34,6 +34,7 @@ class Util xcb_atom_t getAtomByName(const QString& name); QString getNameByAtom(const xcb_atom_t& atom); + xcb_atom_t getAtomFromDisplay(const char * name); void moveX11Window(const xcb_window_t& window, const uint32_t& x, const uint32_t& y); void setX11WindowSize(const xcb_window_t& window, const QSize& size); @@ -58,6 +59,12 @@ class Util Util(const Util&) = delete; Util& operator=(const Util&) = delete; + enum class DispatchEventsMode { + Poll, + EventQueue + }; + void dispatchEvents(DispatchEventsMode mode); + bool isTransparentImage(const QImage &image); QImage convertFromNative(xcb_image_t* image); @@ -71,8 +78,6 @@ class Util _XDisplay *m_display; QSet m_currentIds; - - XcbThread *m_xcbThread; }; } diff --git a/plugins/application-tray/xcbthread.cpp b/plugins/application-tray/xcbthread.cpp deleted file mode 100644 index 538107dc6..000000000 --- a/plugins/application-tray/xcbthread.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "xcbthread.h" -#include "util.h" - -namespace tray { -XcbThread::XcbThread(xcb_connection_t *connection, QObject *parent) - : QThread(parent) - , m_connection(connection) -{ -} - -XcbThread::~XcbThread() -{ -} - -void XcbThread::run() -{ - if (!m_connection) { - return; - } - // The Xembed type tray needs to reset the xwindow state of the receiving event to the state of not receiving events after the mouse - // leaves. This thread is used to receive the leave event and apply the operation. - QScopedPointer event; - while (!isInterruptionRequested()) { - event.reset(xcb_wait_for_event(m_connection)); - if (event) { - uint8_t responseType = event->response_type & ~0x80; - switch (responseType) { - case XCB_LEAVE_NOTIFY: { - xcb_leave_notify_event_t *lE = (xcb_leave_notify_event_t *)event.data(); - UTIL->setX11WindowInputShape(lE->event, QSize(0, 0)); - break; - } - } - } - } -} -} - diff --git a/plugins/application-tray/xcbthread.h b/plugins/application-tray/xcbthread.h deleted file mode 100644 index 215710740..000000000 --- a/plugins/application-tray/xcbthread.h +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include -#include - -namespace tray { -class XcbThread : public QThread { - Q_OBJECT -public: - XcbThread(xcb_connection_t *connection, QObject *parent = nullptr); - ~XcbThread(); - - void run() override; - -private: - xcb_connection_t *m_connection; -}; -} diff --git a/plugins/application-tray/xembedprotocolhandler.cpp b/plugins/application-tray/xembedprotocolhandler.cpp index ae81b2586..69659ab79 100644 --- a/plugins/application-tray/xembedprotocolhandler.cpp +++ b/plugins/application-tray/xembedprotocolhandler.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -31,6 +32,8 @@ XembedProtocol::XembedProtocol(QObject *parent) : AbstractTrayProtocol(parent) , m_trayManager(new TrayManager("org.deepin.dde.TrayManager1", "/org/deepin/dde/TrayManager1", QDBusConnection::sessionBus(), this)) { + qApp->installNativeEventFilter(this); + m_trayManager->Manage(); connect(m_trayManager, &TrayManager::Added, this, &XembedProtocol::onTrayIconsChanged); connect(m_trayManager, &TrayManager::Removed, this, &XembedProtocol::onTrayIconsChanged); @@ -43,6 +46,26 @@ XembedProtocol::~XembedProtocol() m_registedItem.clear(); } +bool XembedProtocol::nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) +{ + Q_UNUSED(result) + + if (eventType != "xcb_generic_event_t") { + return false; + } + + auto *ev = static_cast(message); + + const auto responseType = XCB_EVENT_RESPONSE_TYPE(ev); + if (responseType == XCB_LEAVE_NOTIFY) { + xcb_leave_notify_event_t *lE = (xcb_leave_notify_event_t *)ev; + UTIL->setX11WindowInputShape(lE->event, QSize(0, 0)); + return true; + } + + return false; +} + void XembedProtocol::onTrayIconsChanged() { QTimer::singleShot(200, this,[this](){ diff --git a/plugins/application-tray/xembedprotocolhandler.h b/plugins/application-tray/xembedprotocolhandler.h index 1754ed807..f8e81295c 100644 --- a/plugins/application-tray/xembedprotocolhandler.h +++ b/plugins/application-tray/xembedprotocolhandler.h @@ -17,7 +17,7 @@ #include namespace tray { -class XembedProtocol : public AbstractTrayProtocol +class XembedProtocol : public AbstractTrayProtocol, public QAbstractNativeEventFilter { Q_OBJECT @@ -25,6 +25,9 @@ class XembedProtocol : public AbstractTrayProtocol XembedProtocol(QObject *parent = nullptr); ~XembedProtocol(); +protected: + bool nativeEventFilter(const QByteArray &eventType, void *message, qintptr *result) override; + private Q_SLOTS: void onTrayIconsChanged();