diff --git a/fdoselectionmanager.cpp b/fdoselectionmanager.cpp index 08db8f1..0294123 100644 --- a/fdoselectionmanager.cpp +++ b/fdoselectionmanager.cpp @@ -32,7 +32,7 @@ using Util = tray::Util; FdoSelectionManager::FdoSelectionManager() : QObject() - , m_selectionOwner(new KSelectionOwner(Util::instance()->getAtomFromDisplay("_NET_SYSTEM_TRAY"), -1, this)) + , m_selectionOwner(new KSelectionOwner(UTIL->getAtomFromDisplay("_NET_SYSTEM_TRAY"), UTIL->getX11Connection(), UTIL->getRootWindow(), this)) { qDebug(SNIPROXY) << "starting"; diff --git a/main.cpp b/main.cpp index d18138f..88e7e30 100644 --- a/main.cpp +++ b/main.cpp @@ -10,6 +10,7 @@ #include "fdoselectionmanager.h" #include "debug.h" +#include "util.h" #ifdef None #ifndef FIXX11H_None @@ -25,18 +26,22 @@ inline constexpr XID None = XNone; #include +using Util = tray::Util; + int main(int argc, char **argv) { // the whole point of this is to interact with X, if we are in any other session, force trying to connect to X // if the QPA can't load xcb, this app is useless anyway. - qputenv("QT_QPA_PLATFORM", "xcb"); + qputenv("QT_QPA_PLATFORM", "wayland"); + qputenv("WAYLAND_DISPLAY", "dockplugin"); + qputenv("QT_WAYLAND_SHELL_INTEGRATION", "plugin-shell"); QGuiApplication::setDesktopSettingsAware(false); QCoreApplication::setAttribute(Qt::AA_DisableSessionManager); QGuiApplication app(argc, argv); - if (!KWindowSystem::isPlatformX11()) { + if (!UTIL->isXAvaliable()) { qFatal("xembed-traymanager-proxy requires X11. Aborting"); } diff --git a/util.cpp b/util.cpp index 2ee3f67..95a4353 100644 --- a/util.cpp +++ b/util.cpp @@ -4,6 +4,8 @@ #include +#include "debug.h" + #include "util.h" #include "xcbthread.h" @@ -12,6 +14,9 @@ #include #include #include +#include +#include +#include #include @@ -37,7 +42,29 @@ Util* Util::instance() return _instance; } +void Util::dispatchEvents(DispatchEventsMode mode) +{ + xcb_connection_t *connection = m_x11connection; + if (!connection) { + qCWarning(SNIPROXY, "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(""); @@ -51,8 +78,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() diff --git a/util.h b/util.h index 4eeb1c1..b40cf58 100644 --- a/util.h +++ b/util.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -21,7 +22,7 @@ struct _XDisplay; namespace tray { #define UTIL Util::instance() class XcbThread; -class Util +class Util : public QObject { public: @@ -59,6 +60,12 @@ private: 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);