Hrvoje Senjan 2015-12-13 23:48:07 +00:00 committed by Git OBS Bridge
parent a6cb2d2bbf
commit 6ff7e438c5

View File

@ -1,5 +1,22 @@
From 41df1bdb8b478eb27fb424d201c075c76ec0ed5a Mon Sep 17 00:00:00 2001
From: Benedikt Gollatz <benedikt@gollatz.net>
Date: Sun, 13 Dec 2015 20:47:57 +0000
Subject: [PATCH 1/1] Mitigate failed icon grabbing in xembed-sni-proxy
If grabbed icons are blank, try to salvage the copied data as well as
possible while leaving setups where image grabbing works fine alone.
Based on a patch by Rakyn Barker.
BUG:355684
REVIEW: 126336
---
xembed-sni-proxy/sniproxy.cpp | 143 ++++++++++++++++++++++++++++++++----------
xembed-sni-proxy/sniproxy.h | 5 +-
2 files changed, 114 insertions(+), 34 deletions(-)
diff --git a/xembed-sni-proxy/sniproxy.cpp b/xembed-sni-proxy/sniproxy.cpp diff --git a/xembed-sni-proxy/sniproxy.cpp b/xembed-sni-proxy/sniproxy.cpp
index ca2667f..0b7c072 100644 index ca2667f18f01a1f99b52422d8474aaabad107b92..ae6eab72e41832c4105fcf3ecb0249969d2525f7 100644
--- a/xembed-sni-proxy/sniproxy.cpp --- a/xembed-sni-proxy/sniproxy.cpp
+++ b/xembed-sni-proxy/sniproxy.cpp +++ b/xembed-sni-proxy/sniproxy.cpp
@@ -33,7 +33,7 @@ @@ -33,7 +33,7 @@
@ -11,7 +28,7 @@ index ca2667f..0b7c072 100644
#include <KWindowSystem> #include <KWindowSystem>
#include <netwm.h> #include <netwm.h>
@@ -191,6 +191,10 @@ @@ -191,48 +191,51 @@ SNIProxy::~SNIProxy()
void SNIProxy::update() void SNIProxy::update()
{ {
const QImage image = getImageNonComposite(); const QImage image = getImageNonComposite();
@ -22,17 +39,104 @@ index ca2667f..0b7c072 100644
int w = image.width(); int w = image.width();
int h = image.height(); int h = image.height();
@@ -240,11 +244,70 @@
+ 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();
+}
+
+void sni_cleanup_xcb_image(void *data) {
+ xcb_image_destroy(static_cast<xcb_image_t*>(data));
+}
+
+bool SNIProxy::isTransparentImage(const QImage& image) const
+{
+ 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;
+ if (! (qAlpha(image.pixel(w >> 1, h >> 1)) + qAlpha(image.pixel(w >> 2, h >> 2)) == 0))
+ return false;
// 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;
- }
- }
+ for (int x = 0; x < w; ++x) {
+ for (int y = 0; y < h; ++y) {
+ if (qAlpha(image.pixel(x, y))) {
+ // Found an opaque pixel.
+ return false;
+ }
+ }
}
- // Update icon only if it is at least partially opaque.
- // This is just a workaround for X11 bug: xembed icon may suddenly
- // become transparent for a one or few frames. Reproducible at least
- // 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 for" << m_windowId << Title();
- }
+ return true;
}
-void sni_cleanup_xcb_image(void *data) {
- xcb_image_destroy(static_cast<xcb_image_t*>(data));
-}
-
-QImage SNIProxy::getImageNonComposite()
+QImage SNIProxy::getImageNonComposite() const
{
auto c = QX11Info::connection();
auto cookie = xcb_get_geometry(c, m_windowId);
@@ -240,9 +243,83 @@ QImage SNIProxy::getImageNonComposite()
xcb_image_t *image = xcb_image_get(c, m_windowId, 0, 0, geom->width, geom->height, 0xFFFFFF, XCB_IMAGE_FORMAT_Z_PIXMAP); xcb_image_t *image = xcb_image_get(c, m_windowId, 0, 0, geom->width, geom->height, 0xFFFFFF, XCB_IMAGE_FORMAT_Z_PIXMAP);
- QImage qimage(image->data, image->width, image->height, image->stride, QImage::Format_ARGB32, sni_cleanup_xcb_image, image); - QImage qimage(image->data, image->width, image->height, image->stride, QImage::Format_ARGB32, sni_cleanup_xcb_image, image);
+ QImage qimage(convertFromNative(image)); + // Don't hook up cleanup yet, we may use a different QImage after all
+ QImage naiveConversion = QImage(image->data, image->width, image->height, QImage::Format_ARGB32);
return qimage; +
} + if (isTransparentImage(naiveConversion)) {
+ QImage elaborateConversion = QImage(convertFromNative(image));
+QImage SNIProxy::convertFromNative(xcb_image_t *xcbImage) +
+ // Update icon only if it is at least partially opaque.
+ // This is just a workaround for X11 bug: xembed icon may suddenly
+ // become transparent for a one or few frames. Reproducible at least
+ // with WINE applications.
+ if (isTransparentImage(elaborateConversion)) {
+ qCDebug(SNIPROXY) << "Skip transparent xembed icon for" << m_windowId << Title();
+ return QImage();
+ } else
+ return elaborateConversion;
+ } else {
+ // Now we are sure we can eventually delete the xcb_image_t with this version
+ return QImage(image->data, image->width, image->height, image->stride, QImage::Format_ARGB32, sni_cleanup_xcb_image, image);
+ }
+}
+
+QImage SNIProxy::convertFromNative(xcb_image_t *xcbImage) const
+{ +{
+ QImage::Format format = QImage::Format_Invalid; + QImage::Format format = QImage::Format_Invalid;
+ +
@ -65,7 +169,6 @@ index ca2667f..0b7c072 100644
+ return QImage(); // we don't know + return QImage(); // we don't know
+ } + }
+ +
+ //QImage image(xcbImage->data, xcbImage->width, xcbImage->height, format);
+ QImage image(xcbImage->data, xcbImage->width, xcbImage->height, xcbImage->stride, format, sni_cleanup_xcb_image, xcbImage); + QImage image(xcbImage->data, xcbImage->width, xcbImage->height, xcbImage->stride, format, sni_cleanup_xcb_image, xcbImage);
+ +
+ if (image.isNull()) { + if (image.isNull()) {
@ -87,15 +190,14 @@ index ca2667f..0b7c072 100644
+ image.setColor(0, QColor(Qt::white).rgb()); + image.setColor(0, QColor(Qt::white).rgb());
+ image.setColor(1, QColor(Qt::black).rgb()); + image.setColor(1, QColor(Qt::black).rgb());
+ } + }
+
+ return image;
+}
+
//____________properties__________
QString SNIProxy::Category() const - return qimage;
+ return image;
}
//____________properties__________
diff --git a/xembed-sni-proxy/sniproxy.h b/xembed-sni-proxy/sniproxy.h diff --git a/xembed-sni-proxy/sniproxy.h b/xembed-sni-proxy/sniproxy.h
index 29aa56e..89746a7 100644 index 29aa56e381b034513d4683f047e1556679b57910..6ab5b7d6988b3e975ac562f7b591c2d9307574f0 100644
--- a/xembed-sni-proxy/sniproxy.h --- a/xembed-sni-proxy/sniproxy.h
+++ b/xembed-sni-proxy/sniproxy.h +++ b/xembed-sni-proxy/sniproxy.h
@@ -28,6 +28,7 @@ @@ -28,6 +28,7 @@
@ -106,11 +208,17 @@ index 29aa56e..89746a7 100644
#include "snidbus.h" #include "snidbus.h"
@@ -141,6 +142,7 @@ @@ -140,7 +141,9 @@ Q_SIGNALS:
private: private:
void sendClick(uint8_t mouseButton, int x, int y); void sendClick(uint8_t mouseButton, int x, int y);
QImage getImageNonComposite(); - QImage getImageNonComposite();
+ QImage convertFromNative(xcb_image_t *xcbImage); + QImage getImageNonComposite() const;
+ bool isTransparentImage(const QImage &image) const;
+ QImage convertFromNative(xcb_image_t *xcbImage) const;
QDBusConnection m_dbus; QDBusConnection m_dbus;
xcb_window_t m_windowId; xcb_window_t m_windowId;
--
2.6.2