From 24f75b2fda71c76542452da8c6ea39b39a5b4c4c Mon Sep 17 00:00:00 2001 From: Konrad Materka Date: Wed, 18 Dec 2019 14:03:54 +0100 Subject: [PATCH] [XembedSNIProxy] Redirect and handle structure requests on the embedded window. Summary: When the window is embedded, it should not request position change. Sometimes applications are misbehaving and ignore this constrain. We need to capture all structure requests (position or size change) and ignore them. In other words, we must be a window manager for the embedded window. BUG: 414667 Test Plan: 0. You need multiples screens to test this 1. Configure screens so that (0,0) is not on the primary screen 2. Run any Windows app with tray icon using Wine 3. Left click event should work correctly Reviewers: #plasma_workspaces, #plasma, davidedmundson Reviewed By: #plasma_workspaces, #plasma, davidedmundson Subscribers: plasma-devel Tags: #plasma Differential Revision: https://phabricator.kde.org/D26079 --- xembed-sni-proxy/fdoselectionmanager.cpp | 7 +++++ xembed-sni-proxy/sniproxy.cpp | 38 ++++++++++++++++-------- xembed-sni-proxy/sniproxy.h | 1 + 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/xembed-sni-proxy/fdoselectionmanager.cpp b/xembed-sni-proxy/fdoselectionmanager.cpp index f740b7c39..faf2ef2da 100644 --- a/xembed-sni-proxy/fdoselectionmanager.cpp +++ b/xembed-sni-proxy/fdoselectionmanager.cpp @@ -154,6 +154,13 @@ bool FdoSelectionManager::nativeEventFilter(const QByteArray &eventType, void *m sniProxy->update(); xcb_damage_subtract(QX11Info::connection(), m_damageWatches[damagedWId], XCB_NONE, XCB_NONE); } + } else if (responseType == XCB_CONFIGURE_REQUEST) { + const auto event = reinterpret_cast(ev); + const auto sniProxy = m_proxies.value(event->window); + if (sniProxy) { + // The embedded window tries to move or resize. Ignore this request and send the current configuration. + sniProxy->sendConfigureNotification(); + } } return false; diff --git a/xembed-sni-proxy/sniproxy.cpp b/xembed-sni-proxy/sniproxy.cpp index cdb8d24df..96c480d18 100644 --- a/xembed-sni-proxy/sniproxy.cpp +++ b/xembed-sni-proxy/sniproxy.cpp @@ -49,6 +49,7 @@ #define SNI_WATCHER_PATH "/StatusNotifierWatcher" static uint16_t s_embedSize = 32; //max size of window to embed. We no longer resize the embedded window as Chromium acts stupidly. +static unsigned int XEMBED_VERSION = 0; int SNIProxy::s_serviceCount = 0; @@ -95,10 +96,12 @@ SNIProxy::SNIProxy(xcb_window_t wid, QObject* parent): //create a container window auto screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data; m_containerWid = xcb_generate_id(c); - uint32_t values[2]; - auto mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT; + uint32_t values[3]; + 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 + // Redirect and handle structure (size, position) requests on the embedded window. + 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 */ @@ -148,7 +151,7 @@ SNIProxy::SNIProxy(xcb_window_t wid, QObject* parent): xcb_change_save_set(c, XCB_SET_MODE_INSERT, wid); //tell client we're embedding it - xembed_message_send(wid, XEMBED_EMBEDDED_NOTIFY, m_containerWid, 0, 0); + xembed_message_send(wid, XEMBED_EMBEDDED_NOTIFY, 0, m_containerWid, XEMBED_VERSION); //move window we're embedding const uint32_t windowMoveConfigVals[2] = { 0, 0 }; @@ -220,6 +223,22 @@ void SNIProxy::stackContainerWindow(const uint32_t stackMode) const xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_STACK_MODE, stackData); } +void SNIProxy::sendConfigureNotification() const +{ + xcb_configure_notify_event_t event; + memset(&event, 0x00, sizeof(xcb_configure_notify_event_t)); + event.response_type = XCB_CONFIGURE_NOTIFY; + event.event = m_windowId; + event.window = m_windowId; + event.x = 0; + event.y = 0; + event.width = s_embedSize; + event.height = s_embedSize; + + auto connection = QX11Info::connection(); + xcb_send_event(connection, false, m_windowId, XCB_EVENT_MASK_STRUCTURE_NOTIFY, reinterpret_cast(&event)); +} + QSize SNIProxy::calculateClientWindowSize() const { auto c = QX11Info::connection(); @@ -239,19 +258,12 @@ QSize SNIProxy::calculateClientWindowSize() const if (clientWindowSize.isEmpty() || clientWindowSize.width() > s_embedSize || clientWindowSize.height() > s_embedSize) { qCDebug(SNIPROXY) << "Resizing window" << m_windowId << Title() << "from w*h" << clientWindowSize; - xcb_configure_notify_event_t event; - memset(&event, 0x00, sizeof(xcb_configure_notify_event_t)); - event.response_type = XCB_CONFIGURE_NOTIFY; - event.event = m_windowId; - event.window = m_windowId; - event.width = s_embedSize; - event.height = s_embedSize; - xcb_send_event(c, false, m_windowId, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (char *) &event); + sendConfigureNotification(); - const uint32_t windowMoveConfigVals[2] = { s_embedSize, s_embedSize }; + const uint32_t windowSizeConfigVals[2] = { s_embedSize, s_embedSize }; xcb_configure_window(c, m_windowId, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, - windowMoveConfigVals); + windowSizeConfigVals); clientWindowSize = QSize(s_embedSize, s_embedSize); } diff --git a/xembed-sni-proxy/sniproxy.h b/xembed-sni-proxy/sniproxy.h index d3f004790..408c2f3c0 100644 --- a/xembed-sni-proxy/sniproxy.h +++ b/xembed-sni-proxy/sniproxy.h @@ -50,6 +50,7 @@ public: void update(); void stackContainerWindow(const uint32_t stackMode) const; + void sendConfigureNotification() const; /** * @return the category of the application associated to this item