Compare commits
2 Commits
b0df2b9e27
...
866b81a3dc
| Author | SHA1 | Date | |
|---|---|---|---|
| 866b81a3dc | |||
| faf5b43e2b |
@@ -10,7 +10,6 @@ find_package(Qt6 6.8 CONFIG REQUIRED COMPONENTS DBus)
|
||||
find_package(ECM REQUIRED NO_MODULE)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
include(ECMQtDeclareLoggingCategory)
|
||||
include(KDEInstallDirs)
|
||||
include(ECMConfiguredInstall)
|
||||
|
||||
@@ -35,14 +34,6 @@ set_source_files_properties(
|
||||
|
||||
qt_add_dbus_adaptor(XEMBED_SNI_PROXY_SOURCES org.deepin.dde.TrayManager1.xml traymanager1.h TrayManager1)
|
||||
|
||||
ecm_qt_declare_logging_category(XEMBED_SNI_PROXY_SOURCES HEADER debug.h
|
||||
IDENTIFIER SNIPROXY
|
||||
CATEGORY_NAME dde.xembedsniproxy
|
||||
DEFAULT_SEVERITY Info
|
||||
DESCRIPTION "xembed sni proxy"
|
||||
EXPORT PLASMAWORKSPACE
|
||||
)
|
||||
|
||||
add_executable(xembed-traymanager-proxy ${XEMBED_SNI_PROXY_SOURCES})
|
||||
set_property(TARGET xembed-traymanager-proxy PROPERTY AUTOMOC ON)
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ This is to allow legacy apps (xchat, pidgin, tuxguitar) etc. system trays[1] ava
|
||||
> Currently this project is a standalone project that provides Xembed tray information on TrayManager1 D-Bus, so `dde-tray-loader` could consume it and provide Xembed tray icons.
|
||||
> This project will be integrated into `dde-tray-loader` project.
|
||||
|
||||
This tool can be used on a Wayland session with `wayland` QPA, `xcb` QPA can also be used but it's not mandatory, but either way it's required to have a X connection (via X11 or Xwayland).
|
||||
|
||||
## Build instructions
|
||||
|
||||
```shell
|
||||
|
||||
@@ -7,14 +7,12 @@
|
||||
*/
|
||||
#include "fdoselectionmanager.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QDBusConnection>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
#include <KSelectionOwner>
|
||||
|
||||
#include <qassert.h>
|
||||
#include <xcb/composite.h>
|
||||
#include <xcb/damage.h>
|
||||
#include <xcb/xcb_atom.h>
|
||||
@@ -30,11 +28,13 @@ using Util = tray::Util;
|
||||
#define SYSTEM_TRAY_BEGIN_MESSAGE 1
|
||||
#define SYSTEM_TRAY_CANCEL_MESSAGE 2
|
||||
|
||||
Q_LOGGING_CATEGORY(SELECTIONMGR, "org.deepin.dde.trayloader.selectionmgr")
|
||||
|
||||
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";
|
||||
qDebug(SELECTIONMGR) << "starting";
|
||||
|
||||
// we may end up calling QCoreApplication::quit() in this method, at which point we need the event loop running
|
||||
QTimer::singleShot(0, this, &FdoSelectionManager::init);
|
||||
@@ -42,7 +42,7 @@ FdoSelectionManager::FdoSelectionManager()
|
||||
|
||||
FdoSelectionManager::~FdoSelectionManager()
|
||||
{
|
||||
qCDebug(SNIPROXY) << "closing";
|
||||
qCDebug(SELECTIONMGR) << "closing";
|
||||
m_selectionOwner->release();
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ void FdoSelectionManager::init()
|
||||
xcb_damage_query_version_unchecked(c, XCB_DAMAGE_MAJOR_VERSION, XCB_DAMAGE_MINOR_VERSION);
|
||||
} else {
|
||||
// no XDamage means
|
||||
qCCritical(SNIPROXY) << "could not load damage extension. Quitting";
|
||||
qCCritical(SELECTIONMGR) << "could not load damage extension. Quitting";
|
||||
qApp->exit(-1);
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ void FdoSelectionManager::init()
|
||||
|
||||
bool FdoSelectionManager::addDamageWatch(xcb_window_t client)
|
||||
{
|
||||
qCDebug(SNIPROXY) << "adding damage watch for " << client;
|
||||
qCDebug(SELECTIONMGR) << "adding damage watch for " << client;
|
||||
|
||||
xcb_connection_t *c = Util::instance()->getX11Connection();
|
||||
const auto attribsCookie = xcb_get_window_attributes_unchecked(c, client);
|
||||
@@ -153,16 +153,13 @@ bool FdoSelectionManager::nativeEventFilter(const QByteArray &eventType, void *m
|
||||
void FdoSelectionManager::dock(xcb_window_t winId)
|
||||
{
|
||||
Q_CHECK_PTR(m_trayManager);
|
||||
qCDebug(SNIPROXY) << "trying to dock window " << winId;
|
||||
qCDebug(SELECTIONMGR) << "trying to dock window " << winId;
|
||||
|
||||
if (m_trayManager->haveIcon(winId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (addDamageWatch(winId)) {
|
||||
// auto proxy = new TrayManagerProxy(winId, this);
|
||||
// m_proxies[winId] = proxy;
|
||||
|
||||
// Register with TrayManager1 if available
|
||||
m_trayManager->registerIcon(winId);
|
||||
}
|
||||
@@ -171,7 +168,7 @@ void FdoSelectionManager::dock(xcb_window_t winId)
|
||||
void FdoSelectionManager::undock(xcb_window_t winId)
|
||||
{
|
||||
Q_CHECK_PTR(m_trayManager);
|
||||
qCDebug(SNIPROXY) << "trying to undock window " << winId;
|
||||
qCDebug(SELECTIONMGR) << "trying to undock window " << winId;
|
||||
|
||||
if (m_trayManager->haveIcon(winId)) {
|
||||
return;
|
||||
@@ -186,7 +183,7 @@ void FdoSelectionManager::undock(xcb_window_t winId)
|
||||
|
||||
void FdoSelectionManager::onClaimedOwnership()
|
||||
{
|
||||
qCDebug(SNIPROXY) << "Manager selection claimed";
|
||||
qCDebug(SELECTIONMGR) << "Manager selection claimed";
|
||||
|
||||
initTrayManager();
|
||||
setSystemTrayVisual();
|
||||
@@ -194,13 +191,13 @@ void FdoSelectionManager::onClaimedOwnership()
|
||||
|
||||
void FdoSelectionManager::onFailedToClaimOwnership()
|
||||
{
|
||||
qCWarning(SNIPROXY) << "failed to claim ownership of Systray Manager";
|
||||
qCWarning(SELECTIONMGR) << "failed to claim ownership of Systray Manager";
|
||||
qApp->exit(-1);
|
||||
}
|
||||
|
||||
void FdoSelectionManager::onLostOwnership()
|
||||
{
|
||||
qCWarning(SNIPROXY) << "lost ownership of Systray Manager";
|
||||
qCWarning(SELECTIONMGR) << "lost ownership of Systray Manager";
|
||||
qApp->exit(-1);
|
||||
}
|
||||
|
||||
@@ -253,7 +250,7 @@ void FdoSelectionManager::initTrayManager()
|
||||
QStringLiteral("org.deepin.dde.TrayManager1")
|
||||
);
|
||||
|
||||
qCDebug(SNIPROXY) << "TrayManager1 DBus interface registered";
|
||||
qCDebug(SELECTIONMGR) << "TrayManager1 DBus interface registered";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
17
main.cpp
17
main.cpp
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "fdoselectionmanager.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef None
|
||||
#ifndef FIXX11H_None
|
||||
@@ -25,18 +25,25 @@ inline constexpr XID None = XNone;
|
||||
|
||||
#include <KWindowSystem>
|
||||
|
||||
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");
|
||||
// We will use the X connection managed by UTIL, we don't really care if the tool itself is
|
||||
// running with xcb or wayland QPA.
|
||||
// We'll use wayland QPA for testing on DDE, the following code uses dde-tray-loader's wayland
|
||||
// display, thus we can ensure our X events are not from QPA.
|
||||
qputenv("QT_QPA_PLATFORM", "wayland");
|
||||
qputenv("WAYLAND_DISPLAY", "dockplugin");
|
||||
qputenv("QT_WAYLAND_SHELL_INTEGRATION", "plugin-shell");
|
||||
// qputenv("QT_QPA_PLATFORM", "xcb");
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
@@ -4,32 +4,35 @@
|
||||
*/
|
||||
|
||||
#include "traymanager1.h"
|
||||
#include "debug.h"
|
||||
#include "traymanager1adaptor.h"
|
||||
|
||||
#include <KWindowInfo>
|
||||
#include <QGuiApplication>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
Q_LOGGING_CATEGORY(TRAYMGR, "org.deepin.dde.trayloader.traymgr")
|
||||
|
||||
TrayManager1::TrayManager1(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_adaptor(new TrayManager1Adaptor(this))
|
||||
{
|
||||
qCDebug(SNIPROXY) << "TrayManager1 created";
|
||||
qCDebug(TRAYMGR) << "TrayManager1 created";
|
||||
}
|
||||
|
||||
TrayManager1::~TrayManager1()
|
||||
{
|
||||
qCDebug(SNIPROXY) << "TrayManager1 destroyed";
|
||||
qCDebug(TRAYMGR) << "TrayManager1 destroyed";
|
||||
}
|
||||
|
||||
void TrayManager1::registerIcon(xcb_window_t win)
|
||||
{
|
||||
if (m_icons.contains(win)) {
|
||||
qCWarning(SNIPROXY) << "Icon already registered:" << win;
|
||||
qCWarning(TRAYMGR) << "Icon already registered:" << win;
|
||||
return;
|
||||
}
|
||||
|
||||
m_icons[win] = true;
|
||||
qCDebug(SNIPROXY) << "Icon registered:" << win ;//<< "name:" << proxy->name();
|
||||
qCDebug(TRAYMGR) << "Icon registered:" << win ;//<< "name:" << proxy->name();
|
||||
|
||||
Q_EMIT Added(static_cast<uint32_t>(win));
|
||||
}
|
||||
@@ -37,12 +40,12 @@ void TrayManager1::registerIcon(xcb_window_t win)
|
||||
void TrayManager1::unregisterIcon(xcb_window_t win)
|
||||
{
|
||||
if (!m_icons.contains(win)) {
|
||||
qCWarning(SNIPROXY) << "Icon not found for removal:" << win;
|
||||
qCWarning(TRAYMGR) << "Icon not found for removal:" << win;
|
||||
return;
|
||||
}
|
||||
|
||||
m_icons.remove(win);
|
||||
qCDebug(SNIPROXY) << "Icon unregistered:" << win;
|
||||
qCDebug(TRAYMGR) << "Icon unregistered:" << win;
|
||||
|
||||
Q_EMIT Removed(static_cast<uint32_t>(win));
|
||||
}
|
||||
@@ -54,11 +57,11 @@ void TrayManager1::notifyIconChanged(xcb_window_t win)
|
||||
}
|
||||
|
||||
if (!m_icons[win]) {
|
||||
qCDebug(SNIPROXY) << "EnableNotification is false, not sending changed signal for:" << win;
|
||||
qCDebug(TRAYMGR) << "EnableNotification is false, not sending changed signal for:" << win;
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(SNIPROXY) << "Icon changed:" << win;
|
||||
qCDebug(TRAYMGR) << "Icon changed:" << win;
|
||||
Q_EMIT Changed(static_cast<uint32_t>(win));
|
||||
}
|
||||
|
||||
@@ -80,7 +83,7 @@ bool TrayManager1::haveIcon(xcb_window_t win) const
|
||||
// DBus method implementations
|
||||
bool TrayManager1::Manage()
|
||||
{
|
||||
qCDebug(SNIPROXY) << "Manage() called via DBus";
|
||||
qCDebug(TRAYMGR) << "Manage() called via DBus";
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -99,5 +102,5 @@ void TrayManager1::EnableNotification(uint32_t win, bool enabled)
|
||||
|
||||
m_icons[win] = enabled;
|
||||
|
||||
qCDebug(SNIPROXY) << "EnableNotification for" << win << "=" << enabled;
|
||||
qCDebug(TRAYMGR) << "EnableNotification for" << win << "=" << enabled;
|
||||
}
|
||||
|
||||
45
util.cpp
45
util.cpp
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <QDebug>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
#include "util.h"
|
||||
#include "xcbthread.h"
|
||||
@@ -12,6 +12,9 @@
|
||||
#include <QBitmap>
|
||||
#include <QFileInfo>
|
||||
#include <QtGlobal>
|
||||
#include <QSocketNotifier>
|
||||
#include <QCoreApplication>
|
||||
#include <QAbstractEventDispatcher>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
@@ -23,6 +26,8 @@
|
||||
#include <xcb/xproto.h>
|
||||
#include <xcb/composite.h>
|
||||
|
||||
Q_LOGGING_CATEGORY(TRAYUTIL, "org.deepin.dde.trayloader.util")
|
||||
|
||||
namespace tray {
|
||||
void clean_xcb_image(void *data)
|
||||
{
|
||||
@@ -37,7 +42,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("");
|
||||
@@ -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()
|
||||
|
||||
9
util.h
9
util.h
@@ -8,6 +8,7 @@
|
||||
#include <QImage>
|
||||
#include <QSharedPointer>
|
||||
#include <QSet>
|
||||
#include <QObject>
|
||||
|
||||
#include <cstdint>
|
||||
#include <sys/types.h>
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user