Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:42.3
plasma5-workspace
xembedsniproxy-inject-mouse-clicks-with-XTest.p...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File xembedsniproxy-inject-mouse-clicks-with-XTest.patch of Package plasma5-workspace
From 9df815e843a4385465fff0cb9a76ddc94ed35b38 Mon Sep 17 00:00:00 2001 From: David Edmundson <kde@davidedmundson.co.uk> Date: Thu, 23 Mar 2017 18:08:45 +0000 Subject: Inject mouse clicks from SNI to xembedded icons with XTest Summary: A certain toolkit doesn't register for mouse press release events because it now uses XI2 only. Injecting those directly to the window is too difficult, fortunately in the GTK3 case we can use XTest to send an event. Something I had previously chosen against using because it didn't work with something else (can't remember what). I now have a bit of code choosing which method to use, which will hopefully cover all cases. Code is a bit convuluted because the xcb version of xtest doesn't have the high-level method I want to use in it's API, so I just used Xlib version. CCBUG: 375017 CCBUG: 362941 Test Plan: Ran my usual bunch of test apps: - xchat - a GTK3 systray demo I made - skype (A Qt4 app without SNI patches) All worked as before Reviewers: #plasma Subscribers: plasma-devel Tags: #plasma Differential Revision: https://phabricator.kde.org/D5156 --- xembed-sni-proxy/CMakeLists.txt | 6 +++--- xembed-sni-proxy/sniproxy.cpp | 28 ++++++++++++++++++++++++++-- xembed-sni-proxy/sniproxy.h | 7 +++++++ xembed-sni-proxy/xtestsender.cpp | 32 ++++++++++++++++++++++++++++++++ xembed-sni-proxy/xtestsender.h | 28 ++++++++++++++++++++++++++++ 5 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 xembed-sni-proxy/xtestsender.cpp create mode 100644 xembed-sni-proxy/xtestsender.h diff --git a/xembed-sni-proxy/CMakeLists.txt b/xembed-sni-proxy/CMakeLists.txt index 2a96cd0..1a5322a 100644 --- a/xembed-sni-proxy/CMakeLists.txt +++ b/xembed-sni-proxy/CMakeLists.txt @@ -26,14 +26,13 @@ set(XCB_LIBS XCB::IMAGE ) - - set(XEMBED_SNI_PROXY_SOURCES main.cpp fdoselectionmanager.cpp snidbus.cpp sniproxy.cpp -) + xtestsender.cpp + ) qt5_add_dbus_adaptor(XEMBED_SNI_PROXY_SOURCES org.kde.StatusNotifierItem.xml sniproxy.h SNIProxy) @@ -59,6 +58,7 @@ target_link_libraries(xembedsniproxy Qt5::DBus KF5::WindowSystem ${XCB_LIBS} + Xtst ) install(TARGETS xembedsniproxy ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/xembed-sni-proxy/sniproxy.cpp b/xembed-sni-proxy/sniproxy.cpp index c935c9e..47e98bb 100644 --- a/xembed-sni-proxy/sniproxy.cpp +++ b/xembed-sni-proxy/sniproxy.cpp @@ -24,6 +24,7 @@ #include <xcb/xcb_atom.h> #include <xcb/xcb_event.h> #include <xcb/xcb_image.h> +#include <xcb/xinput.h> #include "xcbutils.h" #include "debug.h" @@ -41,6 +42,10 @@ #include "statusnotifieritemadaptor.h" #include "statusnotifierwatcher_interface.h" +#include "xtestsender.h" + +//#define VISUAL_DEBUG + #define SNI_WATCHER_SERVICE_NAME "org.kde.StatusNotifierWatcher" #define SNI_WATCHER_PATH "/StatusNotifierWatcher" @@ -72,7 +77,8 @@ SNIProxy::SNIProxy(xcb_window_t wid, QObject* parent): //there is an undocumented feature that you can register an SNI by path, however it doesn't detect an object on a service being removed, only the entire 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) + m_windowId(wid), + m_injectMode(Direct) { //create new SNI new StatusNotifierItemAdaptor(this); @@ -195,6 +201,19 @@ SNIProxy::SNIProxy(xcb_window_t wid, QObject* parent): xcb_flush(c); + //guess which input injection method to use + //we can either send an X event to the client or XTest + //some don't support direct X events (GTK3/4), and some don't support XTest because reasons + //note also some clients might not have the XTest extension. We may as well assume it does and just fail to send later. + + //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); + auto windowAttributes = xcb_get_window_attributes_reply(c, waCookie, nullptr); + if (! windowAttributes->all_event_masks & XCB_EVENT_MASK_BUTTON_PRESS) { + m_injectMode = XTest; + } + //there's no damage event for the first paint, and sometimes it's not drawn immediately //not ideal, but it works better than nothing //test with xchat before changing @@ -470,7 +489,7 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y) xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_STACK_MODE, stackAboveData); //mouse down - { + if (m_injectMode == Direct) { xcb_button_press_event_t* event = new xcb_button_press_event_t; memset(event, 0x00, sizeof(xcb_button_press_event_t)); event->response_type = XCB_BUTTON_PRESS; @@ -488,9 +507,12 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y) xcb_send_event(c, false, m_windowId, XCB_EVENT_MASK_BUTTON_PRESS, (char *) event); delete event; + } else { + sendXTestPressed(QX11Info::display(), mouseButton); } //mouse up + if (m_injectMode == Direct) { xcb_button_release_event_t* event = new xcb_button_release_event_t; memset(event, 0x00, sizeof(xcb_button_release_event_t)); @@ -509,6 +531,8 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y) xcb_send_event(c, false, m_windowId, XCB_EVENT_MASK_BUTTON_RELEASE, (char *) event); delete event; + } else { + sendXTestReleased(QX11Info::display(), mouseButton); } #ifndef VISUAL_DEBUG diff --git a/xembed-sni-proxy/sniproxy.h b/xembed-sni-proxy/sniproxy.h index 7366c67..e897a92 100644 --- a/xembed-sni-proxy/sniproxy.h +++ b/xembed-sni-proxy/sniproxy.h @@ -140,6 +140,11 @@ Q_SIGNALS: void NewStatus(const QString &status); private: + enum InjectMode { + Direct, + XTest + }; + void sendClick(uint8_t mouseButton, int x, int y); QImage getImageNonComposite() const; bool isTransparentImage(const QImage &image) const; @@ -150,6 +155,8 @@ private: xcb_window_t m_containerWid; static int s_serviceCount; QPixmap m_pixmap; + + InjectMode m_injectMode; }; #endif // SNIPROXY_H diff --git a/xembed-sni-proxy/xtestsender.cpp b/xembed-sni-proxy/xtestsender.cpp new file mode 100644 index 0000000..112f0aa --- /dev/null +++ b/xembed-sni-proxy/xtestsender.cpp @@ -0,0 +1,32 @@ +/* Wrap XLIB code in a new file as it defines keywords that conflict with Qt + * + * Copyright (C) 2017 <davidedmundson@kde.org> David Edmundson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <X11/extensions/XTest.h> +#include "xtestsender.h" + +void sendXTestPressed(Display *display, int button) +{ + XTestFakeButtonEvent(display, button, true, 0); +} + +void sendXTestReleased(Display *display, int button) +{ + XTestFakeButtonEvent(display, button, false, 0); +} diff --git a/xembed-sni-proxy/xtestsender.h b/xembed-sni-proxy/xtestsender.h new file mode 100644 index 0000000..d058d6b --- /dev/null +++ b/xembed-sni-proxy/xtestsender.h @@ -0,0 +1,28 @@ +/* Wrap XLIB code in a new file as it defines keywords that conflict with Qt + * + * Copyright (C) 2017 <davidedmundson@kde.org> David Edmundson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef XTEST_SENDER_H +#define XTEST_SENDER_H + +typedef _XDisplay Display; + +void sendXTestPressed(Display *display, int button); +void sendXTestReleased(Display *display, int button); + +#endif -- cgit v0.11.2
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor