From b8c6831a1fa5ecaae6a2fff7c3259c9d27adb771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Wed, 13 Feb 2013 08:10:55 +0100 Subject: [PATCH] Port Screenshot effect to XCB This includes: * getting cursor image through xcb_xfixes * using xcb_image_get for reading screen content in xrender case * using xcb_put_image to upload the generated screenshot into shared xpix Overall this means that QPixmap as an X Pixmap wrapper is no longer used. The conversion from xcb_image_t to QImage still needs some code for not matching byte order. I'm a little bit unsure about adding the code as I would not be able to test it. REVIEW: 109076 --- effects/CMakeLists.txt | 2 +- effects/screenshot/screenshot.cpp | 95 +++++++++++++++++-------------- effects/screenshot/screenshot.h | 1 - 3 files changed, 53 insertions(+), 45 deletions(-) diff --git a/effects/CMakeLists.txt b/effects/CMakeLists.txt index 6d2457cdf2..b64b5c2e62 100644 --- a/effects/CMakeLists.txt +++ b/effects/CMakeLists.txt @@ -3,7 +3,7 @@ kde4_no_enable_final(kwineffects) macro( KWIN4_ADD_EFFECT_BACKEND name ) kde4_add_plugin( ${name} ${ARGN} ) - target_link_libraries( ${name} kwineffects ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS} ${X11_Xfixes_LIB} ${X11_Xcursor_LIB} ${X11_LIBRARIES} ${XCB_XCB_LIBRARIES} ${X11_XCB_LIBRARIES} + target_link_libraries( ${name} kwineffects ${KDE4_KDEUI_LIBS} ${KDE4_PLASMA_LIBS} ${X11_Xfixes_LIB} ${X11_Xcursor_LIB} ${X11_LIBRARIES} ${XCB_XCB_LIBRARIES} ${XCB_IMAGE_LIBRARIES} ${X11_XCB_LIBRARIES} ${XCB_XFIXES_LIBRARIES}) endmacro( KWIN4_ADD_EFFECT_BACKEND ) diff --git a/effects/screenshot/screenshot.cpp b/effects/screenshot/screenshot.cpp index d3e33c8baf..02f02363b4 100644 --- a/effects/screenshot/screenshot.cpp +++ b/effects/screenshot/screenshot.cpp @@ -26,9 +26,7 @@ along with this program. If not, see . #include #include #include - -#include -#include +#include namespace KWin { @@ -55,6 +53,24 @@ ScreenShotEffect::~ScreenShotEffect() QDBusConnection::sessionBus().unregisterObject("/Screenshot"); QDBusConnection::sessionBus().unregisterService("org.kde.kwin.Screenshot"); } + +#ifdef KWIN_HAVE_XRENDER_COMPOSITING +static QImage xPictureToImage(xcb_render_picture_t srcPic, const QRect &geometry, xcb_image_t **xImage) +{ + xcb_pixmap_t xpix = xcb_generate_id(connection()); + xcb_create_pixmap(connection(), 32, xpix, rootWindow(), geometry.width(), geometry.height()); + XRenderPicture pic(xpix, 32); + xcb_render_composite(connection(), XCB_RENDER_PICT_OP_SRC, srcPic, XCB_RENDER_PICTURE_NONE, pic, + geometry.x(), geometry.y(), 0, 0, 0, 0, geometry.width(), geometry.height()); + xcb_flush(connection()); + *xImage = xcb_image_get(connection(), xpix, 0, 0, geometry.width(), geometry.height(), ~0, XCB_IMAGE_FORMAT_Z_PIXMAP); + QImage img((*xImage)->data, (*xImage)->width, (*xImage)->height, (*xImage)->stride, QImage::Format_ARGB32_Premultiplied); + // TODO: byte order might need swapping + xcb_free_pixmap(connection(), xpix); + return img; +} +#endif + void ScreenShotEffect::postPaintScreen() { effects->postPaintScreen(); @@ -129,18 +145,12 @@ void ScreenShotEffect::postPaintScreen() ScreenShotEffect::convertFromGLImage(img, width, height); } #ifdef KWIN_HAVE_XRENDER_COMPOSITING + xcb_image_t *xImage = NULL; if (effects->compositingType() == XRenderCompositing) { setXRenderOffscreen(true); effects->drawWindow(m_scheduledScreenshot, mask, QRegion(0, 0, width, height), d); if (xRenderOffscreenTarget()) { - xcb_pixmap_t xpix = xcb_generate_id(connection()); - xcb_create_pixmap(connection(), 32, xpix, rootWindow(), width, height); - // TODO: Qt5 - convert from xpixmap to QImage without a QPixmap - QPixmap pixmap = QPixmap::fromX11Pixmap(xpix); - xcb_render_composite(connection(), XCB_RENDER_PICT_OP_SRC, xRenderOffscreenTarget(), - XCB_RENDER_PICTURE_NONE, pixmap.x11PictureHandle(), 0, 0, 0, 0, 0, 0, width, height); - img = pixmap.toImage().copy(0, 0, width, height); - xcb_free_pixmap(connection(), xpix); + img = xPictureToImage(xRenderOffscreenTarget(), QRect(0, 0, width, height), &xImage); } setXRenderOffscreen(false); } @@ -150,18 +160,22 @@ void ScreenShotEffect::postPaintScreen() grabPointerImage(img, m_scheduledScreenshot->x() + left, m_scheduledScreenshot->y() + top); } - m_lastScreenshot = QPixmap::fromImage(img); - if (m_lastScreenshot.handle() == 0) { - Pixmap xpix = XCreatePixmap(display(), rootWindow(), m_lastScreenshot.width(), - m_lastScreenshot.height(), 32); - m_lastScreenshot = QPixmap::fromX11Pixmap(xpix, QPixmap::ExplicitlyShared); - QPainter p(&m_lastScreenshot); - p.setCompositionMode(QPainter::CompositionMode_Source); - p.drawImage(QPoint(0, 0), img); - p.end(); - XSync(display(), False); + const int depth = img.depth(); + xcb_pixmap_t xpix = xcb_generate_id(connection()); + xcb_create_pixmap(connection(), depth, xpix, rootWindow(), img.width(), img.height()); + + xcb_gcontext_t cid = xcb_generate_id(connection()); + xcb_create_gc(connection(), cid, xpix, 0, NULL); + xcb_put_image(connection(), XCB_IMAGE_FORMAT_Z_PIXMAP, xpix, cid, img.width(), img.height(), + 0, 0, 0, depth, img.byteCount(), img.constBits()); + xcb_free_gc(connection(), cid); + xcb_flush(connection()); + emit screenshotCreated(xpix); +#ifdef KWIN_HAVE_XRENDER_COMPOSITING + if (xImage) { + xcb_image_destroy(xImage); } - emit screenshotCreated(m_lastScreenshot.handle()); +#endif } m_scheduledScreenshot = NULL; } @@ -280,16 +294,12 @@ QString ScreenShotEffect::blitScreenshot(const QRect &geometry) ScreenShotEffect::convertFromGLImage(img, geometry.width(), geometry.height()); } +#ifdef KWIN_HAVE_XRENDER_COMPOSITING + xcb_image_t *xImage = NULL; +#endif if (effects->compositingType() == XRenderCompositing) { #ifdef KWIN_HAVE_XRENDER_COMPOSITING - QPixmap buffer(geometry.size()); - if (buffer.handle() == 0) { - Pixmap xpix = XCreatePixmap(display(), rootWindow(), geometry.width(), geometry.height(), 32); - buffer = QPixmap::fromX11Pixmap(xpix, QPixmap::ExplicitlyShared); - } - XRenderComposite(display(), PictOpSrc, effects->xrenderBufferPicture(), None, buffer.x11PictureHandle(), - 0, 0, 0, 0, geometry.x(), geometry.y(), geometry.width(), geometry.height()); - img = buffer.toImage(); + img = xPictureToImage(effects->xrenderBufferPicture(), geometry, &xImage); #endif } @@ -300,6 +310,11 @@ QString ScreenShotEffect::blitScreenshot(const QRect &geometry) return QString(); } img.save(&temp); +#ifdef KWIN_HAVE_XRENDER_COMPOSITING + if (xImage) { + xcb_image_destroy(xImage); + } +#endif temp.close(); return temp.fileName(); #endif @@ -308,24 +323,18 @@ QString ScreenShotEffect::blitScreenshot(const QRect &geometry) void ScreenShotEffect::grabPointerImage(QImage& snapshot, int offsetx, int offsety) // Uses the X11_EXTENSIONS_XFIXES_H extension to grab the pointer image, and overlays it onto the snapshot. { - XFixesCursorImage *xcursorimg = XFixesGetCursorImage(QX11Info::display()); - if (!xcursorimg) + QScopedPointer cursor( + xcb_xfixes_get_cursor_image_reply(connection(), + xcb_xfixes_get_cursor_image_unchecked(connection()), + NULL)); + if (cursor.isNull()) return; - //Annoyingly, xfixes specifies the data to be 32bit, but places it in an unsigned long * - //which can be 64 bit. So we need to iterate over a 64bit structure to put it in a 32bit - //structure. - QVarLengthArray< quint32 > pixels(xcursorimg->width * xcursorimg->height); - for (int i = 0; i < xcursorimg->width * xcursorimg->height; ++i) - pixels[i] = xcursorimg->pixels[i] & 0xffffffff; - - QImage qcursorimg((uchar *) pixels.data(), xcursorimg->width, xcursorimg->height, + QImage qcursorimg((uchar *) xcb_xfixes_get_cursor_image_cursor_image(cursor.data()), cursor->width, cursor->height, QImage::Format_ARGB32_Premultiplied); QPainter painter(&snapshot); - painter.drawImage(QPointF(xcursorimg->x - xcursorimg->xhot - offsetx, xcursorimg->y - xcursorimg ->yhot - offsety), qcursorimg); - - XFree(xcursorimg); + painter.drawImage(QPointF(cursor->x - cursor->xhot - offsetx, cursor->y - cursor ->yhot - offsety), qcursorimg); } void ScreenShotEffect::convertFromGLImage(QImage &img, int w, int h) diff --git a/effects/screenshot/screenshot.h b/effects/screenshot/screenshot.h index 18b50023bc..f541575915 100644 --- a/effects/screenshot/screenshot.h +++ b/effects/screenshot/screenshot.h @@ -84,7 +84,6 @@ private: void restoreMatrix(); EffectWindow *m_scheduledScreenshot; ScreenShotType m_type; - QPixmap m_lastScreenshot; }; } // namespace