Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Maintenance:4388
xembed-sni-proxy.openSUSE_Leap_42.1_Update
kde355684.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File kde355684.patch of Package xembed-sni-proxy.openSUSE_Leap_42.1_Update
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 --- sniproxy.cpp | 143 ++++++++++++++++++++++++++++++++---------- sniproxy.h | 5 +- 2 files changed, 114 insertions(+), 34 deletions(-) diff --git a/sniproxy.cpp b/sniproxy.cpp index ca2667f18f01a1f99b52422d8474aaabad107b92..ae6eab72e41832c4105fcf3ecb0249969d2525f7 100644 --- a/sniproxy.cpp +++ b/sniproxy.cpp @@ -33,7 +33,7 @@ #include <QGuiApplication> #include <QTimer> -#include <QPainter> +#include <QBitmap> #include <KWindowSystem> #include <netwm.h> @@ -191,48 +191,51 @@ SNIProxy::~SNIProxy() void SNIProxy::update() { const QImage image = getImageNonComposite(); + if (image.isNull()) { + qCDebug(SNIPROXY) << "No xembed icon for" << m_windowId << Title(); + return; + } int w = image.width(); int h = image.height(); + 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); - QImage qimage(image->data, image->width, image->height, image->stride, QImage::Format_ARGB32, sni_cleanup_xcb_image, 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); + + if (isTransparentImage(naiveConversion)) { + QImage elaborateConversion = QImage(convertFromNative(image)); + + // 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; + + switch (xcbImage->depth) { + case 1: + format = QImage::Format_MonoLSB; + break; + case 16: + format = QImage::Format_RGB16; + break; + case 24: + format = QImage::Format_RGB32; + break; + case 30: { + // Qt doesn't have a matching image format. We need to convert manually + quint32 *pixels = reinterpret_cast<quint32 *>(xcbImage->data); + for (uint i = 0; i < (xcbImage->size / 4); i++) { + int r = (pixels[i] >> 22) & 0xff; + int g = (pixels[i] >> 12) & 0xff; + int b = (pixels[i] >> 2) & 0xff; + + pixels[i] = qRgba(r, g, b, 0xff); + } + // fall through, Qt format is still Format_ARGB32_Premultiplied + } + case 32: + format = QImage::Format_ARGB32_Premultiplied; + break; + default: + return QImage(); // we don't know + } + + QImage image(xcbImage->data, xcbImage->width, xcbImage->height, xcbImage->stride, format, sni_cleanup_xcb_image, xcbImage); + + if (image.isNull()) { + return QImage(); + } + + if (format == QImage::Format_RGB32 && xcbImage->bpp == 32) + { + QImage m = image.createHeuristicMask(); + QBitmap mask(QPixmap::fromImage(m)); + QPixmap p = QPixmap::fromImage(image); + p.setMask(mask); + image = p.toImage(); + } + + // work around an abort in QImage::color + if (image.format() == QImage::Format_MonoLSB) { + image.setColorCount(2); + image.setColor(0, QColor(Qt::white).rgb()); + image.setColor(1, QColor(Qt::black).rgb()); + } - return qimage; + return image; } //____________properties__________ diff --git a/sniproxy.h b/sniproxy.h index 29aa56e381b034513d4683f047e1556679b57910..6ab5b7d6988b3e975ac562f7b591c2d9307574f0 100644 --- a/sniproxy.h +++ b/sniproxy.h @@ -28,6 +28,7 @@ #include <QPixmap> #include <xcb/xcb.h> +#include <xcb/xcb_image.h> #include "snidbus.h" @@ -140,7 +141,9 @@ Q_SIGNALS: private: void sendClick(uint8_t mouseButton, int x, int y); - QImage getImageNonComposite(); + QImage getImageNonComposite() const; + bool isTransparentImage(const QImage &image) const; + QImage convertFromNative(xcb_image_t *xcbImage) const; QDBusConnection m_dbus; xcb_window_t m_windowId; -- 2.6.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