diff -Nru ukui-sni-4.10.0.5/debian/changelog ukui-sni-4.10.0.5/debian/changelog --- ukui-sni-4.10.0.5/debian/changelog 2024-11-19 14:01:03.000000000 +0800 +++ ukui-sni-4.10.0.5/debian/changelog 2024-12-27 16:02:15.000000000 +0800 @@ -1,3 +1,16 @@ +ukui-sni (4.10.0.5-ok1.2) nile; urgency=medium + + * Issues: 无 + * 其他改动: + - 为后台进程增加日志打印机制 + - xembed部分同步上游提交 + - 修改折叠区弹窗收起tooltip仍然显示的bug + - 修改添加版本号异常的bug + * 其他改动影响域: + - 任务栏,托盘 + + -- youdiansaodongxi <guojiaqi@kylinos.cn> Fri, 27 Dec 2024 16:02:15 +0800 + ukui-sni (4.10.0.5-ok1.1) nile; urgency=medium * Issues: 无 diff -Nru ukui-sni-4.10.0.5/debian/patches/0003-update-changelog-for-4.10.0.5-ok1.2.patch ukui-sni-4.10.0.5/debian/patches/0003-update-changelog-for-4.10.0.5-ok1.2.patch --- ukui-sni-4.10.0.5/debian/patches/0003-update-changelog-for-4.10.0.5-ok1.2.patch 1970-01-01 08:00:00.000000000 +0800 +++ ukui-sni-4.10.0.5/debian/patches/0003-update-changelog-for-4.10.0.5-ok1.2.patch 2024-12-27 16:02:15.000000000 +0800 @@ -0,0 +1,743 @@ +From: youdiansaodongxi <guojiaqi@kylinos.cn> +Date: Fri, 27 Dec 2024 16:09:17 +0800 +Subject: update changelog for: 4.10.0.5-ok1.2 + +--- + CMakeLists.txt | 2 +- + log-utils.cpp | 138 +++++++++++++++++++++++++++ + log-utils.h | 41 ++++++++ + status-notifier-watcher/CMakeLists.txt | 2 + + status-notifier-watcher/main.cpp | 3 + + ukui-system-tray/plugin/tray-items-model.cpp | 2 +- + ukui-system-tray/widget/ui/FoldArea.qml | 4 +- + ukui-system-tray/widget/ui/TrayView.qml | 1 + + xembed-sni-proxy/CMakeLists.txt | 8 +- + xembed-sni-proxy/c_ptr.h | 22 +++++ + xembed-sni-proxy/fdo-selection-manager.cpp | 16 +--- + xembed-sni-proxy/main.cpp | 3 + + xembed-sni-proxy/sni-proxy.cpp | 121 +++++++++++++++-------- + xembed-sni-proxy/sni-proxy.h | 3 +- + xembed-sni-proxy/xcb-utils.h | 5 +- + 15 files changed, 308 insertions(+), 63 deletions(-) + create mode 100644 log-utils.cpp + create mode 100644 log-utils.h + create mode 100644 xembed-sni-proxy/c_ptr.h + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 2bddbb5..6a3a25f 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -16,8 +16,8 @@ find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core DBus Network Gui Widgets Quic + + add_subdirectory(status-notifier-watcher) + add_subdirectory(status-notifier-host) +-add_subdirectory(xembed-sni-proxy) + add_subdirectory(ukui-system-tray) ++add_subdirectory(xembed-sni-proxy) + if(BUILD_TEST) + add_subdirectory(test) + endif() +diff --git a/log-utils.cpp b/log-utils.cpp +new file mode 100644 +index 0000000..6d612e1 +--- /dev/null ++++ b/log-utils.cpp +@@ -0,0 +1,138 @@ ++/* ++ * Copyright (C) 2024, KylinSoft Co., Ltd. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <https://www.gnu.org/licenses/>. ++ * ++ * Authors: iaom <zhangpengfei@kylinos.cn> ++ * ++ */ ++ ++#include "log-utils.h" ++#include <QFile> ++#include <QDebug> ++#include <QDir> ++#include <QDateTime> ++#include <QStandardPaths> ++ ++#define LOG_FILE_COUNT 2 ++#define MAX_LOG_FILE_SIZE 4194304 ++#define MAX_LOG_CHECK_INTERVAL 43200000 ++ ++quint64 LogUtils::m_startUpTime = 0; ++int LogUtils::m_logFileId = -1; ++QString LogUtils::m_logFileName; ++QString LogUtils::m_currentLogFile; ++static QString logFilePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.log/ukui-sni/"; ++ ++void LogUtils::messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) ++{ ++ checkLogFile(); ++ ++ QByteArray localMsg = msg.toLocal8Bit(); ++ QByteArray currentTime = QTime::currentTime().toString().toLocal8Bit(); ++ const char *file = context.file ? context.file : ""; ++ const char *function = context.function ? context.function : ""; ++ ++ FILE *log_file = fopen(m_currentLogFile.toLocal8Bit().constData(), "a+"); ++ ++ switch (type) { ++ case QtDebugMsg: ++ if (!log_file) { ++ break; ++ } ++ fprintf(log_file, "Debug: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); ++ break; ++ case QtInfoMsg: ++ fprintf(log_file? log_file: stdout, "Info: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); ++ break; ++ case QtWarningMsg: ++ fprintf(log_file? log_file: stderr, "Warning: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); ++ break; ++ case QtCriticalMsg: ++ fprintf(log_file? log_file: stderr, "Critical: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); ++ break; ++ case QtFatalMsg: ++ fprintf(log_file? log_file: stderr, "Fatal: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); ++ break; ++ } ++ ++ if (log_file) { ++ fclose(log_file); ++ } ++} ++ ++void LogUtils::initLogFile(const QString &fileName) ++{ ++ QDir dir; ++ if (!dir.exists(logFilePath)) { ++ if (!dir.mkpath(logFilePath)) { ++ qWarning() << "Unable to create" << logFilePath; ++ return; ++ } ++ } ++ m_logFileName = logFilePath + fileName + "-%1.log"; ++ ++ for (int i = 0; i < LOG_FILE_COUNT; ++i) { ++ m_currentLogFile = m_logFileName.arg(i); ++ if (QFile::exists(m_currentLogFile)) { ++ if (checkFileSize(m_currentLogFile)) { ++ m_logFileId = i; ++ break; ++ } ++ } else { ++ QFile file(m_currentLogFile); ++ file.open(QIODevice::WriteOnly); ++ file.close(); ++ } ++ } ++ ++ ++ if (m_logFileId < 0) { ++ m_logFileId = 0; ++ m_currentLogFile = m_logFileName.arg(m_logFileId); ++ clearFile(m_currentLogFile); ++ } ++ ++ qInfo() << "Current log file:" << m_currentLogFile; ++} ++ ++void LogUtils::checkLogFile() ++{ ++ quint64 logTime = QDateTime::currentDateTime().toMSecsSinceEpoch(); ++ quint64 spacing = std::max(logTime, m_startUpTime) - std::min(logTime, m_startUpTime); ++ ++ if (spacing <= MAX_LOG_CHECK_INTERVAL || checkFileSize(m_currentLogFile)) { ++ return; ++ } ++ ++ m_logFileId = ((m_logFileId + 1) % LOG_FILE_COUNT); ++ m_currentLogFile = m_logFileName.arg(m_logFileId); ++ if (!checkFileSize(m_currentLogFile)) { ++ clearFile(m_currentLogFile); ++ } ++} ++ ++bool LogUtils::checkFileSize(const QString &fileName) ++{ ++ return QFile(fileName).size() < MAX_LOG_FILE_SIZE; ++} ++ ++void LogUtils::clearFile(const QString &fileName) ++{ ++ QFile file(fileName); ++ file.open(QIODevice::WriteOnly); ++ file.write(""); ++ file.flush(); ++ file.close(); ++} +diff --git a/log-utils.h b/log-utils.h +new file mode 100644 +index 0000000..dccf1d0 +--- /dev/null ++++ b/log-utils.h +@@ -0,0 +1,41 @@ ++/* ++ * Copyright (C) 2024, KylinSoft Co., Ltd. ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see <https://www.gnu.org/licenses/>. ++ * ++ * Authors: iaom <zhangpengfei@kylinos.cn> ++ * ++ */ ++ ++#ifndef LOGUTILS_H ++#define LOGUTILS_H ++#include <QtMessageHandler> ++ ++class LogUtils ++{ ++public: ++ static void initLogFile(const QString &fileName); ++ static void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg); ++ ++private: ++ static void checkLogFile(); ++ static bool checkFileSize(const QString &fileName); ++ static void clearFile(const QString &fileName); ++ static quint64 m_startUpTime; ++ static int m_logFileId; ++ static QString m_logFileName; ++ static QString m_currentLogFile; ++}; ++ ++#endif // LOGUTILS_H +diff --git a/status-notifier-watcher/CMakeLists.txt b/status-notifier-watcher/CMakeLists.txt +index 80600ca..b7f3206 100644 +--- a/status-notifier-watcher/CMakeLists.txt ++++ b/status-notifier-watcher/CMakeLists.txt +@@ -6,6 +6,7 @@ set(UKUI_SNI_WATCHER_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_MICRO}) + set(3rdParties_DIR ../3rd-parties/qtsingleapplication/src/) + configure_file (ukui-sni-watcher-config.h.in ukui-sni-watcher-config.h @ONLY) + include_directories(../common) ++include_directories(../) + set(ukuiSNIWatcher_SRCS + ${3rdParties_DIR}qtsinglecoreapplication.h + ${3rdParties_DIR}qtsinglecoreapplication.cpp +@@ -16,6 +17,7 @@ set(ukuiSNIWatcher_SRCS + watcher-private.h + status-notifier-watcher-application.cpp + status-notifier-watcher-application.h ++ ../log-utils.cpp ../log-utils.h + main.cpp) + set_source_files_properties(../dbus/org.kde.StatusNotifierWatcher.xml PROPERTIES + NO_NAMESPACE false +diff --git a/status-notifier-watcher/main.cpp b/status-notifier-watcher/main.cpp +index e355cf3..e2e10f6 100644 +--- a/status-notifier-watcher/main.cpp ++++ b/status-notifier-watcher/main.cpp +@@ -17,8 +17,11 @@ + * Authors: iaom <zhangpengfei@kylinos.cn> + */ + #include "status-notifier-watcher-application.h" ++#include "log-utils.h" + int main(int argc, char *argv[]) + { ++ LogUtils::initLogFile("ukui-sni-watcher"); ++ qInstallMessageHandler(LogUtils::messageOutput); + StatusNotifierWatcherApplication app(argc, argv); + if(app.isRunning()) { + return 0; +diff --git a/ukui-system-tray/plugin/tray-items-model.cpp b/ukui-system-tray/plugin/tray-items-model.cpp +index 4acc2fa..11e1dec 100644 +--- a/ukui-system-tray/plugin/tray-items-model.cpp ++++ b/ukui-system-tray/plugin/tray-items-model.cpp +@@ -51,7 +51,7 @@ TrayItemsModel::TrayItemsModel(QObject *parent) : QAbstractListModel(parent) + } + //showed items + if (!data.contains(QStringLiteral("version"))) { +- m_config->setValue(QStringLiteral("orderedItems"), QStringLiteral("1.0")); ++ m_config->setValue(QStringLiteral("version"), QStringLiteral("1.0")); + m_orderList = DEFAULT_ORDERED_ITEMS; + m_config->setValue(QStringLiteral("orderedItems"), DEFAULT_ORDERED_ITEMS); + } else { +diff --git a/ukui-system-tray/widget/ui/FoldArea.qml b/ukui-system-tray/widget/ui/FoldArea.qml +index 654a9dd..f296f74 100644 +--- a/ukui-system-tray/widget/ui/FoldArea.qml ++++ b/ukui-system-tray/widget/ui/FoldArea.qml +@@ -9,6 +9,7 @@ import org.ukui.quick.platform 1.0 as Platform + DropArea { + property bool isEmpty: foldModel.count > 0 ? false : true + property int sourceIndex ++ property bool foldWindowVisible: false + signal foldAreaDragFinshed(int selectIndex) + width: foldModel.count > 5 ? foldView.cellWidth * 5 + 8 : foldModel.count * foldView.cellWidth + 8 + height: (foldModel.count % 5) === 0 ? +@@ -106,8 +107,9 @@ DropArea { + UkuiItems.Tooltip { + id: tooltip + anchors.fill: parent +- mainText: model.ToolTipTitle.length == 0 ? model.Title : model.ToolTipTitle ++ mainText: model.ToolTipTitle.length === 0 ? model.Title : model.ToolTipTitle + posFollowCursor: false ++ active: foldWindowVisible + location: { + switch (dropArea.panelPos) { + case UkuiItems.Types.Bottom: +diff --git a/ukui-system-tray/widget/ui/TrayView.qml b/ukui-system-tray/widget/ui/TrayView.qml +index 1d9d64f..af6f285 100644 +--- a/ukui-system-tray/widget/ui/TrayView.qml ++++ b/ukui-system-tray/widget/ui/TrayView.qml +@@ -184,6 +184,7 @@ DropArea { + + FoldArea { + id: foldBase ++ foldWindowVisible: foldWindow.visible + onFoldAreaDragFinshed: fromIndex => { + if (dropArea.inserted) { + if (dropArea.dragType === 1) { +diff --git a/xembed-sni-proxy/CMakeLists.txt b/xembed-sni-proxy/CMakeLists.txt +index 5bb9bed..ea47dc9 100644 +--- a/xembed-sni-proxy/CMakeLists.txt ++++ b/xembed-sni-proxy/CMakeLists.txt +@@ -1,6 +1,4 @@ +-add_definitions(-DQT_NO_CAST_TO_ASCII +--DQT_NO_CAST_FROM_ASCII +--DQT_NO_CAST_FROM_BYTEARRAY) ++set(CMAKE_CXX_STANDARD 20) + include(../cmake/find-modules/FindXCB.cmake) + set(XCB_LIBS + xcb +@@ -13,6 +11,7 @@ set(XCB_LIBS + find_package(KF5WindowSystem) + + include_directories(../common) ++include_directories(../) + set(XEMBED_SNI_PROXY_SOURCES + main.cpp + fdo-selection-manager.cpp +@@ -25,6 +24,9 @@ set(XEMBED_SNI_PROXY_SOURCES + ../common/dbus-types.cpp + ../common/dbus-types.h + ../common/typedefs.h ++ c_ptr.h ++ ../log-utils.cpp ++ ../log-utils.h + ) + + qt_add_dbus_adaptor(XEMBED_SNI_PROXY_SOURCES ../dbus/org.kde.StatusNotifierItem.xml sni-proxy.h SNIProxy) +diff --git a/xembed-sni-proxy/c_ptr.h b/xembed-sni-proxy/c_ptr.h +new file mode 100644 +index 0000000..20bc6dd +--- /dev/null ++++ b/xembed-sni-proxy/c_ptr.h +@@ -0,0 +1,22 @@ ++/* ++ SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com> ++ SPDX-FileCopyrightText: 2024 iaom <zhangpengfei@kylinos.cn> ++ ++ SPDX-License-Identifier: LGPL-2.1-or-later ++*/ ++#pragma once ++#include <memory> ++ ++struct CDeleter { ++ template<typename T> ++ void operator()(T *ptr) ++ { ++ if (ptr) { ++ free(ptr); ++ } ++ } ++}; ++ ++template<typename T> ++using UniqueCPointer = std::unique_ptr<T, CDeleter>; ++ +diff --git a/xembed-sni-proxy/fdo-selection-manager.cpp b/xembed-sni-proxy/fdo-selection-manager.cpp +index c616a0d..de99e3b 100644 +--- a/xembed-sni-proxy/fdo-selection-manager.cpp ++++ b/xembed-sni-proxy/fdo-selection-manager.cpp +@@ -19,6 +19,7 @@ + + #include "sni-proxy.h" + #include "xcb-utils.h" ++#include "c_ptr.h" + + #define SYSTEM_TRAY_REQUEST_DOCK 0 + #define SYSTEM_TRAY_BEGIN_MESSAGE 1 +@@ -75,8 +76,8 @@ bool FdoSelectionManager::addDamageWatch(xcb_window_t client) + xcb_damage_create(c, damageId, client, XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY); + + xcb_generic_error_t *error = nullptr; +- QScopedPointer<xcb_get_window_attributes_reply_t, QScopedPointerPodDeleter> attr(xcb_get_window_attributes_reply(c, attribsCookie, &error)); +- QScopedPointer<xcb_generic_error_t, QScopedPointerPodDeleter> getAttrError(error); ++ UniqueCPointer<xcb_get_window_attributes_reply_t> attr(xcb_get_window_attributes_reply(c, attribsCookie, &error)); ++ UniqueCPointer<xcb_generic_error_t> getAttrError(error); + uint32_t events = XCB_EVENT_MASK_STRUCTURE_NOTIFY; + if (attr) { + events = events | attr->your_event_mask; +@@ -88,7 +89,7 @@ bool FdoSelectionManager::addDamageWatch(xcb_window_t client) + // the event mask will not be removed again. We cannot track whether another component also needs STRUCTURE_NOTIFY (e.g. KWindowSystem). + // if we would remove the event mask again, other areas will break. + const auto changeAttrCookie = xcb_change_window_attributes_checked(c, client, XCB_CW_EVENT_MASK, &events); +- QScopedPointer<xcb_generic_error_t, QScopedPointerPodDeleter> changeAttrError(xcb_request_check(c, changeAttrCookie)); ++ UniqueCPointer<xcb_generic_error_t> changeAttrError(xcb_request_check(c, changeAttrCookie)); + // if window is gone by this point, it will be caught by eventFilter, so no need to check later errors. + if (changeAttrError && changeAttrError->error_code == XCB_WINDOW) { + return false; +@@ -146,15 +147,6 @@ bool FdoSelectionManager::nativeEventFilter(const QByteArray &eventType, void *m + sniProxy->resizeWindow(event->width, event->height); + } + } +- } else if (responseType == XCB_VISIBILITY_NOTIFY) { +- const auto event = reinterpret_cast<xcb_visibility_notify_event_t *>(ev); +- // it's possible that something showed our container window, we have to hide it +- // workaround for BUG 357443: when KWin is restarted, container window is shown on top +- if (event->state == XCB_VISIBILITY_UNOBSCURED) { +- for (auto sniProxy : m_proxies.values()) { +- sniProxy->hideContainerWindow(event->window); +- } +- } + } + + return false; +diff --git a/xembed-sni-proxy/main.cpp b/xembed-sni-proxy/main.cpp +index 132dd3e..47d50ae 100644 +--- a/xembed-sni-proxy/main.cpp ++++ b/xembed-sni-proxy/main.cpp +@@ -16,6 +16,7 @@ + #include <QDBusMetaType> + + #include <KWindowSystem> ++#include <log-utils.h> + + namespace Xcb + { +@@ -24,6 +25,8 @@ Xcb::Atoms *atoms; + + int main(int argc, char **argv) + { ++ LogUtils::initLogFile("xembed-sni-proxy"); ++ qInstallMessageHandler(LogUtils::messageOutput); + // 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"); +diff --git a/xembed-sni-proxy/sni-proxy.cpp b/xembed-sni-proxy/sni-proxy.cpp +index 7ca1704..250f04a 100644 +--- a/xembed-sni-proxy/sni-proxy.cpp ++++ b/xembed-sni-proxy/sni-proxy.cpp +@@ -10,6 +10,7 @@ + #include "sni-proxy.h" + + #include <algorithm> ++#include <span> + #include <xcb/xcb_atom.h> + #include <xcb/xcb_event.h> + +@@ -29,6 +30,7 @@ + #include "statusnotifierwatcher_interface.h" + + #include "xtest-sender.h" ++#include "c_ptr.h" + + // #define VISUAL_DEBUG + +@@ -56,6 +58,26 @@ void xembed_message_send(xcb_window_t towin, long message, long d1, long d2, lon + xcb_send_event(QX11Info::connection(), false, towin, XCB_EVENT_MASK_NO_EVENT, (char *)&ev); + } + ++static bool checkWindowOrDescendantWantButtonEvents(xcb_window_t window) ++{ ++ auto connection = QX11Info::connection(); ++ auto waCookie = xcb_get_window_attributes(connection, window); ++ UniqueCPointer<xcb_get_window_attributes_reply_t> windowAttributes(xcb_get_window_attributes_reply(connection, waCookie, nullptr)); ++ if (windowAttributes && windowAttributes->all_event_masks & XCB_EVENT_MASK_BUTTON_PRESS) { ++ return true; ++ } ++ if (windowAttributes && windowAttributes->do_not_propagate_mask & XCB_EVENT_MASK_BUTTON_PRESS) { ++ return false; ++ } ++ auto treeCookie = xcb_query_tree(connection, window); ++ UniqueCPointer<xcb_query_tree_reply_t> tree(xcb_query_tree_reply(connection, treeCookie, nullptr)); ++ if (!tree) { ++ return false; ++ } ++ std::span<xcb_window_t> children(xcb_query_tree_children(tree.get()), xcb_query_tree_children_length(tree.get())); ++ return std::ranges::any_of(children, &checkWindowOrDescendantWantButtonEvents); ++} ++ + SNIProxy::SNIProxy(xcb_window_t wid, QObject *parent) + : QObject(parent) + , +@@ -64,7 +86,6 @@ SNIProxy::SNIProxy(xcb_window_t wid, QObject *parent) + // service closing instead lets use one DBus connection per SNI + m_dbus(QDBusConnection::connectToBus(QDBusConnection::SessionBus, QStringLiteral("XembedSniProxy%1").arg(s_serviceCount++))) + , m_windowId(wid) +- , sendingClickEvent(false) + , m_injectMode(Direct) + { + new StatusNotifierItemAdaptor(this); +@@ -101,9 +122,8 @@ SNIProxy::SNIProxy(xcb_window_t wid, QObject *parent) + uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK; + values[0] = screen->black_pixel; // draw a solid background so the embedded icon doesn't get garbage in it + values[1] = true; // bypass wM +- values[2] = XCB_EVENT_MASK_VISIBILITY_CHANGE | // receive visibility change, to handle KWin restart #357443 +- // Redirect and handle structure (size, position) requests from the embedded window. +- XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT; ++ values[2] = XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT; ++ + xcb_create_window(c, /* connection */ + XCB_COPY_FROM_PARENT, /* depth */ + m_containerWid, /* window Id */ +@@ -124,15 +144,13 @@ SNIProxy::SNIProxy(xcb_window_t wid, QObject *parent) + We also need it to exist in the right place to get the clicks working as GTK will check sendEvent locations to see if our window is in the right place. + So even though our contents are drawn via compositing we still put this window in the right place + +- We can't composite it away anything parented owned by the root window (apparently) +- Stack Under works in the non composited case, but it doesn't seem to work in kwin's composited case (probably need set relevant NETWM hint) +- +- As a last resort set opacity to 0 just to make sure this container never appears ++ Set opacity to 0 just to make sure this container never appears ++ And set the input region to null so everything just clicks through + */ + +-#ifndef VISUAL_DEBUG +- stackContainerWindow(XCB_STACK_MODE_BELOW); ++ setActiveForInput(false); + ++#ifndef VISUAL_DEBUG + NETWinInfo wm(c, m_containerWid, screen->root, NET::Properties(), NET::Properties2()); + wm.setOpacity(0); + #endif +@@ -178,8 +196,8 @@ SNIProxy::SNIProxy(xcb_window_t wid, QObject *parent) + // we query if the client selected button presses in the event mask + // if the client does supports that we send directly, otherwise we'll use xtest + auto waCookie = xcb_get_window_attributes(c, wid); +- QScopedPointer<xcb_get_window_attributes_reply_t, QScopedPointerPodDeleter> windowAttributes(xcb_get_window_attributes_reply(c, waCookie, nullptr)); +- if (windowAttributes && !(windowAttributes->all_event_masks & XCB_EVENT_MASK_BUTTON_PRESS)) { ++ UniqueCPointer<xcb_get_window_attributes_reply_t> windowAttributes(xcb_get_window_attributes_reply(c, waCookie, nullptr)); ++ if (!checkWindowOrDescendantWantButtonEvents(wid)) { + m_injectMode = XTest; + } + +@@ -230,20 +248,12 @@ void SNIProxy::resizeWindow(const uint16_t width, const uint16_t height) const + xcb_flush(connection); + } + +-void SNIProxy::hideContainerWindow(xcb_window_t windowId) const +-{ +- if (m_containerWid == windowId && !sendingClickEvent) { +- qDebug() << "Container window visible, stack below"; +- stackContainerWindow(XCB_STACK_MODE_BELOW); +- } +-} +- + QSize SNIProxy::calculateClientWindowSize() const + { + auto c = QX11Info::connection(); + + auto cookie = xcb_get_geometry(c, m_windowId); +- QScopedPointer<xcb_get_geometry_reply_t, QScopedPointerPodDeleter> clientGeom(xcb_get_geometry_reply(c, cookie, nullptr)); ++ UniqueCPointer<xcb_get_geometry_reply_t> clientGeom(xcb_get_geometry_reply(c, cookie, nullptr)); + + QSize clientWindowSize; + if (clientGeom) { +@@ -369,9 +379,8 @@ QImage SNIProxy::convertFromNative(xcb_image_t *xcbImage) const + + if (format == QImage::Format_RGB32 && xcbImage->bpp == 32) { + QImage m = image.createHeuristicMask(); +- QBitmap mask(QPixmap::fromImage(m)); +- QPixmap p = QPixmap::fromImage(image); +- p.setMask(mask); ++ QPixmap p = QPixmap::fromImage(std::move(image)); ++ p.setMask(QBitmap::fromImage(std::move(m))); + image = p.toImage(); + } + +@@ -391,7 +400,9 @@ QImage SNIProxy::convertFromNative(xcb_image_t *xcbImage) const + */ + QPoint SNIProxy::calculateClickPoint() const + { +- QPoint clickPoint = QPoint(0, 0); ++ QSize clientSize = calculateClientWindowSize(); ++ QPoint clickPoint = QPoint(clientSize.width() / 2, clientSize.height() / 2); ++ + + auto c = QX11Info::connection(); + +@@ -400,8 +411,8 @@ QPoint SNIProxy::calculateClickPoint() const + // at the same time make the request for rectangles (even if this request isn't needed) + xcb_shape_get_rectangles_cookie_t rectaglesCookie = xcb_shape_get_rectangles(c, m_windowId, XCB_SHAPE_SK_BOUNDING); + +- QScopedPointer<xcb_shape_query_extents_reply_t, QScopedPointerPodDeleter> extentsReply(xcb_shape_query_extents_reply(c, extentsCookie, nullptr)); +- QScopedPointer<xcb_shape_get_rectangles_reply_t, QScopedPointerPodDeleter> rectanglesReply(xcb_shape_get_rectangles_reply(c, rectaglesCookie, nullptr)); ++ UniqueCPointer<xcb_shape_query_extents_reply_t> extentsReply(xcb_shape_query_extents_reply(c, extentsCookie, nullptr)); ++ UniqueCPointer<xcb_shape_get_rectangles_reply_t> rectanglesReply(xcb_shape_get_rectangles_reply(c, rectaglesCookie, nullptr)); + + if (!extentsReply || !rectanglesReply || !extentsReply->bounding_shaped) { + return clickPoint; +@@ -428,11 +439,30 @@ QPoint SNIProxy::calculateClickPoint() const + return clickPoint; + } + +-void SNIProxy::stackContainerWindow(const uint32_t stackMode) const ++void SNIProxy::setActiveForInput(bool active) const + { + auto c = QX11Info::connection(); +- const uint32_t stackData[] = {stackMode}; +- xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_STACK_MODE, stackData); ++ if (active) { ++ xcb_rectangle_t rectangle; ++ rectangle.x = 0; ++ rectangle.y = 0; ++ rectangle.width = s_embedSize; ++ rectangle.height = s_embedSize; ++ xcb_shape_rectangles(c, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, 0, m_containerWid, 0, 0, 1, &rectangle); ++ ++ const uint32_t stackData[] = {XCB_STACK_MODE_ABOVE}; ++ xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_STACK_MODE, stackData); ++ } else { ++ xcb_rectangle_t rectangle; ++ rectangle.x = 0; ++ rectangle.y = 0; ++ rectangle.width = 0; ++ rectangle.height = 0; ++ xcb_shape_rectangles(c, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, 0, m_containerWid, 0, 0, 1, &rectangle); ++ ++ const uint32_t stackData[] = {XCB_STACK_MODE_BELOW}; ++ xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_STACK_MODE, stackData); ++ } + } + + //____________properties__________ +@@ -520,12 +550,11 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y) + // ideally we should make this match the plasmoid hit area + + qDebug() << "Received click" << mouseButton << "with passed x*y" << x << y; +- sendingClickEvent = true; + + auto c = QX11Info::connection(); + + auto cookieSize = xcb_get_geometry(c, m_windowId); +- QScopedPointer<xcb_get_geometry_reply_t, QScopedPointerPodDeleter> clientGeom(xcb_get_geometry_reply(c, cookieSize, nullptr)); ++ UniqueCPointer<xcb_get_geometry_reply_t> clientGeom(xcb_get_geometry_reply(c, cookieSize, nullptr)); + + if (!clientGeom) { + return; +@@ -537,7 +566,7 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y) + if (mouseButton >= XCB_BUTTON_INDEX_4) { + // scroll event, take pointer position + auto cookie = xcb_query_pointer(c, m_windowId); +- QScopedPointer<xcb_query_pointer_reply_t, QScopedPointerPodDeleter> pointer(xcb_query_pointer_reply(c, cookie, nullptr)); ++ UniqueCPointer<xcb_query_pointer_reply_t> pointer(xcb_query_pointer_reply(c, cookie, nullptr)); + configVals[0] = pointer->root_x; + configVals[1] = pointer->root_y; + } else { +@@ -547,8 +576,11 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y) + qDebug() << configVals[0] << configVals[1]; + xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, configVals); + +- // pull window up +- stackContainerWindow(XCB_STACK_MODE_ABOVE); ++ setActiveForInput(true); ++ ++ if (qgetenv("XDG_SESSION_TYPE") == "wayland") { ++ xcb_warp_pointer(c, XCB_NONE, m_windowId, 0, 0, 0, 0, clickPoint.x(), clickPoint.y()); ++ } + + // mouse down + if (m_injectMode == Direct) { +@@ -596,11 +628,20 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y) + sendXTestReleased(QX11Info::display(), mouseButton); + } + +-#ifndef VISUAL_DEBUG +- stackContainerWindow(XCB_STACK_MODE_BELOW); +-#endif +- +- sendingClickEvent = false; ++ if (m_injectMode == Direct) { ++ setActiveForInput(false); ++ } else { ++ // delayed because on xwayland with the new libei path it will go to XWayland ++ // then kwin, then back to X ++ // we need to delay slightly until that happens ++ if (qgetenv("XDG_SESSION_TYPE") == QByteArrayLiteral("wayland")) { ++ QTimer::singleShot(300, this, [this]() { ++ setActiveForInput(false); ++ }); ++ } else { ++ setActiveForInput(false); ++ } ++ } + } + + uint SNIProxy::getPid(const xcb_window_t windowId) +diff --git a/xembed-sni-proxy/sni-proxy.h b/xembed-sni-proxy/sni-proxy.h +index b5128d3..4b729db 100644 +--- a/xembed-sni-proxy/sni-proxy.h ++++ b/xembed-sni-proxy/sni-proxy.h +@@ -39,7 +39,6 @@ public: + + void update(); + void resizeWindow(const uint16_t width, const uint16_t height) const; +- void hideContainerWindow(xcb_window_t windowId) const; + + /** + * @return the category of the application associated to this item +@@ -146,7 +145,7 @@ private: + bool isTransparentImage(const QImage &image) const; + QImage convertFromNative(xcb_image_t *xcbImage) const; + QPoint calculateClickPoint() const; +- void stackContainerWindow(const uint32_t stackMode) const; ++ void setActiveForInput(bool active) const; + uint getPid(const xcb_window_t windowId); + + QDBusConnection m_dbus; +diff --git a/xembed-sni-proxy/xcb-utils.h b/xembed-sni-proxy/xcb-utils.h +index fb7e4e6..af425e9 100644 +--- a/xembed-sni-proxy/xcb-utils.h ++++ b/xembed-sni-proxy/xcb-utils.h +@@ -18,6 +18,7 @@ + + #include <QVector> + #include <QX11Info> ++#include <c_ptr.h> + + /** XEMBED messages */ + #define XEMBED_EMBEDDED_NOTIFY 0 +@@ -31,8 +32,6 @@ + + namespace Xcb + { +-typedef xcb_window_t WindowId; +-template <typename T> using ScopedCPointer = QScopedPointer<T, QScopedPointerPodDeleter>; + class Atom + { + public: +@@ -81,7 +80,7 @@ private: + if (m_retrieved || !m_cookie.sequence) { + return; + } +- ScopedCPointer<xcb_intern_atom_reply_t> reply(xcb_intern_atom_reply(m_connection, m_cookie, nullptr)); ++ UniqueCPointer<xcb_intern_atom_reply_t> reply(xcb_intern_atom_reply(m_connection, m_cookie, nullptr)); + if (reply) { + m_atom = reply->atom; + } diff -Nru ukui-sni-4.10.0.5/debian/patches/series ukui-sni-4.10.0.5/debian/patches/series --- ukui-sni-4.10.0.5/debian/patches/series 2024-11-19 14:01:03.000000000 +0800 +++ ukui-sni-4.10.0.5/debian/patches/series 2024-12-27 16:02:15.000000000 +0800 @@ -1,2 +1,3 @@ 0001-update-changelog-for-4.10.0.5-ok1.patch 0002-update-changelog-for-4.10.0.5-ok1.1.patch +0003-update-changelog-for-4.10.0.5-ok1.2.patch