You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
plasma-workspace/0005-Merge-xembed-SNI-proxy...

214 lines
8.8 KiB

From c4d3d42ec4a9ec6fe08f2077072056dfb6b9994c Mon Sep 17 00:00:00 2001
From: Eugene Paskevich <eugene@raptor.kiev.ua>
Date: Wed, 4 Nov 2015 14:20:09 +0000
Subject: [PATCH 05/20] Merge xembed SNI proxy updates
Hush the NetWinInfo deprecation warning
Hush the int narrowing warning
Create the container window on-screen
Switch to 32x32 pixel icons and avoid scaling
Made sure container window is under mouse upon click
Reviewed-by: David Edmundson
---
xembed-sni-proxy/sniproxy.cpp | 100 +++++++++++++++++++++++++++---------------
1 file changed, 64 insertions(+), 36 deletions(-)
diff --git a/xembed-sni-proxy/sniproxy.cpp b/xembed-sni-proxy/sniproxy.cpp
index b5cf3c3..ca2667f 100644
--- a/xembed-sni-proxy/sniproxy.cpp
+++ b/xembed-sni-proxy/sniproxy.cpp
@@ -44,7 +44,7 @@
#define SNI_WATCHER_SERVICE_NAME "org.kde.StatusNotifierWatcher"
#define SNI_WATCHER_PATH "/StatusNotifierWatcher"
-static uint16_t s_embedSize = 48; //max size of window to embed. We no longer resize the embedded window as Chromium acts stupidly.
+static uint16_t s_embedSize = 32; //max size of window to embed. We no longer resize the embedded window as Chromium acts stupidly.
int SNIProxy::s_serviceCount = 0;
@@ -93,7 +93,7 @@ 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];
+ uint32_t values[2];
auto mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT;
values[0] = screen->black_pixel; //draw a solid background so the embeded icon doesn't get garbage in it
values[1] = true; //bypass wM
@@ -101,9 +101,9 @@ SNIProxy::SNIProxy(xcb_window_t wid, QObject* parent):
XCB_COPY_FROM_PARENT, /* depth */
m_containerWid, /* window Id */
screen->root, /* parent window */
- -500, 0, /* x, y */
+ 0, 0, /* x, y */
s_embedSize, s_embedSize, /* width, height */
- 0, /* border_width */
+ 0, /* border_width */
XCB_WINDOW_CLASS_INPUT_OUTPUT,/* class */
screen->root_visual, /* visual */
mask, values); /* masks */
@@ -123,7 +123,7 @@ SNIProxy::SNIProxy(xcb_window_t wid, QObject* parent):
const uint32_t stackBelowData[] = {XCB_STACK_MODE_BELOW};
xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_STACK_MODE, stackBelowData);
- NETWinInfo wm(c, m_containerWid, screen->root, 0);
+ NETWinInfo wm(c, m_containerWid, screen->root, 0, 0);
wm.setOpacity(0);
#endif
@@ -161,13 +161,13 @@ SNIProxy::SNIProxy(xcb_window_t wid, QObject* parent):
//this is needed as chormium and such when resized just fill the icon with transparent space and only draw in the middle
//however spotify does need this as by default the window size is 900px wide.
//use an artbitrary heuristic to make sure icons are always sensible
- if (clientGeom->width < 12 || clientGeom->width > s_embedSize ||
- clientGeom->height < 12 || clientGeom->height > s_embedSize)
+ if (clientGeom->width > s_embedSize || clientGeom->height > s_embedSize )
{
const uint32_t windowMoveConfigVals[2] = { s_embedSize, s_embedSize };
xcb_configure_window(c, wid,
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
windowMoveConfigVals);
+ qCDebug(SNIPROXY) << "Resizing window" << wid << Title() << "from w*h" << clientGeom->width << clientGeom->height;
}
//show the embedded window otherwise nothing happens
@@ -192,18 +192,22 @@ void SNIProxy::update()
{
const QImage image = getImageNonComposite();
- bool isTransparentImage = true;
-
- int sum = 0;
- for (int x = 0; x < image.width(); ++x) {
- for (int y = 0; y < image.height(); ++y) {
- sum += qAlpha(image.pixel(x, y));
- if (sum >= 255) {
- // There is enough amount of opaque pixels.
- isTransparentImage = false;
- break;
- }
- }
+ int w = image.width();
+ int h = image.height();
+
+ // check for the center and sub-center pixels first and avoid full image scan
+ bool isTransparentImage = qAlpha(image.pixel(w >> 1, h >> 1)) + qAlpha(image.pixel(w >> 2, h >> 2)) == 0;
+
+ // skip scan altogether if sub-center pixel found to be opaque
+ // and break out from the outer loop too on full scan
+ for (int x = 0; x < w && isTransparentImage; ++x) {
+ for (int y = 0; y < h; ++y) {
+ if (qAlpha(image.pixel(x, y))) {
+ // Found an opaque pixel.
+ isTransparentImage = false;
+ break;
+ }
+ }
}
// Update icon only if it is at least partially opaque.
@@ -212,10 +216,15 @@ void SNIProxy::update()
// with WINE applications.
if (!isTransparentImage) {
m_pixmap = QPixmap::fromImage(image);
+ if (w != s_embedSize || h != s_embedSize) {
+ qCDebug(SNIPROXY) << "Scaling pixmap of window" << m_windowId << Title() << "from w*h" << w << h;
+ m_pixmap = m_pixmap.scaled(s_embedSize, s_embedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ }
emit NewIcon();
+ emit NewToolTip();
}
else {
- qCDebug(SNIPROXY) << "Skip transparent xembed icon";
+ qCDebug(SNIPROXY) << "Skip transparent xembed icon for" << m_windowId << Title();
}
}
@@ -282,14 +291,14 @@ void SNIProxy::Activate(int x, int y)
sendClick(XCB_BUTTON_INDEX_1, x, y);
}
-void SNIProxy::ContextMenu(int x, int y)
+void SNIProxy::SecondaryActivate(int x, int y)
{
- sendClick(XCB_BUTTON_INDEX_3, x, y);
+ sendClick(XCB_BUTTON_INDEX_2, x, y);
}
-void SNIProxy::SecondaryActivate(int x, int y)
+void SNIProxy::ContextMenu(int x, int y)
{
- sendClick(XCB_BUTTON_INDEX_2, x, y);
+ sendClick(XCB_BUTTON_INDEX_3, x, y);
}
void SNIProxy::Scroll(int delta, const QString& orientation)
@@ -311,18 +320,41 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y)
//note x,y are not actually where the mouse is, but the plasmoid
//ideally we should make this match the plasmoid hit area
- qCDebug(SNIPROXY) << "Sending click " << mouseButton << "to" << x << y;
+ qCDebug(SNIPROXY) << "Received click" << mouseButton << "with passed x*y" << x << y;
auto c = QX11Info::connection();
- //set our window so the middle is where the mouse is
+ auto cookieSize = xcb_get_geometry(c, m_windowId);
+ QScopedPointer<xcb_get_geometry_reply_t> clientGeom(xcb_get_geometry_reply(c, cookieSize, Q_NULLPTR));
+
+ auto cookie = xcb_query_pointer(c, m_windowId);
+ QScopedPointer<xcb_query_pointer_reply_t> pointer(xcb_query_pointer_reply(c, cookie, Q_NULLPTR));
+ /*qCDebug(SNIPROXY) << "samescreen" << pointer->same_screen << endl
+ << "root x*y" << pointer->root_x << pointer->root_y << endl
+ << "win x*y" << pointer->win_x << pointer->win_y;*/
+
+ //move our window so the mouse is within its geometry
+ uint32_t configVals[2] = {0, 0};
+ if (mouseButton >= XCB_BUTTON_INDEX_4) {
+ //scroll event, take pointer position
+ configVals[0] = pointer->root_x;
+ configVals[1] = pointer->root_y;
+ } else {
+ if (pointer->root_x > x + clientGeom->width)
+ configVals[0] = pointer->root_x - clientGeom->width + 1;
+ else
+ configVals[0] = static_cast<uint32_t>(x);
+ if (pointer->root_y > y + clientGeom->height)
+ configVals[1] = pointer->root_y - clientGeom->height + 1;
+ else
+ configVals[1] = static_cast<uint32_t>(y);
+ }
+ xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, configVals);
+
+ //pull window up
const uint32_t stackAboveData[] = {XCB_STACK_MODE_ABOVE};
xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_STACK_MODE, stackAboveData);
- const uint32_t config_vals[4] = {x, y, s_embedSize, s_embedSize };
- xcb_configure_window(c, m_containerWid,
- XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
- config_vals);
//mouse down
{
xcb_button_press_event_t* event = new xcb_button_press_event_t;
@@ -364,13 +396,9 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y)
xcb_send_event(c, false, m_windowId, XCB_EVENT_MASK_BUTTON_RELEASE, (char *) event);
free(event);
}
+
#ifndef VISUAL_DEBUG
const uint32_t stackBelowData[] = {XCB_STACK_MODE_BELOW};
xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_STACK_MODE, stackBelowData);
#endif
- }
-
-
-
-
-//
+}
--
2.5.0