File Calculate-first-clickable-point-from-the-top-left.patch of Package plasma5-workspace

From 989a7759a969c7b4dd677e5e1944d849a72450fa Mon Sep 17 00:00:00 2001
From: Konrad Materka <kmaterka@wp.pl>
Date: Wed, 28 Aug 2019 15:07:18 +0100
Subject: Calculate first clickable point, from the top-left

Summary:
Wine is using XWindow Shape Extension for transparent tray icons.
We need to find first clickable point starting from top-left.

BUG: 399234

Test Plan:
Bug fix test:
1. Enable KWin compositing;
2. Download this test program (SHA-1: 63ae606aee64259091e7f82436d4ecdf3a6e9047): https://www.nirsoft.net/utils/tflash210.zip
3. Run the .exe with Wine **Staging**
4. Right click on the icon
5. Context menu should show

Regression test:
1. Run XChat
2. Right click
3. Context menu should show in the same place as without patch

Reviewers: davidedmundson, #plasma_workspaces

Reviewed By: davidedmundson, #plasma_workspaces

Subscribers: davidedmundson, plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D22767
---
 xembed-sni-proxy/sniproxy.cpp | 58 ++++++++++++++++++++++++++++++++++++++-----
 xembed-sni-proxy/sniproxy.h   |  2 ++
 2 files changed, 54 insertions(+), 6 deletions(-)

diff --git a/xembed-sni-proxy/sniproxy.cpp b/xembed-sni-proxy/sniproxy.cpp
index 5b687c4..46ebb4c 100644
--- a/xembed-sni-proxy/sniproxy.cpp
+++ b/xembed-sni-proxy/sniproxy.cpp
@@ -373,6 +373,51 @@ QImage SNIProxy::convertFromNative(xcb_image_t *xcbImage) const
     return image;
 }
 
+/*
+  Wine is using XWindow Shape Extension for transparent tray icons.
+  We need to find first clickable point starting from top-left.
+*/
+QPoint SNIProxy::calculateClickPoint() const
+{
+    QPoint clickPoint = QPoint(0, 0);
+
+    auto c = QX11Info::connection();
+
+    // request extent to check if shape has been set
+    xcb_shape_query_extents_cookie_t extentsCookie = xcb_shape_query_extents(c, m_windowId);
+    // 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));
+
+    if (!extentsReply || !rectanglesReply || !extentsReply->bounding_shaped) {
+        return clickPoint;
+    }
+
+    xcb_rectangle_t *rectangles = xcb_shape_get_rectangles_rectangles(rectanglesReply.data());
+    if (!rectangles) {
+        return clickPoint;
+    }
+
+    const QImage image = getImageNonComposite();
+
+    double minLength = sqrt(pow(image.height(), 2) + pow(image.width(), 2));
+    const int nRectangles = xcb_shape_get_rectangles_rectangles_length(rectanglesReply.data());
+    for (int i = 0; i < nRectangles; ++i) {
+        double length = sqrt(pow(rectangles[i].x, 2) + pow(rectangles[i].y, 2));
+        if (length < minLength) {
+            minLength = length;
+            clickPoint = QPoint(rectangles[i].x, rectangles[i].y);
+        }
+    }
+
+    qCDebug(SNIPROXY) << "Click point:" << clickPoint;
+    return clickPoint;
+}
+
 //____________properties__________
 
 QString SNIProxy::Category() const
@@ -474,6 +519,7 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y)
 
     //move our window so the mouse is within its geometry
     uint32_t configVals[2] = {0, 0};
+    const QPoint clickPoint = calculateClickPoint();
     if (mouseButton >= XCB_BUTTON_INDEX_4) {
 	//scroll event, take pointer position
 	configVals[0] = pointer->root_x;
@@ -482,11 +528,11 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y)
 	if (pointer->root_x > x + clientGeom->width)
 	    configVals[0] = pointer->root_x - clientGeom->width + 1;
 	else
-	    configVals[0] = static_cast<uint32_t>(x);
+	    configVals[0] = static_cast<uint32_t>(x - clickPoint.x());
 	if (pointer->root_y > y + clientGeom->height)
 	    configVals[1] = pointer->root_y - clientGeom->height + 1;
 	else
-	    configVals[1] = static_cast<uint32_t>(y);
+	    configVals[1] = static_cast<uint32_t>(y - clickPoint.y());
     }
     xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, configVals);
 
@@ -505,8 +551,8 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y)
         event->root = QX11Info::appRootWindow();
         event->root_x = x;
         event->root_y = y;
-        event->event_x = 0;
-        event->event_y = 0;
+        event->event_x = static_cast<int16_t>(clickPoint.x());
+        event->event_y = static_cast<int16_t>(clickPoint.y());
         event->child = 0;
         event->state = 0;
         event->detail = mouseButton;
@@ -529,8 +575,8 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y)
         event->root = QX11Info::appRootWindow();
         event->root_x = x;
         event->root_y = y;
-        event->event_x = 0;
-        event->event_y = 0;
+        event->event_x = static_cast<int16_t>(clickPoint.x());
+        event->event_y = static_cast<int16_t>(clickPoint.y());
         event->child = 0;
         event->state = 0;
         event->detail = mouseButton;
diff --git a/xembed-sni-proxy/sniproxy.h b/xembed-sni-proxy/sniproxy.h
index 1f4d56e..8496a4c 100644
--- a/xembed-sni-proxy/sniproxy.h
+++ b/xembed-sni-proxy/sniproxy.h
@@ -26,6 +26,7 @@
 #include <QDBusConnection>
 #include <QDBusObjectPath>
 #include <QPixmap>
+#include <QPoint>
 
 #include <xcb/xcb.h>
 #include <xcb/xcb_image.h>
@@ -149,6 +150,7 @@ private:
     QImage getImageNonComposite() const;
     bool isTransparentImage(const QImage &image) const;
     QImage convertFromNative(xcb_image_t *xcbImage) const;
+    QPoint calculateClickPoint() const;
 
     QDBusConnection m_dbus;
     xcb_window_t m_windowId;
-- 
cgit v1.1

openSUSE Build Service is sponsored by