Git commit fb5dde6604b0d82e69ce9912f7188383940609c7 by Aaron Seigo. Committed on 15/09/2014 at 07:09. Pushed by aseigo into branch 'frameworks'. use XCB to convert native handles adapted from patch by Martin Gr=C3=A4=C3=9Flin M +54 -17 CMakeLists.txt A +31 -0 cmake/modules/FindX11_XCB.cmake A +238 -0 cmake/modules/FindXCB.cmake M +10 -4 config-ksnapshot.h.cmake M +23 -61 ksnapshot.cpp M +0 -1 ksnapshot.h A +178 -0 xcb/pixmaphelper.cpp [License: GPL (v2+)] A +34 -0 xcb/pixmaphelper.h [License: GPL (v2+)] A +209 -0 xcb/xcbutils.h [License: GPL (v2)] http://commits.kde.org/ksnapshot/fb5dde6604b0d82e69ce9912f7188383940609c7 diff --git a/CMakeLists.txt b/CMakeLists.txt index b2f2dc7..69d6fc9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,11 @@ set (QT_MIN_VERSION "5.2.0") #macro_optional_find_package(Kipi) = find_package(ECM 1.1.0 REQUIRED NO_MODULE) -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MO= DULE_DIR}) + +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules + ${CMAKE_MODULE_PATH} + ${ECM_MODULE_PATH} + ${ECM_KDE_MODULE_DIR}) = include(KDEInstallDirs) include(KDECMakeSettings) @@ -34,21 +38,22 @@ add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FA= ST_OPERATOR_PLUS) find_package(X11) if (X11_FOUND) set(HAVE_X11 1) +endif(X11_FOUND) = - if (X11_Xshape_FOUND) - set(HAVE_X11_EXTENSIONS_SHAPE_H 1) - endif (X11_Xshape_FOUND) +find_package(XCB MODULE COMPONENTS XCB SHAPE XFIXES) +set_package_properties(XCB PROPERTIES DESCRIPTION "X protocol C-language B= inding" + URL "http://xcb.freedesktop.org" + TYPE OPTIONAL) +find_package(X11_XCB MODULE) +set_package_properties(X11_XCB PROPERTIES DESCRIPTION "Xlib/XCB interface = library" + URL "http://xcb.freedesktop.org" + TYPE OPTIONAL) = - if (X11_Xfixes_FOUND) - set(HAVE_X11_EXTENSIONS_XFIXES_H 1) - endif (X11_Xfixes_FOUND) -endif (X11_FOUND) -#feature_summary(WHAT ENABLED_FEATURES DESCRIPTION "X11 Fixes Extension (x= fixes.h)" "Support for capturing the cursor" "http://www.x.org/" VAR HAVE_X= 11_EXTENSIONS_XFIXES_H) +#include_directories(${CMAKE_CURRENT_SOURCE_DIR}) = if (KIPI_FOUND) - include_directories(${KIPI_INCLUDE_DIR}) + include_directories(${KIPI_INCLUDE_DIR}) endif (KIPI_FOUND) -#macro_log_feature(KIPI_FOUND "KIPI plugins" "Provides various image expor= t features, such as printing, emailing and uploading" "http://www.kipi-plug= ins.org/" FALSE "" "") = configure_file(config-ksnapshot.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config= -ksnapshot.h) = @@ -65,6 +70,12 @@ set(ksnapshot_file_SRCS ksnapshotobject.cpp ksnapshotpreview.cpp) = +if (XCB_XCB_FOUND AND X11_XCB_FOUND) + set(ksnapshot_xcb_SRCS + # windowgrabber_x11.cpp + xcb/pixmaphelper.cpp) +endif (XCB_XCB_FOUND AND X11_XCB_FOUND) + if (KIPI_FOUND) set(ksnapshot_kipi_SRCS kipiinterface.cpp @@ -76,6 +87,7 @@ endif (KIPI_FOUND) set(ksnapshot_SRCS main.cpp ksnapshot.cpp = + ${ksnapshot_xcb_SRCS} ${ksnapshot_file_SRCS} ${ksnapshot_kipi_SRCS}) = @@ -100,11 +112,21 @@ target_link_libraries(ksnapshot KF5::KIOWidgets KF5::WindowSystem KF5::XmlGui - ${X11_LIBRARIES}) - -if (X11_Xfixes_FOUND) - target_link_libraries(ksnapshot ${X11_Xfixes_LIB}) -endif (X11_Xfixes_FOUND) + ${X11_LIBRARIES} + ) + +if (X11_XCB_FOUND) + target_link_libraries(ksnapshot ${X11_XCB_LIBRARIES}) +endif () +if (XCB_XCB_FOUND) + target_link_libraries(ksnapshot ${XCB_XCB_LIBRARY}) +endif () +if (XCB_SHAPE_FOUND) + target_link_libraries(ksnapshot ${XCB_SHAPE_LIBRARY}) +endif () +if (XCB_XFIXES_FOUND) + target_link_libraries(ksnapshot ${XCB_XFIXES_LIBRARY}) +endif () = if (KIPI_FOUND) target_link_libraries(ksnapshot ${KIPI_LIBRARIES}) @@ -129,7 +151,22 @@ target_link_libraries(kbackgroundsnapshot KF5::I18n KF5::KIOWidgets KF5::WindowSystem - ${X11_LIBRARIES}) + ${X11_LIBRARIES} + ) + +target_link_libraries(kbackgroundsnapshot ${KDE4_KIO_LIBS}) + +if (X11_XCB_FOUND) + target_link_libraries(kbackgroundsnapshot ${X11_XCB_LIBRARIES}) +endif () + +if (XCB_XCB_FOUND) + target_link_libraries(kbackgroundsnapshot ${XCB_XCB_LIBRARY}) +endif () + +if (XCB_SHAPE_FOUND) + target_link_libraries(kbackgroundsnapshot ${XCB_SHAPE_LIBRARY}) +endif () = install(TARGETS kbackgroundsnapshot ${INSTALL_TARGETS_DEFAULT_ARGS}) = diff --git a/cmake/modules/FindX11_XCB.cmake b/cmake/modules/FindX11_XCB.cm= ake new file mode 100644 index 0000000..e2c18a9 --- /dev/null +++ b/cmake/modules/FindX11_XCB.cmake @@ -0,0 +1,31 @@ +# - Try to find libX11-xcb +# Once done this will define +# +# X11_XCB_FOUND - system has libX11-xcb +# X11_XCB_LIBRARIES - Link these to use libX11-xcb +# X11_XCB_INCLUDE_DIR - the libX11-xcb include dir +# X11_XCB_DEFINITIONS - compiler switches required for using libX11-xcb + +# Copyright (c) 2011 Fredrik H=C3=B6glund +# Copyright (c) 2008 Helio Chissini de Castro, +# Copyright (c) 2007 Matthias Kretz, +# +# Redistribution and use is allowed according to the terms of the BSD lice= nse. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +IF (NOT WIN32) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + FIND_PACKAGE(PkgConfig) + PKG_CHECK_MODULES(PKG_X11_XCB QUIET x11-xcb) + + SET(X11_XCB_DEFINITIONS ${PKG_X11_XCB_CFLAGS}) + + FIND_PATH(X11_XCB_INCLUDE_DIR NAMES X11/Xlib-xcb.h HINTS ${PKG_X11_XCB_= INCLUDE_DIRS}) + FIND_LIBRARY(X11_XCB_LIBRARIES NAMES X11-xcb HINTS ${PKG_X11_XCB_= LIBRARY_DIRS}) + + include(FindPackageHandleStandardArgs) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(X11_XCB DEFAULT_MSG X11_XCB_LIBRARIES = X11_XCB_INCLUDE_DIR) + + MARK_AS_ADVANCED(X11_XCB_INCLUDE_DIR X11_XCB_LIBRARIES) +ENDIF (NOT WIN32) diff --git a/cmake/modules/FindXCB.cmake b/cmake/modules/FindXCB.cmake new file mode 100644 index 0000000..823d167 --- /dev/null +++ b/cmake/modules/FindXCB.cmake @@ -0,0 +1,238 @@ +# Try to find XCB on a Unix system +# +# This will define: +# +# XCB_FOUND - True if xcb is available +# XCB_LIBRARIES - Link these to use xcb +# XCB_INCLUDE_DIRS - Include directory for xcb +# XCB_DEFINITIONS - Compiler flags for using xcb +# +# In addition the following more fine grained variables will be defined: +# +# XCB_XCB_FOUND XCB_XCB_INCLUDE_DIR XCB_XCB_LIBRARY +# XCB_UTIL_FOUND XCB_UTIL_INCLUDE_DIR XCB_UTIL_LIBRARY +# XCB_COMPOSITE_FOUND XCB_COMPOSITE_INCLUDE_DIR XCB_COMPOSITE_LIBRARY +# XCB_DAMAGE_FOUND XCB_DAMAGE_INCLUDE_DIR XCB_DAMAGE_LIBRARY +# XCB_XFIXES_FOUND XCB_XFIXES_INCLUDE_DIR XCB_XFIXES_LIBRARY +# XCB_RENDER_FOUND XCB_RENDER_INCLUDE_DIR XCB_RENDER_LIBRARY +# XCB_RANDR_FOUND XCB_RANDR_INCLUDE_DIR XCB_RANDR_LIBRARY +# XCB_SHAPE_FOUND XCB_SHAPE_INCLUDE_DIR XCB_SHAPE_LIBRARY +# XCB_DRI2_FOUND XCB_DRI2_INCLUDE_DIR XCB_DRI2_LIBRARY +# XCB_GLX_FOUND XCB_GLX_INCLUDE_DIR XCB_GLX_LIBRARY +# XCB_SHM_FOUND XCB_SHM_INCLUDE_DIR XCB_SHM_LIBRARY +# XCB_XV_FOUND XCB_XV_INCLUDE_DIR XCB_XV_LIBRARY +# XCB_SYNC_FOUND XCB_SYNC_INCLUDE_DIR XCB_SYNC_LIBRARY +# XCB_XTEST_FOUND XCB_XTEST_INCLUDE_DIR XCB_XTEST_LIBRARY +# XCB_ICCCM_FOUND XCB_ICCCM_INCLUDE_DIR XCB_ICCCM_LIBRARY +# XCB_EWMH_FOUND XCB_EWMH_INCLUDE_DIR XCB_EWMH_LIBRARY +# XCB_IMAGE_FOUND XCB_IMAGE_INCLUDE_DIR XCB_IMAGE_LIBRARY +# XCB_RENDERUTIL_FOUND XCB_RENDERUTIL_INCLUDE_DIR XCB_RENDERUTIL_LIBRARY +# XCB_KEYSYMS_FOUND XCB_KEYSYMS_INCLUDE_DIR XCB_KEYSYMS_LIBRARY +# +# Copyright (c) 2011 Fredrik H=C3=B6glund +# Copyright (c) 2013 Martin Gr=C3=A4=C3=9Flin +# +# Redistribution and use is allowed according to the terms of the BSD lice= nse. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +set(knownComponents XCB + COMPOSITE + DAMAGE + DRI2 + EWMH + GLX + ICCCM + IMAGE + KEYSYMS + RANDR + RENDER + RENDERUTIL + SHAPE + SHM + SYNC + UTIL + XFIXES + XTEST + XV) + +unset(unknownComponents) + +set(pkgConfigModules) +set(requiredComponents) + +if (XCB_FIND_COMPONENTS) + set(comps ${XCB_FIND_COMPONENTS}) +else() + set(comps ${knownComponents}) +endif() + +# iterate through the list of requested components, and check that we know= them all. +# If not, fail. +foreach(comp ${comps}) + list(FIND knownComponents ${comp} index ) + if("${index}" STREQUAL "-1") + list(APPEND unknownComponents "${comp}") + else() + if("${comp}" STREQUAL "XCB") + list(APPEND pkgConfigModules "xcb") + elseif("${comp}" STREQUAL "COMPOSITE") + list(APPEND pkgConfigModules "xcb-composite") + elseif("${comp}" STREQUAL "DAMAGE") + list(APPEND pkgConfigModules "xcb-damage") + elseif("${comp}" STREQUAL "DRI2") + list(APPEND pkgConfigModules "xcb-dri2") + elseif("${comp}" STREQUAL "EWMH") + list(APPEND pkgConfigModules "xcb-ewmh") + elseif("${comp}" STREQUAL "GLX") + list(APPEND pkgConfigModules "xcb-glx") + elseif("${comp}" STREQUAL "ICCCM") + list(APPEND pkgConfigModules "xcb-icccm") + elseif("${comp}" STREQUAL "IMAGE") + list(APPEND pkgConfigModules "xcb-image") + elseif("${comp}" STREQUAL "KEYSYMS") + list(APPEND pkgConfigModules "xcb-keysyms") + elseif("${comp}" STREQUAL "RANDR") + list(APPEND pkgConfigModules "xcb-randr") + elseif("${comp}" STREQUAL "RENDER") + list(APPEND pkgConfigModules "xcb-render") + elseif("${comp}" STREQUAL "RENDERUTIL") + list(APPEND pkgConfigModules "xcb-renderutil") + elseif("${comp}" STREQUAL "SHAPE") + list(APPEND pkgConfigModules "xcb-shape") + elseif("${comp}" STREQUAL "SHM") + list(APPEND pkgConfigModules "xcb-shm") + elseif("${comp}" STREQUAL "SYNC") + list(APPEND pkgConfigModules "xcb-sync") + elseif("${comp}" STREQUAL "UTIL") + list(APPEND pkgConfigModules "xcb-util") + elseif("${comp}" STREQUAL "XFIXES") + list(APPEND pkgConfigModules "xcb-xfixes") + elseif("${comp}" STREQUAL "XTEST") + list(APPEND pkgConfigModules "xcb-xtest") + elseif("${comp}" STREQUAL "XV") + list(APPEND pkgConfigModules "xcb-xv") + endif() + endif() +endforeach() + + +if(DEFINED unknownComponents) + set(msgType STATUS) + if(XCB_FIND_REQUIRED) + set(msgType FATAL_ERROR) + endif() + if(NOT XCB_FIND_QUIETLY) + message(${msgType} "XCB: requested unknown components ${unknownCompo= nents}") + endif() + return() +endif() + +macro(_XCB_HANDLE_COMPONENT _comp) + set(_header ) + set(_lib ) + if("${_comp}" STREQUAL "XCB") + set(_header "xcb/xcb.h") + set(_lib "xcb") + elseif("${_comp}" STREQUAL "COMPOSITE") + set(_header "xcb/composite.h") + set(_lib "xcb-composite") + elseif("${_comp}" STREQUAL "DAMAGE") + set(_header "xcb/damage.h") + set(_lib "xcb-damage") + elseif("${_comp}" STREQUAL "DRI2") + set(_header "xcb/dri2.h") + set(_lib "xcb-dri2") + elseif("${_comp}" STREQUAL "EWMH") + set(_header "xcb/xcb_ewmh.h") + set(_lib "xcb-ewmh") + elseif("${_comp}" STREQUAL "GLX") + set(_header "xcb/glx.h") + set(_lib "xcb-glx") + elseif("${_comp}" STREQUAL "ICCCM") + set(_header "xcb/xcb_icccm.h") + set(_lib "xcb-icccm") + elseif("${_comp}" STREQUAL "IMAGE") + set(_header "xcb/xcb_image.h") + set(_lib "xcb-image") + elseif("${_comp}" STREQUAL "KEYSYMS") + set(_header "xcb/xcb_keysyms.h") + set(_lib "xcb-keysyms") + elseif("${_comp}" STREQUAL "RANDR") + set(_header "xcb/randr.h") + set(_lib "xcb-randr") + elseif("${_comp}" STREQUAL "RENDER") + set(_header "xcb/render.h") + set(_lib "xcb-render") + elseif("${_comp}" STREQUAL "RENDERUTIL") + set(_header "xcb/xcb_renderutil.h") + set(_lib "xcb-render-util") + elseif("${_comp}" STREQUAL "SHAPE") + set(_header "xcb/shape.h") + set(_lib "xcb-shape") + elseif("${_comp}" STREQUAL "SHM") + set(_header "xcb/shm.h") + set(_lib "xcb-shm") + elseif("${_comp}" STREQUAL "SYNC") + set(_header "xcb/sync.h") + set(_lib "xcb-sync") + elseif("${_comp}" STREQUAL "UTIL") + set(_header "xcb/xcb_util.h") + set(_lib "xcb-util") + elseif("${_comp}" STREQUAL "XFIXES") + set(_header "xcb/xfixes.h") + set(_lib "xcb-xfixes") + elseif("${_comp}" STREQUAL "XTEST") + set(_header "xcb/xtest.h") + set(_lib "xcb-xtest") + elseif("${_comp}" STREQUAL "XV") + set(_header "xcb/xv.h") + set(_lib "xcb-xv") + endif() + + find_path(XCB_${_comp}_INCLUDE_DIR NAMES ${_header} HINTS ${PKG_XCB_IN= CLUDE_DIRS}) + find_library(XCB_${_comp}_LIBRARY NAMES ${_lib} HINTS ${PKG_XCB_LIBRAR= Y_DIRS}) + + if(XCB_${_comp}_INCLUDE_DIR AND XCB_${_comp}_LIBRARY) + list(APPEND XCB_INCLUDE_DIRS ${XCB_${_comp}_INCLUDE_DIR}) + list(APPEND XCB_LIBRARIES ${XCB_${_comp}_LIBRARY}) + if (NOT XCB_FIND_QUIETLY) + message(STATUS "XCB[${_comp}]: Found component ${_comp}") + endif() + endif() + + if(XCB_FIND_REQUIRED_${_comp}) + list(APPEND requiredComponents XCB_${_comp}_FOUND) + endif() + + find_package_handle_standard_args(XCB_${_comp} DEFAULT_MSG XCB_${_comp= }_LIBRARY XCB_${_comp}_INCLUDE_DIR) + + mark_as_advanced(XCB_${_comp}_LIBRARY XCB_${_comp}_INCLUDE_DIR) + + # compatibility for old variable naming + set(XCB_${_comp}_INCLUDE_DIRS ${XCB_${_comp}_INCLUDE_DIR}) + set(XCB_${_comp}_LIBRARIES ${XCB_${_comp}_LIBRARY}) +endmacro() + +IF (NOT WIN32) + include(FindPackageHandleStandardArgs) + # Use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + find_package(PkgConfig) + pkg_check_modules(PKG_XCB QUIET ${pkgConfigModules}) + + set(XCB_DEFINITIONS ${PKG_XCB_CFLAGS}) + + foreach(comp ${comps}) + _xcb_handle_component(${comp}) + endforeach() + + if(XCB_INCLUDE_DIRS) + list(REMOVE_DUPLICATES XCB_INCLUDE_DIRS) + endif() + + find_package_handle_standard_args(XCB DEFAULT_MSG XCB_LIBRARIES XCB_IN= CLUDE_DIRS ${requiredComponents}) + + # compatibility for old variable naming + set(XCB_INCLUDE_DIR ${XCB_INCLUDE_DIRS}) + +ENDIF (NOT WIN32) diff --git a/config-ksnapshot.h.cmake b/config-ksnapshot.h.cmake index a70b068..3514dd5 100644 --- a/config-ksnapshot.h.cmake +++ b/config-ksnapshot.h.cmake @@ -1,11 +1,17 @@ /* Define to 1 if we are building with X11 */ #cmakedefine01 HAVE_X11 = -/* Define to 1 if you have the header file. */ -#cmakedefine01 HAVE_X11_EXTENSIONS_SHAPE_H +/* Define to 1 if you have xcb */ +#cmakedefine XCB_XCB_FOUND 1 = -/* Define to 1 if you have the header file. */ -#cmakedefine01 HAVE_X11_EXTENSIONS_XFIXES_H +/* Define to 1 if you have x11-xcb */ +#cmakedefine X11_XCB_FOUND 1 + +/* Define to 1 if you have xfixes */ +#cmakedefine XCB_XFIXES_FOUND 1 + +/* Define to 1 if you have shape */ +#cmakedefine XCB_SHAPE_FOUND 1 = /* Define to 1 if you have libkipi */ #cmakedefine KIPI_FOUND diff --git a/ksnapshot.cpp b/ksnapshot.cpp index fd9a2ad..2bc458e 100644 --- a/ksnapshot.cpp +++ b/ksnapshot.cpp @@ -84,12 +84,16 @@ #include #endif = -#if HAVE_X11_EXTENSIONS_XFIXES_H -#include +#if HAVE_X11 #include +#include #include #endif = +#if XCB_XCB_FOUND +#include +#endif + class KSnapshotWidget : public QWidget, public Ui::KSnapshotWidget { public: @@ -105,8 +109,7 @@ KSnapshot::KSnapshot(QWidget *parent, KSnapshotObject:= :CaptureMode mode) : QDialog(parent), KSnapshotObject(), m_modified(true), - m_savedPosition(QPoint(-1, -1)), - m_haveXFixes(false) + m_savedPosition(QPoint(-1, -1)) { // TEMPORARY Make sure "untitled" enters the string freeze for 4.6, // as explained in http://lists.kde.org/?l=3Dkde-graphics-devel&m=3D12= 8942871430175&w=3D2 @@ -197,32 +200,19 @@ KSnapshot::KSnapshot(QWidget *parent, KSnapshotObjec= t::CaptureMode mode) KConfigGroup conf(KSharedConfig::openConfig(), "GENERAL"); = #ifdef KIPI_FOUND -#if(KIPI_VERSION >=3D 0x020000) - m_pluginLoader =3D new KIPI::PluginLoader(); - m_pluginLoader->setInterface(new KIPIInterface(this)); - m_pluginLoader->init(); -#else - m_pluginLoader =3D new KIPI::PluginLoader(QStringList(), new KIPIInter= face(this), ""); -#endif + #if(KIPI_VERSION >=3D 0x020000) + m_pluginLoader =3D new KIPI::PluginLoader(); + m_pluginLoader->setInterface(new KIPIInterface(this)); + m_pluginLoader->init(); + #else + m_pluginLoader =3D new KIPI::PluginLoader(QStringList(), new KIPII= nterface(this), ""); + #endif #endif = -#if HAVE_X11_EXTENSIONS_XFIXES_H +#if HAVE_X11 { - int tmp1, tmp2; - //Check whether the XFixes extension is available + // prevent KWin from animating the window in the compositor Display *dpy =3D QX11Info::display(); - if (!XFixesQueryExtension(dpy, &tmp1, &tmp2)) { - m_snapshotWidget->cbIncludePointer->hide(); - m_snapshotWidget->lblIncludePointer->hide(); - } else { - m_haveXFixes =3D true; - } - - // actually not depending on XFixes, but to simplify the ifdefs pu= t here - // we can safely assume that XFixes is present for this functional= ity - // it's supposed to prevent that KWin animates the window in the c= ompositor - // and XFixes is a requirement for the compositor. So if XFixes is= not present - // KWin cannot be compiled at all. Atom atom =3D XInternAtom(dpy, "_KDE_NET_WM_SKIP_CLOSE_ANIMATION",= False); long d =3D 1; XChangeProperty(dpy, winId(), atom, XA_CARDINAL, 32, @@ -620,13 +610,8 @@ void KSnapshot::slotWindowGrabbed(const QPixmap &pix) = void KSnapshot::slotScreenshotReceived(qulonglong handle) { -#if HAVE_X11 - //FIXME: there is no fromX11Pixmap anymore and nothing there to replac= e it - // may have to write our own thing? want to look around a bit mo= re - // to see if anyone has beaten us to that. i mean, screen shotti= ng - // is *not* an uncommon task. Since this comes from kwin, perhaps - // discuss with kwin developers. - //slotWindowGrabbed( QPixmap::fromX11Pixmap( handle ) ); +#if XCB_XCB_FOUND + slotWindowGrabbed(PixmapHelperXCB::grabWindow(handle)); #else Q_UNUSED(handle) #endif @@ -803,39 +788,16 @@ void KSnapshot::performGrab() show(); } = -// Uses the X11_EXTENSIONS_XFIXES_H extension to grab the pointer image, a= nd overlays it onto the snapshot. +// Grabs the pointer image if there is platform support for it, and overla= ys it onto the snapshot. void KSnapshot::grabPointerImage(int offsetx, int offsety) { -#if HAVE_X11_EXTENSIONS_XFIXES_H - if (!m_haveXFixes || !includePointer()) { - return; - } - - XFixesCursorImage *xcursorimg =3D XFixesGetCursorImage(QX11Info::displ= ay()); - if (!xcursorimg) { - 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 t= o put it in a 32bit - //structure. - QVarLengthArray< quint32 > pixels(xcursorimg->width * xcursorimg->heig= ht); - for (int i =3D 0; i < xcursorimg->width * xcursorimg->height; ++i) { - pixels[i] =3D xcursorimg->pixels[i] & 0xffffffff; - } - - QImage qcursorimg((uchar *) pixels.data(), xcursorimg->width, xcursori= mg->height, - QImage::Format_ARGB32_Premultiplied); - - QPainter painter(&m_snapshot); - painter.drawImage(QPointF(xcursorimg->x - xcursorimg->xhot - offsetx, = xcursorimg->y - xcursorimg ->yhot - offsety), qcursorimg); - - XFree(xcursorimg); -#else // HAVE_X11_EXTENSIONS_XFIXES_H +#if XCB_XFIXES_FOUND + PixmapHelperXCB::compositePointer(offsetx, offsety, m_snapshot); +#else Q_UNUSED(offsetx); Q_UNUSED(offsety); return; -#endif // HAVE_X11_EXTENSIONS_XFIXES_H +#endif } = void KSnapshot::setTime(int newTime) diff --git a/ksnapshot.h b/ksnapshot.h index 3c71ce9..51836bc 100644 --- a/ksnapshot.h +++ b/ksnapshot.h @@ -142,7 +142,6 @@ private: KSnapshotWidget *m_snapshotWidget; bool m_modified; QPoint m_savedPosition; - bool m_haveXFixes; bool m_includeAlpha; QPolygon m_lastFreeRegion; QRect m_lastRegion; diff --git a/xcb/pixmaphelper.cpp b/xcb/pixmaphelper.cpp new file mode 100644 index 0000000..4060e98 --- /dev/null +++ b/xcb/pixmaphelper.cpp @@ -0,0 +1,178 @@ +/* + Copyright (C) 2013 Martin Gr=C3=A4=C3=9Flin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or ( at your option ) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "xcb/pixmaphelper.h" + +#include + +#include + +#include + +#include "xcb/xcbutils.h" + +namespace PixmapHelperXCB +{ + +void compositePointer(int offsetx, int offsety, QPixmap &snapshot) +{ + Xcb::ScopedCPointer cursor( + xcb_xfixes_get_cursor_image_reply(Xcb::connection(), + xcb_xfixes_get_cursor_image_= unchecked(Xcb::connection()), + NULL)); + + if (cursor.isNull()) { + return; + } + + QImage qcursorimg((uchar *) xcb_xfixes_get_cursor_image_cursor_image(c= ursor.data()), + cursor->width, cursor->height, + QImage::Format_ARGB32_Premultiplied); + + QPainter painter(&snapshot); + painter.drawImage(QPointF(cursor->x - cursor->xhot - offsetx, cursor->= y - cursor ->yhot - offsety), qcursorimg); +} + +QPixmap grabWindow(WId id, int x, int y, int width, int height) +{ + xcb_connection_t *c =3D Xcb::connection(); + Xcb::WindowGeometry geo(id); + if (geo.isNull()) { + return QPixmap(); + } + if (width < 0 || width > geo->width) { + width =3D geo->width; + } + if (width + x > geo->width) { + width =3D width + x - geo->width; + } + if (height < 0 || height > geo->height) { + height =3D geo->height; + } + if (height + y > geo->height) { + height =3D height + y - geo->height; + } + Xcb::ScopedCPointer xImage(xcb_get_image_reply( + c, xcb_get_image_unchecked(c, XCB_IMAGE_FORMAT_Z_PIXMAP, id, x, y,= width, height, ~0), NULL)); + if (xImage.isNull()) { + return QPixmap(); + } + QImage::Format format =3D QImage::Format_ARGB32_Premultiplied; + switch (xImage->depth) { + case 1: + format =3D QImage::Format_MonoLSB; + break; + case 30: { + // Qt doesn't have a matching image format. We need to convert man= ually + uint32_t *pixels =3D reinterpret_cast(xcb_get_image_da= ta(xImage.data())); + for (uint32_t i =3D 0; i < xImage.data()->length; ++i) { + int r =3D (pixels[i] >> 22) & 0xff; + int g =3D (pixels[i] >> 12) & 0xff; + int b =3D (pixels[i] >> 2) & 0xff; + + pixels[i] =3D qRgba(r, g, b, 0xff); + } + QImage image(reinterpret_cast(pixels), geo->width, geo->h= eight, + xcb_get_image_data_length(xImage.data()) / geo->heigh= t, QImage::Format_ARGB32_Premultiplied); + if (image.isNull()) { + return QPixmap(); + } + return QPixmap::fromImage(image); + } + case 32: + format =3D QImage::Format_ARGB32_Premultiplied; + break; + default: + if (xImage->depth =3D=3D defaultDepth()) { + format =3D findFormat(); + if (format =3D=3D QImage::Format_Invalid) { + return QPixmap(); + } + } else { + // we don't know + return QPixmap(); + } + } + QImage image(xcb_get_image_data(xImage.data()), width, height, + xcb_get_image_data_length(xImage.data()) / height, format= ); + if (image.isNull()) { + return QPixmap(); + } + if (image.format() =3D=3D QImage::Format_MonoLSB) { + // work around an abort in QImage::color + image.setColorCount(2); + image.setColor(0, QColor(Qt::white).rgb()); + image.setColor(1, QColor(Qt::black).rgb()); + } + return QPixmap::fromImage(image); +} + +uint8_t defaultDepth() +{ + xcb_connection_t *c =3D Xcb::connection(); + int screen =3D QX11Info::appScreen(); + + xcb_screen_iterator_t it =3D xcb_setup_roots_iterator(xcb_get_setup(c)= ); + for (; it.rem; --screen, xcb_screen_next(&it)) { + if (screen =3D=3D 0) { + return it.data->root_depth; + } + } + return 0; +} + +QImage::Format findFormat() +{ + xcb_connection_t *c =3D Xcb::connection(); + int screen =3D QX11Info::appScreen(); + + xcb_screen_iterator_t screenIt =3D xcb_setup_roots_iterator(xcb_get_se= tup(c)); + for (; screenIt.rem; --screen, xcb_screen_next(&screenIt)) { + if (screen !=3D 0) { + continue; + } + xcb_depth_iterator_t depthIt =3D xcb_screen_allowed_depths_iterato= r(screenIt.data); + for (; depthIt.rem; xcb_depth_next(&depthIt)) { + xcb_visualtype_iterator_t visualIt =3D xcb_depth_visuals_itera= tor(depthIt.data); + for (; visualIt.rem; xcb_visualtype_next(&visualIt)) { + if (screenIt.data->root_visual !=3D visualIt.data->visual_= id) { + continue; + } + xcb_visualtype_t *visual =3D visualIt.data; + if ((depthIt.data->depth =3D=3D 24 || depthIt.data->depth = =3D=3D 32) && + visual->red_mask =3D=3D 0x00ff0000 && + visual->green_mask =3D=3D 0x0000ff00 && + visual->blue_mask =3D=3D 0x000000ff) { + return QImage::Format_ARGB32_Premultiplied; + } + if (depthIt.data->depth =3D=3D 16 && + visual->red_mask =3D=3D 0xf800 && + visual->green_mask =3D=3D 0x07e0 && + visual->blue_mask =3D=3D 0x001f) { + return QImage::Format_RGB16; + } + break; + } + } + } + return QImage::Format_Invalid; +} + +} // namespace PixmapHelperXCB + diff --git a/xcb/pixmaphelper.h b/xcb/pixmaphelper.h new file mode 100644 index 0000000..9dfddff --- /dev/null +++ b/xcb/pixmaphelper.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2013 Martin Gr=C3=A4=C3=9Flin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or ( at your option ) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef PIXMAPHELPER_XCB_H +#define PIXMAPHELPER_XCB_H + +#include +#include + +namespace PixmapHelperXCB +{ + void compositePointer(int offsetX, int offsetY, QPixmap &snapshot); + QPixmap grabWindow(WId window, int x =3D 0, int y =3D 0, int width =3D= -1, int height =3D -1); + + uint8_t defaultDepth(); + QImage::Format findFormat(); +}; + +#endif diff --git a/xcb/xcbutils.h b/xcb/xcbutils.h new file mode 100644 index 0000000..b57b692 --- /dev/null +++ b/xcb/xcbutils.h @@ -0,0 +1,209 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2012, 2013 Martin Gr=C3=A4=C3=9Flin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#ifndef XCBUTILS_H +#define XCBUTILS_H + +// Qt +#include +#include +#include + +// xcb +#include +#include +#include + +namespace Xcb +{ + +inline xcb_connection_t *connection() +{ + return XGetXCBConnection(QX11Info::display()); +} + +class ServerGrabber +{ +public: + ServerGrabber() { + xcb_grab_server(connection()); + } + ~ServerGrabber() { + xcb_ungrab_server(connection()); + } +}; + +template +class ScopedCPointer : public QScopedPointer +{ +public: + ScopedCPointer(T *p =3D 0) : QScopedPointer(p) {} +}; + +template +class Wrapper +{ +public: + Wrapper() + : m_retrieved(false) + , m_window(XCB_WINDOW_NONE) + , m_reply(NULL) + { + m_cookie.sequence =3D 0; + } + explicit Wrapper(xcb_window_t window) + : m_retrieved(false) + , m_cookie(requestFunc(connection(), window)) + , m_window(window) + , m_reply(NULL) + { + } + explicit Wrapper(const Wrapper &other) + : m_retrieved(other.m_retrieved) + , m_cookie(other.m_cookie) + , m_window(other.m_window) + , m_reply(NULL) + { + takeFromOther(const_cast(other)); + } + virtual ~Wrapper() { + cleanup(); + } + inline Wrapper &operator=3D(const Wrapper &other) { + if (this !=3D &other) { + // if we had managed a reply, free it + cleanup(); + // copy members + m_retrieved =3D other.m_retrieved; + m_cookie =3D other.m_cookie; + m_window =3D other.m_window; + m_reply =3D other.m_reply; + // take over the responsibility for the reply pointer + takeFromOther(const_cast(other)); + } + return *this; + } + + inline const Reply *operator->() { + getReply(); + return m_reply; + } + inline bool isNull() { + getReply(); + return m_reply =3D=3D NULL; + } + inline operator bool() { + return !isNull(); + } + inline const Reply *data() { + getReply(); + return m_reply; + } + inline xcb_window_t window() const { + return m_window; + } + inline bool isRetrieved() const { + return m_retrieved; + } + /** + * Returns the value of the reply pointer referenced by this object. T= he reply pointer of + * this object will be reset to null. Calling any method which require= s the reply to be valid + * will crash. + * + * Callers of this function take ownership of the pointer. + **/ + inline Reply *take() { + getReply(); + Reply *ret =3D m_reply; + m_reply =3D NULL; + m_window =3D XCB_WINDOW_NONE; + return ret; + } + +protected: + void getReply() { + if (m_retrieved || !m_cookie.sequence) { + return; + } + m_reply =3D replyFunc(connection(), m_cookie, NULL); + m_retrieved =3D true; + } + +private: + inline void cleanup() { + if (!m_retrieved && m_cookie.sequence) { + xcb_discard_reply(connection(), m_cookie.sequence); + } else if (m_reply) { + free(m_reply); + } + } + inline void takeFromOther(Wrapper &other) { + if (m_retrieved) { + m_reply =3D other.take(); + } else { + //ensure that other object doesn't try to get the reply or dis= cards it in the dtor + other.m_retrieved =3D true; + other.m_window =3D XCB_WINDOW_NONE; + } + } + bool m_retrieved; + Cookie m_cookie; + xcb_window_t m_window; + Reply *m_reply; +}; + +typedef Wrapper WindowAttributes; + + +class WindowGeometry : public Wrapper +{ +public: + WindowGeometry() : Wrapper() {} + explicit WindowGeometry(xcb_window_t window) : Wrapper(window) {} + + inline QRect rect() { + const xcb_get_geometry_reply_t *geometry =3D data(); + if (!geometry) { + return QRect(); + } + return QRect(geometry->x, geometry->y, geometry->width, geometry->= height); + } +}; + +class Tree : public Wrapper +{ +public: + explicit Tree(xcb_window_t window) : Wrapper(w= indow) {} + + inline xcb_window_t *children() { + return xcb_query_tree_children(data()); + } + inline xcb_window_t parent() { + if (isNull()) + return XCB_WINDOW_NONE; + return (*this)->parent; + } +}; + +} // namespace + +#endif