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
This commit is contained in:
parent
3809f58dbb
commit
b8c6831a1f
3 changed files with 53 additions and 45 deletions
|
@ -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 )
|
||||
|
||||
|
|
|
@ -26,9 +26,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <QtDBus/QDBusConnection>
|
||||
#include <QtCore/QVarLengthArray>
|
||||
#include <QtGui/QPainter>
|
||||
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
#include <QX11Info>
|
||||
#include <xcb/xcb_image.h>
|
||||
|
||||
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<xcb_xfixes_get_cursor_image_reply_t, QScopedPointerPodDeleter> 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)
|
||||
|
|
|
@ -84,7 +84,6 @@ private:
|
|||
void restoreMatrix();
|
||||
EffectWindow *m_scheduledScreenshot;
|
||||
ScreenShotType m_type;
|
||||
QPixmap m_lastScreenshot;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
Loading…
Reference in a new issue