avoid depend on qGuiApp directly
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
build/
|
||||
.cache/
|
||||
.vscode/
|
||||
@@ -8,6 +8,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) # ensure adapter class can include related hea
|
||||
|
||||
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)
|
||||
@@ -16,33 +17,14 @@ include(ECMConfiguredInstall)
|
||||
find_package(KF6 6.6 REQUIRED COMPONENTS
|
||||
WindowSystem)
|
||||
|
||||
find_package(XCB
|
||||
REQUIRED COMPONENTS
|
||||
XCB
|
||||
XFIXES
|
||||
DAMAGE
|
||||
COMPOSITE
|
||||
RANDR
|
||||
SHM
|
||||
UTIL
|
||||
IMAGE
|
||||
)
|
||||
|
||||
set(XCB_LIBS
|
||||
XCB::XCB
|
||||
XCB::XFIXES
|
||||
XCB::DAMAGE
|
||||
XCB::COMPOSITE
|
||||
XCB::RANDR
|
||||
XCB::SHM
|
||||
XCB::UTIL
|
||||
XCB::IMAGE
|
||||
)
|
||||
pkg_check_modules(X11 REQUIRED IMPORTED_TARGET x11 xcb xcb-image xcb-damage xcb-composite xcb-xfixes xcb-util xcb-shape xtst xcb-xtest xcb-res xcb-ewmh)
|
||||
|
||||
set(XEMBED_SNI_PROXY_SOURCES
|
||||
main.cpp
|
||||
fdoselectionmanager.cpp fdoselectionmanager.h
|
||||
traymanager1.cpp traymanager1.h
|
||||
util.cpp util.h
|
||||
xcbthread.cpp xcbthread.h
|
||||
)
|
||||
|
||||
set_source_files_properties(
|
||||
@@ -72,8 +54,7 @@ target_link_libraries(xembed-traymanager-proxy
|
||||
Qt::Core
|
||||
Qt::DBus
|
||||
KF6::WindowSystem
|
||||
${XCB_LIBS}
|
||||
X11::Xtst
|
||||
PkgConfig::X11
|
||||
)
|
||||
|
||||
install(TARGETS xembed-traymanager-proxy ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
|
||||
#include "traymanager1.h"
|
||||
#include "xcbutils.h"
|
||||
#include "util.h"
|
||||
|
||||
using Util = tray::Util;
|
||||
|
||||
#define SYSTEM_TRAY_REQUEST_DOCK 0
|
||||
#define SYSTEM_TRAY_BEGIN_MESSAGE 1
|
||||
@@ -29,7 +32,6 @@
|
||||
|
||||
FdoSelectionManager::FdoSelectionManager()
|
||||
: QObject()
|
||||
, m_x11Interface(qGuiApp->nativeInterface<QNativeInterface::QX11Application>())
|
||||
, m_selectionOwner(new KSelectionOwner(Xcb::atoms->selectionAtom, -1, this))
|
||||
{
|
||||
qDebug(SNIPROXY) << "starting";
|
||||
@@ -47,7 +49,7 @@ FdoSelectionManager::~FdoSelectionManager()
|
||||
void FdoSelectionManager::init()
|
||||
{
|
||||
// load damage extension
|
||||
xcb_connection_t *c = m_x11Interface->connection();
|
||||
xcb_connection_t *c = Util::instance()->getX11Connection();
|
||||
xcb_prefetch_extension_data(c, &xcb_damage_id);
|
||||
const auto *reply = xcb_get_extension_data(c, &xcb_damage_id);
|
||||
if (reply && reply->present) {
|
||||
@@ -71,7 +73,7 @@ bool FdoSelectionManager::addDamageWatch(xcb_window_t client)
|
||||
{
|
||||
qCDebug(SNIPROXY) << "adding damage watch for " << client;
|
||||
|
||||
xcb_connection_t *c = m_x11Interface->connection();
|
||||
xcb_connection_t *c = Util::instance()->getX11Connection();
|
||||
const auto attribsCookie = xcb_get_window_attributes_unchecked(c, client);
|
||||
|
||||
const auto damageId = xcb_generate_id(c);
|
||||
@@ -204,7 +206,7 @@ void FdoSelectionManager::onLostOwnership()
|
||||
|
||||
void FdoSelectionManager::setSystemTrayVisual()
|
||||
{
|
||||
xcb_connection_t *c = m_x11Interface->connection();
|
||||
xcb_connection_t *c = Util::instance()->getX11Connection();
|
||||
auto screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
|
||||
auto trayVisual = screen->root_visual;
|
||||
xcb_depth_iterator_t depth_iterator = xcb_screen_allowed_depths_iterator(screen);
|
||||
|
||||
@@ -42,7 +42,6 @@ private:
|
||||
void setSystemTrayVisual();
|
||||
void initTrayManager();
|
||||
|
||||
QNativeInterface::QX11Application *m_x11Interface = nullptr;
|
||||
TrayManager1 *m_trayManager = nullptr;
|
||||
|
||||
uint8_t m_damageEventBase;
|
||||
|
||||
377
util.cpp
Normal file
377
util.cpp
Normal file
@@ -0,0 +1,377 @@
|
||||
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include "util.h"
|
||||
#include "xcbthread.h"
|
||||
|
||||
#include <QSize>
|
||||
#include <QPixmap>
|
||||
#include <QBitmap>
|
||||
#include <QFileInfo>
|
||||
#include <QtGlobal>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <xcb/res.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xtest.h>
|
||||
#include <xcb/xproto.h>
|
||||
#include <xcb/composite.h>
|
||||
|
||||
namespace tray {
|
||||
void clean_xcb_image(void *data)
|
||||
{
|
||||
xcb_image_destroy(static_cast<xcb_image_t *>(data));
|
||||
}
|
||||
|
||||
Util* Util::instance()
|
||||
{
|
||||
static Util* _instance = nullptr;
|
||||
if (_instance == nullptr)
|
||||
_instance = new Util();
|
||||
return _instance;
|
||||
}
|
||||
|
||||
Util::Util()
|
||||
{
|
||||
m_x11connection = xcb_connect(nullptr, nullptr);
|
||||
m_display = XOpenDisplay("");
|
||||
if (!m_x11connection || !isXAvaliable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const xcb_setup_t *setup = xcb_get_setup(m_x11connection);
|
||||
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
|
||||
xcb_screen_t* screen = iter.data;
|
||||
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();
|
||||
}
|
||||
|
||||
Util::~Util()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool Util::isXAvaliable()
|
||||
{
|
||||
static std::once_flag flag;
|
||||
static bool avaliable = false;
|
||||
|
||||
std::call_once(flag, [this](){
|
||||
if (!(m_x11connection && m_display)) return;
|
||||
|
||||
// xtest support
|
||||
const xcb_query_extension_reply_t *xtest_ext_reply;
|
||||
xtest_ext_reply = xcb_get_extension_data(m_x11connection, &xcb_test_id);
|
||||
|
||||
// xshape support
|
||||
const xcb_query_extension_reply_t *xshape_ext_reply;
|
||||
xshape_ext_reply = xcb_get_extension_data(m_x11connection, &xcb_shape_id);
|
||||
|
||||
// xewmh support
|
||||
xcb_ewmh_connection_t ewmh;
|
||||
xcb_intern_atom_cookie_t *ewmh_cookie = xcb_ewmh_init_atoms(m_x11connection, &ewmh);
|
||||
if (!ewmh_cookie) return;
|
||||
|
||||
xcb_ewmh_init_atoms_replies(&ewmh, ewmh_cookie, NULL);
|
||||
avaliable = m_x11connection && m_display &&
|
||||
(xtest_ext_reply && xtest_ext_reply->present) &&
|
||||
(xshape_ext_reply && xshape_ext_reply->present) &&
|
||||
(ewmh._NET_WM_STATE && ewmh._NET_WM_WINDOW_TYPE);
|
||||
});
|
||||
|
||||
return avaliable;
|
||||
}
|
||||
|
||||
xcb_connection_t* Util::getX11Connection()
|
||||
{
|
||||
return m_x11connection;
|
||||
}
|
||||
|
||||
xcb_window_t Util::getRootWindow()
|
||||
{
|
||||
return m_rootWindow;
|
||||
}
|
||||
|
||||
_XDisplay* Util::getDisplay()
|
||||
{
|
||||
return m_display;
|
||||
}
|
||||
|
||||
xcb_atom_t Util::getAtomByName(const QString &name)
|
||||
{
|
||||
xcb_atom_t ret = m_atoms.value(name, 0);
|
||||
if (!ret) {
|
||||
xcb_intern_atom_cookie_t cookie = xcb_intern_atom(m_x11connection, false, name.size(), name.toStdString().c_str());
|
||||
QSharedPointer<xcb_intern_atom_reply_t> reply(xcb_intern_atom_reply(m_x11connection, cookie, nullptr), [=](xcb_intern_atom_reply_t* reply){
|
||||
free(reply);}
|
||||
);
|
||||
|
||||
if (reply) {
|
||||
m_atoms.insert(name, xcb_atom_t(reply->atom));
|
||||
ret = reply->atom;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString Util::getNameByAtom(const xcb_atom_t& atom)
|
||||
{
|
||||
auto name = m_atoms.key(atom);
|
||||
if (name.isEmpty()) {
|
||||
xcb_get_atom_name_cookie_t cookie = xcb_get_atom_name(m_x11connection, atom);
|
||||
QSharedPointer<xcb_get_atom_name_reply_t> reply(
|
||||
xcb_get_atom_name_reply(m_x11connection, cookie, nullptr),
|
||||
[=](xcb_get_atom_name_reply_t* reply) {free(reply);});
|
||||
if (!reply) {
|
||||
return name;
|
||||
}
|
||||
std::string tmp;
|
||||
tmp.assign(xcb_get_atom_name_name(reply.get()), xcb_get_atom_name_name_length(reply.get()));
|
||||
name = tmp.c_str();
|
||||
if (!name.isEmpty()) {
|
||||
m_atoms.insert(name, atom);
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
void Util::moveX11Window(const xcb_window_t& window, const uint32_t& x, const uint32_t& y)
|
||||
{
|
||||
const uint32_t windowMoveConfigVals[2] = {x, y};
|
||||
xcb_configure_window(m_x11connection, window, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, windowMoveConfigVals);
|
||||
xcb_flush(m_x11connection);
|
||||
}
|
||||
|
||||
void Util::setX11WindowSize(const xcb_window_t& window, const QSize& size)
|
||||
{
|
||||
const int windowSizeConfigVals[2] = {size.width(), size.height()};
|
||||
xcb_configure_window(m_x11connection, window, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, windowSizeConfigVals);
|
||||
xcb_flush(m_x11connection);
|
||||
}
|
||||
|
||||
QSize Util::getX11WindowSize(const xcb_window_t& window)
|
||||
{
|
||||
auto cookie = xcb_get_geometry(m_x11connection, window);
|
||||
QSharedPointer<xcb_get_geometry_reply_t> clientGeom(xcb_get_geometry_reply(m_x11connection, cookie, nullptr));
|
||||
|
||||
return clientGeom ? QSize(clientGeom->width, clientGeom->height) : QSize(0, 0);
|
||||
}
|
||||
|
||||
QString Util::getX11WindowName(const xcb_window_t& window)
|
||||
{
|
||||
std::string ret;
|
||||
xcb_get_property_cookie_t cookie = xcb_ewmh_get_wm_name(&m_ewmh, window);
|
||||
xcb_ewmh_get_utf8_strings_reply_t reply;
|
||||
if (xcb_ewmh_get_wm_name_reply(&m_ewmh, cookie, &reply, nullptr)) {
|
||||
ret.assign(reply.strings, reply.strings_len);
|
||||
xcb_ewmh_get_utf8_strings_reply_wipe(&reply);
|
||||
}
|
||||
return ret.c_str();
|
||||
}
|
||||
|
||||
void Util::setX11WindowInputShape(const xcb_window_t& window, const QSize& size)
|
||||
{
|
||||
xcb_rectangle_t rectangle;
|
||||
rectangle.x = 0;
|
||||
rectangle.y = 0;
|
||||
rectangle.width = size.width();
|
||||
rectangle.height = size.height();
|
||||
xcb_shape_rectangles(m_x11connection, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, window, 0, 0, 1, &rectangle);
|
||||
xcb_shape_mask(m_x11connection, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, window, 0, 0, XCB_PIXMAP_NONE);
|
||||
|
||||
const uint32_t stackData[] = {size.width() > 0 && size.height() > 0 ? XCB_STACK_MODE_ABOVE : XCB_STACK_MODE_BELOW};
|
||||
xcb_configure_window(m_x11connection, window, XCB_CONFIG_WINDOW_STACK_MODE, stackData);
|
||||
xcb_flush(m_x11connection);
|
||||
}
|
||||
|
||||
QImage Util::getX11WidnowImageNonComposite(const xcb_window_t& window)
|
||||
{
|
||||
QSize size = getX11WindowSize(window);
|
||||
xcb_image_t *image = xcb_image_get(m_x11connection, window, 0, 0, size.width(), size.height(), 0xFFFFFFFF, XCB_IMAGE_FORMAT_Z_PIXMAP);
|
||||
|
||||
QImage naiveConversion;
|
||||
if (image) {
|
||||
naiveConversion = QImage(image->data, image->width, image->height, QImage::Format_ARGB32);
|
||||
} else {
|
||||
return QImage();
|
||||
}
|
||||
|
||||
if (isTransparentImage(naiveConversion)) {
|
||||
QImage elaborateConversion = QImage(convertFromNative(image));
|
||||
if (isTransparentImage(elaborateConversion)) {
|
||||
return QImage();
|
||||
} else
|
||||
return elaborateConversion;
|
||||
} else {
|
||||
return QImage(image->data, image->width, image->height, image->stride, QImage::Format_ARGB32, clean_xcb_image, image);
|
||||
}
|
||||
}
|
||||
|
||||
void Util::setX11WindowOpacity(const xcb_window_t& window, const double& opacity)
|
||||
{
|
||||
xcb_atom_t opacityAtom = getAtomByName("_NET_WM_WINDOW_OPACITY");
|
||||
quint32 value = qRound64(qBound(qreal(0), opacity, qreal(1)) * 0xffffffff);
|
||||
|
||||
xcb_change_property(m_x11connection,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
window,
|
||||
opacityAtom,
|
||||
XCB_ATOM_CARDINAL,
|
||||
32,
|
||||
1,
|
||||
(uchar *)&value);
|
||||
xcb_flush(m_x11connection);
|
||||
}
|
||||
|
||||
pid_t Util::getWindowPid(const xcb_window_t& window)
|
||||
{
|
||||
xcb_res_client_id_spec_t spec = { window, XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID };
|
||||
xcb_res_query_client_ids_cookie_t cookie = xcb_res_query_client_ids_unchecked(m_x11connection, 1, &spec);
|
||||
QSharedPointer<xcb_res_query_client_ids_reply_t> reply(xcb_res_query_client_ids_reply(m_x11connection, cookie, NULL),[](xcb_res_query_client_ids_reply_t* reply){
|
||||
free(reply);
|
||||
});
|
||||
|
||||
if (reply) {
|
||||
xcb_res_client_id_value_iterator_t iter = xcb_res_query_client_ids_ids_iterator(reply.get());
|
||||
for (; iter.rem; xcb_res_client_id_value_next(&iter)) {
|
||||
if (iter.data->spec.mask == XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID && xcb_res_client_id_value_value_length(iter.data) == 1) {
|
||||
return xcb_res_client_id_value_value(iter.data)[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
// qWarning() << "failed to get pid for window: " << window;
|
||||
return 0;
|
||||
}
|
||||
|
||||
QString Util::getProcExe(const pid_t& pid)
|
||||
{
|
||||
return QFileInfo(QString("/proc/").append(QString::number(pid).append("/exe"))).canonicalFilePath().split("/").last();
|
||||
}
|
||||
|
||||
void Util::sendXembedMessage(const xcb_window_t& window, const long& message, const long& data1, const long& data2, const long& data3)
|
||||
{
|
||||
xcb_client_message_event_t ev;
|
||||
|
||||
ev.response_type = XCB_CLIENT_MESSAGE;
|
||||
ev.window = window;
|
||||
ev.format = 32;
|
||||
ev.data.data32[0] = XCB_CURRENT_TIME;
|
||||
ev.data.data32[1] = message;
|
||||
ev.data.data32[2] = data1;
|
||||
ev.data.data32[3] = data2;
|
||||
ev.data.data32[4] = data3;
|
||||
ev.type = getAtomByName(QStringLiteral("_XEMBED"));
|
||||
xcb_send_event(m_x11connection, false, window, XCB_EVENT_MASK_NO_EVENT, (char *)&ev);
|
||||
}
|
||||
|
||||
QString Util::generateUniqueId(const QString &id)
|
||||
{
|
||||
for (int i = 0; i < 100; i++) {
|
||||
QString newId = id + "-" + QString::number(i);
|
||||
if (!m_currentIds.contains(newId)) {
|
||||
m_currentIds.insert(newId);
|
||||
return newId;
|
||||
}
|
||||
}
|
||||
|
||||
qWarning() << "failed to generate unique id:" << id;
|
||||
return id;
|
||||
}
|
||||
|
||||
void Util::removeUniqueId(const QString &id) {
|
||||
m_currentIds.remove(id);
|
||||
}
|
||||
|
||||
bool Util::isTransparentImage(const QImage &image)
|
||||
{
|
||||
int w = image.width();
|
||||
int h = image.height();
|
||||
|
||||
if (!(qAlpha(image.pixel(w >> 1, h >> 1)) + qAlpha(image.pixel(w >> 2, h >> 2)) == 0))
|
||||
return false;
|
||||
|
||||
for (int x = 0; x < w; ++x) {
|
||||
for (int y = 0; y < h; ++y) {
|
||||
if (qAlpha(image.pixel(x, y))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QImage Util::convertFromNative(xcb_image_t *xcbImage)
|
||||
{
|
||||
QImage::Format format = QImage::Format_Invalid;
|
||||
|
||||
switch (xcbImage->depth) {
|
||||
case 1:
|
||||
format = QImage::Format_MonoLSB;
|
||||
break;
|
||||
case 16:
|
||||
format = QImage::Format_RGB16;
|
||||
break;
|
||||
case 24:
|
||||
format = QImage::Format_RGB32;
|
||||
break;
|
||||
case 30: {
|
||||
quint32 *pixels = reinterpret_cast<quint32 *>(xcbImage->data);
|
||||
for (uint i = 0; i < (xcbImage->size / 4); i++) {
|
||||
int r = (pixels[i] >> 22) & 0xff;
|
||||
int g = (pixels[i] >> 12) & 0xff;
|
||||
int b = (pixels[i] >> 2) & 0xff;
|
||||
|
||||
pixels[i] = qRgba(r, g, b, 0xff);
|
||||
}
|
||||
Q_FALLTHROUGH();
|
||||
}
|
||||
case 32:
|
||||
format = QImage::Format_ARGB32_Premultiplied;
|
||||
break;
|
||||
default:
|
||||
return QImage();
|
||||
}
|
||||
|
||||
QImage image(xcbImage->data, xcbImage->width, xcbImage->height, xcbImage->stride, format, clean_xcb_image, xcbImage);
|
||||
|
||||
if (image.isNull()) {
|
||||
return QImage();
|
||||
}
|
||||
|
||||
if (format == QImage::Format_RGB32 && xcbImage->bpp == 32) {
|
||||
QImage m = image.createHeuristicMask();
|
||||
QPixmap p = QPixmap::fromImage(std::move(image));
|
||||
p.setMask(QBitmap::fromImage(std::move(m)));
|
||||
image = p.toImage();
|
||||
}
|
||||
|
||||
if (image.format() == QImage::Format_MonoLSB) {
|
||||
image.setColorCount(2);
|
||||
image.setColor(0, QColor(Qt::white).rgb());
|
||||
image.setColor(1, QColor(Qt::black).rgb());
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
QPoint Util::getMousePos() const
|
||||
{
|
||||
QPoint pos;
|
||||
xcb_query_pointer_cookie_t cookie = xcb_query_pointer(m_x11connection, m_rootWindow);
|
||||
QScopedPointer<xcb_query_pointer_reply_t> reply(xcb_query_pointer_reply(m_x11connection, cookie, NULL));
|
||||
if (reply) {
|
||||
pos = QPoint(reply->root_x, reply->root_y);
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
78
util.h
Normal file
78
util.h
Normal file
@@ -0,0 +1,78 @@
|
||||
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QHash>
|
||||
#include <QImage>
|
||||
#include <QSharedPointer>
|
||||
#include <QSet>
|
||||
|
||||
#include <cstdint>
|
||||
#include <sys/types.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xproto.h>
|
||||
#include <xcb/xcb_ewmh.h>
|
||||
#include <xcb/xcb_image.h>
|
||||
|
||||
struct _XDisplay;
|
||||
|
||||
namespace tray {
|
||||
#define UTIL Util::instance()
|
||||
class XcbThread;
|
||||
class Util
|
||||
{
|
||||
|
||||
public:
|
||||
static Util* instance();
|
||||
|
||||
bool isXAvaliable();
|
||||
xcb_connection_t* getX11Connection();
|
||||
xcb_window_t getRootWindow();
|
||||
_XDisplay* getDisplay();
|
||||
|
||||
xcb_atom_t getAtomByName(const QString& name);
|
||||
QString getNameByAtom(const xcb_atom_t& atom);
|
||||
|
||||
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);
|
||||
QSize getX11WindowSize(const xcb_window_t& window);
|
||||
QString getX11WindowName(const xcb_window_t& window);
|
||||
void setX11WindowInputShape(const xcb_window_t& widnow, const QSize& size);
|
||||
QImage getX11WidnowImageNonComposite(const xcb_window_t& window);
|
||||
void setX11WindowOpacity(const xcb_window_t& window, const double& opacity);
|
||||
pid_t getWindowPid(const xcb_window_t& window);
|
||||
QString getProcExe(const pid_t& pid);
|
||||
|
||||
void sendXembedMessage(const xcb_window_t& window, const long& message, const long& data1, const long& data2, const long& data3);
|
||||
|
||||
QString generateUniqueId(const QString &id);
|
||||
void removeUniqueId(const QString &id);
|
||||
|
||||
QPoint getMousePos() const;
|
||||
|
||||
private:
|
||||
Util();
|
||||
~Util();
|
||||
Util(const Util&) = delete;
|
||||
Util& operator=(const Util&) = delete;
|
||||
|
||||
bool isTransparentImage(const QImage &image);
|
||||
|
||||
QImage convertFromNative(xcb_image_t* image);
|
||||
|
||||
private:
|
||||
xcb_ewmh_connection_t m_ewmh;
|
||||
QHash<QString, xcb_atom_t> m_atoms;
|
||||
|
||||
xcb_connection_t* m_x11connection;
|
||||
xcb_window_t m_rootWindow;
|
||||
_XDisplay *m_display;
|
||||
|
||||
QSet<QString> m_currentIds;
|
||||
|
||||
XcbThread *m_xcbThread;
|
||||
};
|
||||
|
||||
}
|
||||
42
xcbthread.cpp
Normal file
42
xcbthread.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// 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<xcb_generic_event_t> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
22
xcbthread.h
Normal file
22
xcbthread.h
Normal file
@@ -0,0 +1,22 @@
|
||||
// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QThread>
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user