[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [ksnapshot/frameworks] /: split out the platform dependent parts of window grabber
From:       Aaron Seigo <aseigo () kde ! org>
Date:       2014-09-15 8:16:03
Message-ID: E1XTRS7-0005kS-VD () scm ! kde ! org
[Download RAW message or body]

Git commit adbe9ebb97af49af0dc00e4e91ffc36b7e2b51e1 by Aaron Seigo.
Committed on 15/09/2014 at 07:54.
Pushed by aseigo into branch 'frameworks'.

split out the platform dependent parts of window grabber

from a patch by Martin Gräßlin

M  +18   -9    CMakeLists.txt
M  +10   -425  windowgrabber.cpp
M  +1    -0    windowgrabber.h
A  +189  -0    windows/windowgrabber.cpp     [License: GPL (v2+)]
A  +287  -0    xcb/windowgrabber.cpp     [License: GPL (v2+)]

http://commits.kde.org/ksnapshot/adbe9ebb97af49af0dc00e4e91ffc36b7e2b51e1

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 69d6fc9..8ddef9f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -57,6 +57,11 @@ endif (KIPI_FOUND)
 
 configure_file(config-ksnapshot.h.cmake \
${CMAKE_CURRENT_BINARY_DIR}/config-ksnapshot.h)  
+if (XCB_XCB_FOUND AND X11_XCB_FOUND)
+   set(ksnapshot_xcb_SRCS
+       xcb/pixmaphelper.cpp)
+endif (XCB_XCB_FOUND AND X11_XCB_FOUND)
+
 ########### next target ###############
 
 add_subdirectory( doc )
@@ -70,12 +75,6 @@ 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
@@ -118,12 +117,15 @@ target_link_libraries(ksnapshot
 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 ()
@@ -139,10 +141,13 @@ install(TARGETS ksnapshot ${INSTALL_TARGETS_DEFAULT_ARGS})
 
 set(kbackgroundsnapshot_SRCS
    kbackgroundsnapshot.cpp
-   ${ksnapshot_file_SRCS})
-
+   )
 
-add_executable(kbackgroundsnapshot ${kbackgroundsnapshot_SRCS})
+add_executable(kbackgroundsnapshot
+               ${kbackgroundsnapshot_SRCS}
+               ${ksnapshot_xcb_SRCS}
+               ${ksnapshot_file_SRCS}
+               )
 
 target_link_libraries(kbackgroundsnapshot
                       Qt5::X11Extras
@@ -168,6 +173,10 @@ if (XCB_SHAPE_FOUND)
     target_link_libraries(kbackgroundsnapshot ${XCB_SHAPE_LIBRARY})
 endif ()
 
+if (XCB_XFIXES_FOUND)
+    target_link_libraries(kbackgroundsnapshot ${XCB_XFIXES_LIBRARY})
+endif ()
+
 install(TARGETS kbackgroundsnapshot ${INSTALL_TARGETS_DEFAULT_ARGS})
 
 ########### install files ###############
diff --git a/windowgrabber.cpp b/windowgrabber.cpp
index c7c11ba..c58b38d 100644
--- a/windowgrabber.cpp
+++ b/windowgrabber.cpp
@@ -19,12 +19,11 @@
 */
 
 #include "windowgrabber.h"
+#include "config-ksnapshot.h"
 
 #include <iostream>
 #include <algorithm>
 
-#include <kwindowinfo.h>
-
 #include <QApplication>
 #include <QBitmap>
 #include <QDebug>
@@ -36,332 +35,12 @@
 #include <QScreen>
 #include <QWheelEvent>
 
-#include "config-ksnapshot.h"
-
-#if HAVE_X11
-#include <X11/Xlib.h>
-#if HAVE_X11_EXTENSIONS_SHAPE_H
-#include <X11/extensions/shape.h>
-#endif // HAVE_X11_EXTENSIONS_SHAPE_H
-#include <QX11Info>
-#endif // HAVE_X11
-
 #ifdef Q_OS_WIN
-#include <windows.h>
-
-static UINT cxWindowBorder, cyWindowBorder;
-#endif // Q_OS_WIN
-
-static
-const int minSize = 8;
-
-static
-bool operator< (const QRect &r1, const QRect &r2)
-{
-    return r1.width() * r1.height() < r2.width() * r2.height();
-}
-
-// Recursively iterates over the window w and its children, thereby building
-// a tree of window descriptors. Windows in non-viewable state or with height
-// or width smaller than minSize will be ignored.
-#if HAVE_X11
-static
-void getWindowsRecursive(std::vector<QRect> *windows, Window w,
-                         int rx = 0, int ry = 0, int depth = 0)
-{
-    XWindowAttributes atts;
-    XGetWindowAttributes(QX11Info::display(), w, &atts);
-
-    if (atts.map_state == IsViewable &&
-            atts.width >= minSize && atts.height >= minSize) {
-        int x = 0, y = 0;
-        if (depth) {
-            x = atts.x + rx;
-            y = atts.y + ry;
-        }
-
-        QRect r(x, y, atts.width, atts.height);
-        if (std::find(windows->begin(), windows->end(), r) == windows->end()) {
-            windows->push_back(r);
-        }
-
-        Window root, parent;
-        Window *children;
-        unsigned int nchildren;
-
-        if (XQueryTree(QX11Info::display(), w, &root, &parent, &children, \
                &nchildren) != 0) {
-            for (unsigned int i = 0; i < nchildren; ++i) {
-                getWindowsRecursive(windows, children[ i ], x, y, depth + 1);
-            }
-
-            if (children != NULL) {
-                XFree(children);
-            }
-        }
-    }
-
-    if (depth == 0) {
-        std::sort(windows->begin(), windows->end());
-    }
-}
-#elif defined(Q_OS_WIN)
-static
-bool maybeAddWindow(HWND hwnd, std::vector<QRect> *windows)
-{
-    WINDOWINFO wi;
-    GetWindowInfo(hwnd, &wi);
-    RECT rect = wi.rcClient;
-
-#if 0
-    RECT rect;
-    GetWindowRect(hwnd, &rect);
+#include "windows/windowgrabber.cpp"
+#elif XCB_XCB_FOUND
+#include "xcb/windowgrabber.cpp"
 #endif
 
-    int width = rect.right - rect.left;
-    int height = rect.bottom - rect.top;
-
-    // For some reason, rect.left and rect.top are shifted by cxWindowBorders and \
                cyWindowBorders pixels respectively
-    // in *every* case (for every window), but cxWindowBorders and cyWindowBorders \
                are non-zero only in the
-    // biggest-window case, therefore we need to save the biggest cxWindowBorders \
                and cyWindowBorders to adjust the rect later
-    cxWindowBorder = qMax(cxWindowBorder, wi.cxWindowBorders);
-    cyWindowBorder = qMax(cyWindowBorder, wi.cyWindowBorders);
-
-    if (((wi.dwStyle & WS_VISIBLE) != 0) && (width >= minSize) && (height >= \
                minSize)) {
-        //QRect r( rect.left + 4, rect.top + 4, width, height); // 4 = \
                max(wi.cxWindowBorders) = max(wi.cyWindowBorders)
-        QRect r(rect.left + cxWindowBorder, rect.top + cyWindowBorder, width, \
                height);
-        if (std::find(windows->begin(), windows->end(), r) == windows->end()) {
-            windows->push_back(r);
-            return true;
-        }
-    }
-    return false;
-}
-
-static
-BOOL CALLBACK getWindowsRecursiveHelper(HWND hwnd, LPARAM lParam)
-{
-    maybeAddWindow(hwnd, reinterpret_cast< std::vector<QRect>* >(lParam));
-    return TRUE;
-}
-
-static
-void getWindowsRecursive(std::vector<QRect> *windows, HWND hwnd,
-                         int rx = 0, int ry = 0, int depth = 0)
-{
-
-    maybeAddWindow(hwnd, windows);
-
-    EnumChildWindows(hwnd, getWindowsRecursiveHelper, (LPARAM) windows);
-
-    std::sort(windows->begin(), windows->end());
-}
-#endif // HAVE_X11
-
-#if HAVE_X11
-static
-Window findRealWindow(Window w, int depth = 0)
-{
-    if (depth > 5) {
-        return None;
-    }
-
-    static Atom wm_state = XInternAtom(QX11Info::display(), "WM_STATE", False);
-    Atom type;
-    int format;
-    unsigned long nitems, after;
-    unsigned char *prop;
-
-    if (XGetWindowProperty(QX11Info::display(), w, wm_state, 0, 0, False, \
                AnyPropertyType,
-                           &type, &format, &nitems, &after, &prop) == Success) {
-        if (prop != NULL) {
-            XFree(prop);
-        }
-
-        if (type != None) {
-            return w;
-        }
-    }
-
-    Window root, parent;
-    Window *children;
-    unsigned int nchildren;
-    Window ret = None;
-
-    if (XQueryTree(QX11Info::display(), w, &root, &parent, &children, &nchildren) != \
                0) {
-        for (unsigned int i = 0;
-                i < nchildren && ret == None;
-                ++i) {
-            ret = findRealWindow(children[ i ], depth + 1);
-        }
-
-        if (children != NULL) {
-            XFree(children);
-        }
-    }
-
-    return ret;
-}
-#elif defined(Q_OS_WIN)
-static
-HWND findRealWindow(HWND w, int depth = 0)
-{
-    // TODO Implement
-    return w; // This is WRONG but makes code compile for now
-}
-#endif // HAVE_X11
-
-#if HAVE_X11
-static
-Window windowUnderCursor(bool includeDecorations = true)
-{
-    Window root;
-    Window child;
-    uint mask;
-    int rootX, rootY, winX, winY;
-
-    XGrabServer(QX11Info::display());
-    XQueryPointer(QX11Info::display(), QX11Info::appRootWindow(), &root, &child,
-                  &rootX, &rootY, &winX, &winY, &mask);
-
-    if (child == None) {
-        child = QX11Info::appRootWindow();
-    }
-
-    if (!includeDecorations) {
-        Window real_child = findRealWindow(child);
-
-        if (real_child != None) {   // test just in case
-            child = real_child;
-        }
-    }
-
-    return child;
-}
-#elif defined(Q_OS_WIN)
-static
-HWND windowUnderCursor(bool includeDecorations = true)
-{
-    POINT pointCursor;
-    QPoint qpointCursor = QCursor::pos();
-    pointCursor.x = qpointCursor.x();
-    pointCursor.y = qpointCursor.y();
-    HWND windowUnderCursor = WindowFromPoint(pointCursor);
-
-    if (includeDecorations) {
-        LONG_PTR style = GetWindowLongPtr(windowUnderCursor, GWL_STYLE);
-        if ((style & WS_CHILD) != 0) {
-            windowUnderCursor = GetAncestor(windowUnderCursor, GA_ROOT);
-        }
-    }
-    return windowUnderCursor;
-}
-#endif
-
-#if HAVE_X11
-static
-QPixmap grabWindow(Window child, int x, int y, uint w, uint h, uint border,
-                   QString *title = 0, QString *windowClass = 0)
-{
-    QPixmap pm;
-    const QList<QScreen *> screens = qApp->screens();
-    const QDesktopWidget *desktop = QApplication::desktop();
-    const int screenId = desktop->screenNumber(QPoint(x, y));
-    if (screenId < screens.count()) {
-        pm = screens[screenId]->grabWindow(QX11Info::appRootWindow(), x, y, w, h);
-    }
-
-    KWindowInfo winInfo(findRealWindow(child), NET::WMVisibleName, \
                NET::WM2WindowClass);
-
-    if (title) {
-        (*title) = winInfo.visibleName();
-    }
-
-    if (windowClass) {
-        (*windowClass) = winInfo.windowClassName();
-    }
-
-#if HAVE_X11_EXTENSIONS_SHAPE_H
-    int tmp1, tmp2;
-    //Check whether the extension is available
-    if (XShapeQueryExtension(QX11Info::display(), &tmp1, &tmp2)) {
-        QBitmap mask(w, h);
-        //As the first step, get the mask from XShape.
-        int count, order;
-        XRectangle *rects = XShapeGetRectangles(QX11Info::display(), child,
-                                                ShapeBounding, &count, &order);
-        //The ShapeBounding region is the outermost shape of the window;
-        //ShapeBounding - ShapeClipping is defined to be the border.
-        //Since the border area is part of the window, we use bounding
-        // to limit our work region
-        if (rects) {
-            //Create a QRegion from the rectangles describing the bounding mask.
-            QRegion contents;
-            for (int pos = 0; pos < count; pos++)
-                contents += QRegion(rects[pos].x, rects[pos].y,
-                                    rects[pos].width, rects[pos].height);
-            XFree(rects);
-
-            //Create the bounding box.
-            QRegion bbox(0, 0, w, h);
-
-            if (border > 0) {
-                contents.translate(border, border);
-                contents += QRegion(0, 0, border, h);
-                contents += QRegion(0, 0, w, border);
-                contents += QRegion(0, h - border, w, border);
-                contents += QRegion(w - border, 0, border, h);
-            }
-
-            //Get the masked away area.
-            QRegion maskedAway = bbox - contents;
-            QVector<QRect> maskedAwayRects = maskedAway.rects();
-
-            //Construct a bitmap mask from the rectangles
-            QPainter p(&mask);
-            p.fillRect(0, 0, w, h, Qt::color1);
-            for (int pos = 0; pos < maskedAwayRects.count(); pos++) {
-                p.fillRect(maskedAwayRects[pos], Qt::color0);
-            }
-            p.end();
-
-            pm.setMask(mask);
-        }
-    }
-#endif // HAVE_X11_EXTENSIONS_SHAPE_H
-
-    return pm;
-}
-#elif defined(Q_OS_WIN)
-static
-QPixmap grabWindow(HWND hWnd, QString *title = 0, QString *windowClass = 0)
-{
-    RECT windowRect;
-    GetWindowRect(hWnd, &windowRect);
-    int w = windowRect.right - windowRect.left;
-    int h = windowRect.bottom - windowRect.top;
-    HDC targetDC = GetWindowDC(hWnd);
-    HDC hDC = CreateCompatibleDC(targetDC);
-    HBITMAP tempPict = CreateCompatibleBitmap(targetDC, w, h);
-    HGDIOBJ oldPict = SelectObject(hDC, tempPict);
-    BitBlt(hDC, 0, 0, w, h, targetDC, 0, 0, SRCCOPY);
-    tempPict = (HBITMAP) SelectObject(hDC, oldPict);
-    QPixmap pm = QPixmap::fromWinHBITMAP(tempPict);
-
-    DeleteDC(hDC);
-    ReleaseDC(hWnd, targetDC);
-
-    KWindowInfo winInfo(findRealWindow(hWnd), NET::WMVisibleName, \
                NET::WM2WindowClass);
-    if (title) {
-        (*title) = winInfo.visibleName();
-    }
-
-    if (windowClass) {
-        (*windowClass) = winInfo.windowClassName();
-    }
-    return pm;
-}
-#endif // HAVE_X11
-
 QString WindowGrabber::title;
 QString WindowGrabber::windowClass;
 QPoint WindowGrabber::windowPosition;
@@ -370,47 +49,16 @@ WindowGrabber::WindowGrabber()
     : QDialog(0, Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | \
Qt::X11BypassWindowManagerHint),  current(-1), yPos(-1)
 {
-    setWindowModality(Qt::WindowModal);
-    int y, x;
-    uint w, h;
-
-#if HAVE_X11
-    uint border, depth;
-    Window root;
-    XGrabServer(QX11Info::display());
-    Window child = windowUnderCursor();
-    XGetGeometry(QX11Info::display(), child, &root, &x, &y, &w, &h, &border, \
                &depth);
-    XUngrabServer(QX11Info::display());
-
-    QPixmap pm(grabWindow(child, x, y, w, h, border, &title, &windowClass));
-#elif defined(Q_OS_WIN)
-    HWND child = windowUnderCursor();
-
-    WINDOWINFO wi;
-    GetWindowInfo(child, &wi);
-
-    RECT r;
-    GetWindowRect(child, &r);
-    x = r.left;
-    y = r.top;
-    w = r.right - r.left;
-    h = r.bottom - r.top;
-    cxWindowBorder = wi.cxWindowBorders;
-    cyWindowBorder = wi.cyWindowBorders;
-
-    HDC childDC = GetDC(child);
-
-    QPixmap pm(grabWindow(child, &title, &windowClass));
-#endif // HAVE_X11
-
-    getWindowsRecursive(&windows, child);
+    QPixmap pm;
+    QRect rect;
+    platformSetup(pm, rect);
 
     QPalette p = palette();
     p.setBrush(backgroundRole(), QBrush(pm));
     setPalette(p);
     setFixedSize(pm.size());
     setMouseTracking(true);
-    setGeometry(x, y, w, h);
+    setGeometry(rect);
     current = windowIndex(mapFromGlobal(QCursor::pos()));
 }
 
@@ -418,68 +66,6 @@ WindowGrabber::~WindowGrabber()
 {
 }
 
-QPixmap WindowGrabber::grabCurrent(bool includeDecorations)
-{
-    int x, y;
-#if HAVE_X11
-    Window root;
-    uint w, h, border, depth;
-
-    XGrabServer(QX11Info::display());
-    Window child = windowUnderCursor(includeDecorations);
-    XGetGeometry(QX11Info::display(), child, &root, &x, &y, &w, &h, &border, \
                &depth);
-
-    Window parent;
-    Window *children;
-    unsigned int nchildren;
-
-    if (XQueryTree(QX11Info::display(), child, &root, &parent,
-                   &children, &nchildren) != 0) {
-        if (children != NULL) {
-            XFree(children);
-        }
-
-        int newx, newy;
-        Window dummy;
-
-        if (XTranslateCoordinates(QX11Info::display(), parent, \
                QX11Info::appRootWindow(),
-                                  x, y, &newx, &newy, &dummy)) {
-            x = newx;
-            y = newy;
-        }
-    }
-
-    windowPosition = QPoint(x, y);
-    QPixmap pm(grabWindow(child, x, y, w, h, border, &title, &windowClass));
-    XUngrabServer(QX11Info::display());
-    return pm;
-#elif defined(Q_OS_WIN)
-    HWND hWindow;
-    hWindow = windowUnderCursor(includeDecorations);
-    Q_ASSERT(hWindow);
-
-    HWND hParent;
-
-// Now find the top-most window
-    do {
-        hParent = hWindow;
-    } while ((hWindow = GetParent(hWindow)) != NULL);
-    Q_ASSERT(hParent);
-
-    RECT r;
-    GetWindowRect(hParent, &r);
-
-    x = r.left;
-    y = r.top;
-
-    windowPosition = QPoint(x, y);
-    QPixmap pm(grabWindow(hParent, &title, &windowClass));
-    return pm;
-#endif // HAVE_X11
-    return QPixmap();
-}
-
-
 void WindowGrabber::mousePressEvent(QMouseEvent *e)
 {
     if (e->button() == Qt::RightButton) {
@@ -503,11 +89,10 @@ void WindowGrabber::mouseReleaseEvent(QMouseEvent *e)
     }
 }
 
-static
-const int minDistance = 10;
-
 void WindowGrabber::mouseMoveEvent(QMouseEvent *e)
 {
+    static const int minDistance = 10;
+
     if (yPos == -1) {
         int w = windowIndex(e->pos());
         if (w != -1 && w != current) {
diff --git a/windowgrabber.h b/windowgrabber.h
index 6b55357..8d541e0 100644
--- a/windowgrabber.h
+++ b/windowgrabber.h
@@ -58,6 +58,7 @@ protected:
     void paintEvent(QPaintEvent *);
 
 private:
+    void platformSetup(QPixmap &pm, QRect &geom);
     void increaseScope(const QPoint &);
     void decreaseScope(const QPoint &);
     int windowIndex(const QPoint &) const;
diff --git a/windows/windowgrabber.cpp b/windows/windowgrabber.cpp
new file mode 100644
index 0000000..8cf1225
--- /dev/null
+++ b/windows/windowgrabber.cpp
@@ -0,0 +1,189 @@
+/*
+  Copyright (C) 2004 Bernd Brandstetter <bbrand@freenet.de>
+  Copyright (C) 2010, 2011 Pau Garcia i Quiles <pgquiles@elpauer.org>
+
+  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 "windowgrabber.h"
+
+#include <windows.h>
+
+static UINT cxWindowBorder, cyWindowBorder;
+
+static
+const int minSize = 8;
+
+static
+bool operator< (const QRect &r1, const QRect &r2)
+{
+    return r1.width() * r1.height() < r2.width() * r2.height();
+}
+
+static
+bool maybeAddWindow(HWND hwnd, std::vector<QRect> *windows)
+{
+    WINDOWINFO wi;
+    GetWindowInfo(hwnd, &wi);
+    RECT rect = wi.rcClient;
+
+#if 0
+    RECT rect;
+    GetWindowRect(hwnd, &rect);
+#endif
+
+    int width = rect.right - rect.left;
+    int height = rect.bottom - rect.top;
+
+    // For some reason, rect.left and rect.top are shifted by cxWindowBorders and \
cyWindowBorders pixels respectively +    // in *every* case (for every window), but \
cxWindowBorders and cyWindowBorders are non-zero only in the +    // biggest-window \
case, therefore we need to save the biggest cxWindowBorders and cyWindowBorders to \
adjust the rect later +    cxWindowBorder = qMax(cxWindowBorder, wi.cxWindowBorders);
+    cyWindowBorder = qMax(cyWindowBorder, wi.cyWindowBorders);
+
+    if (((wi.dwStyle & WS_VISIBLE) != 0) && (width >= minSize) && (height >= \
minSize)) { +        //QRect r( rect.left + 4, rect.top + 4, width, height); // 4 = \
max(wi.cxWindowBorders) = max(wi.cyWindowBorders) +        QRect r(rect.left + \
cxWindowBorder, rect.top + cyWindowBorder, width, height); +        if \
(std::find(windows->begin(), windows->end(), r) == windows->end()) { +            \
windows->push_back(r); +            return true;
+        }
+    }
+    return false;
+}
+
+static
+BOOL CALLBACK getWindowsRecursiveHelper(HWND hwnd, LPARAM lParam)
+{
+    maybeAddWindow(hwnd, reinterpret_cast< std::vector<QRect>* >(lParam));
+    return TRUE;
+}
+
+static
+void getWindowsRecursive(std::vector<QRect> *windows, HWND hwnd,
+                         int rx = 0, int ry = 0, int depth = 0)
+{
+
+    maybeAddWindow(hwnd, windows);
+
+    EnumChildWindows(hwnd, getWindowsRecursiveHelper, (LPARAM) windows);
+
+    std::sort(windows->begin(), windows->end());
+}
+
+static
+HWND findRealWindow(HWND w, int depth = 0)
+{
+    // TODO Implement
+    return w; // This is WRONG but makes code compile for now
+}
+
+static
+HWND windowUnderCursor(bool includeDecorations = true)
+{
+    POINT pointCursor;
+    QPoint qpointCursor = QCursor::pos();
+    pointCursor.x = qpointCursor.x();
+    pointCursor.y = qpointCursor.y();
+    HWND windowUnderCursor = WindowFromPoint(pointCursor);
+
+    if (includeDecorations) {
+        LONG_PTR style = GetWindowLongPtr(windowUnderCursor, GWL_STYLE);
+        if ((style & WS_CHILD) != 0) {
+            windowUnderCursor = GetAncestor(windowUnderCursor, GA_ROOT);
+        }
+    }
+    return windowUnderCursor;
+}
+
+static
+QPixmap grabWindow(HWND hWnd, QString *title = 0, QString *windowClass = 0)
+{
+    RECT windowRect;
+    GetWindowRect(hWnd, &windowRect);
+    int w = windowRect.right - windowRect.left;
+    int h = windowRect.bottom - windowRect.top;
+    HDC targetDC = GetWindowDC(hWnd);
+    HDC hDC = CreateCompatibleDC(targetDC);
+    HBITMAP tempPict = CreateCompatibleBitmap(targetDC, w, h);
+    HGDIOBJ oldPict = SelectObject(hDC, tempPict);
+    BitBlt(hDC, 0, 0, w, h, targetDC, 0, 0, SRCCOPY);
+    tempPict = (HBITMAP) SelectObject(hDC, oldPict);
+    QPixmap pm = QPixmap::fromWinHBITMAP(tempPict);
+
+    DeleteDC(hDC);
+    ReleaseDC(hWnd, targetDC);
+
+    KWindowInfo winInfo(findRealWindow(hWnd), NET::WMVisibleName, \
NET::WM2WindowClass); +    if (title) {
+        (*title) = winInfo.visibleName();
+    }
+
+    if (windowClass) {
+        (*windowClass) = winInfo.windowClassName();
+    }
+    return pm;
+}
+
+QPixmap WindowGrabber::platformSetup()
+{
+    HWND child = windowUnderCursor();
+
+    WINDOWINFO wi;
+    GetWindowInfo(child, &wi);
+
+    RECT r;
+    GetWindowRect(child, &r);
+    x = r.left;
+    y = r.top;
+    w = r.right - r.left;
+    h = r.bottom - r.top;
+    cxWindowBorder = wi.cxWindowBorders;
+    cyWindowBorder = wi.cyWindowBorders;
+
+    HDC childDC = GetDC(child);
+
+    QPixmap pm(grabWindow(child, &title, &windowClass));
+    getWindowsRecursive(&windows, child);
+    return pm;
+}
+
+QPixmap WindowGrabber::grabCurrent(bool includeDecorations)
+{
+    int x, y;
+    HWND hWindow;
+    hWindow = windowUnderCursor(includeDecorations);
+    Q_ASSERT(hWindow);
+
+    HWND hParent;
+
+    // Now find the top-most window
+    do {
+        hParent = hWindow;
+    } while ((hWindow = GetParent(hWindow)) != NULL);
+    Q_ASSERT(hParent);
+
+    RECT r;
+    GetWindowRect(hParent, &r);
+
+    x = r.left;
+    y = r.top;
+
+    windowPosition = QPoint(x, y);
+    QPixmap pm(grabWindow(hParent, &title, &windowClass));
+    return pm;
+}
+
diff --git a/xcb/windowgrabber.cpp b/xcb/windowgrabber.cpp
new file mode 100644
index 0000000..c462115
--- /dev/null
+++ b/xcb/windowgrabber.cpp
@@ -0,0 +1,287 @@
+/*
+  Copyright (C) 2004 Bernd Brandstetter <bbrand@freenet.de>
+  Copyright (C) 2010, 2011 Pau Garcia i Quiles <pgquiles@elpauer.org>
+  Copyright (C) 2013 Martin Gräßlin <mgraesslin@kde.org>
+
+  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 "windowgrabber.h"
+#include "config-ksnapshot.h"
+
+// std
+#include <algorithm>
+
+// xcb
+#if XCB_SHAPE_FOUND
+#include <xcb/shape.h>
+#endif
+
+// Qt
+#include <QBitmap>
+#include <QPainter>
+#include <QX11Info>
+
+// KDE Frameworks
+#include <KWindowInfo>
+
+#include "xcb/pixmaphelper.h"
+#include "xcb/xcbutils.h"
+
+static
+bool operator< ( const QRect& r1, const QRect& r2 )
+{
+    return r1.width() * r1.height() < r2.width() * r2.height();
+}
+
+// Recursively iterates over the window w and its children, thereby building
+// a tree of window descriptors. Windows in non-viewable state or with height
+// or width smaller than minSize will be ignored.
+static
+void getWindowsRecursive(std::vector<QRect> *windows, xcb_window_t w,
+                         int rx = 0, int ry = 0, int depth = 0)
+{
+    static const int minSize = 8;
+
+    Xcb::WindowAttributes attrs(w);
+    Xcb::WindowGeometry geo(w);
+    if (!attrs.isNull() && !geo.isNull() &&
+        attrs->map_state == XCB_MAP_STATE_VIEWABLE &&
+        geo->width >= minSize && geo->height >= minSize) {
+        int x = 0, y = 0;
+        if (depth) {
+            x = geo->x + rx;
+            y = geo->y + ry;
+        }
+
+        QRect r(x, y, geo->width, geo->height);
+        if (std::find(windows->begin(), windows->end(), r) == windows->end()) {
+            windows->push_back(r);
+        }
+
+        Xcb::Tree tree(w);
+        if (!tree.isNull()) {
+            xcb_window_t *children = tree.children();
+            for (uint16_t i = 0; i < tree->children_len; ++i) {
+                getWindowsRecursive(windows, children[i], x, y, depth + 1);
+            }
+        }
+    }
+
+    if (depth == 0) {
+        std::sort(windows->begin(), windows->end());
+    }
+}
+
+static
+xcb_atom_t wmStateAtom()
+{
+    static xcb_atom_t s_atom = XCB_ATOM_NONE;
+    if (s_atom == XCB_ATOM_NONE) {
+        const QByteArray wmStateName("WM_STATE");
+        Xcb::ScopedCPointer<xcb_intern_atom_reply_t> wmState(xcb_intern_atom_reply(
+            Xcb::connection(), xcb_intern_atom_unchecked(Xcb::connection(), false, \
wmStateName.length(), wmStateName.constData()), NULL)); +        if \
(wmState.isNull()) { +            return XCB_ATOM_NONE;
+        }
+        s_atom = wmState->atom;
+    }
+    return s_atom;
+}
+
+static
+xcb_window_t findRealWindow(xcb_window_t w, int depth = 0)
+{
+    if( depth > 5 ) {
+        return XCB_WINDOW_NONE;
+    }
+
+    xcb_atom_t wmState = wmStateAtom();
+    Xcb::ScopedCPointer<xcb_get_property_reply_t> prop(
+        xcb_get_property_reply(
+            Xcb::connection(),
+            xcb_get_property_unchecked(Xcb::connection(), false, w, wmState, \
XCB_ATOM_ANY, 0, 0), +            NULL));
+    if (!prop.isNull()) {
+        if (prop->type != XCB_ATOM_NONE) {
+            return w;
+        }
+    }
+
+    Xcb::Tree tree(w);
+    if (tree.isNull()) {
+        return XCB_WINDOW_NONE;
+    }
+    xcb_window_t *children = tree.children();
+    for (uint16_t i = 0; i < tree->children_len; ++i) {
+        if (xcb_window_t window = findRealWindow(children[i], depth+1)) {
+            return window;
+        }
+    }
+    return XCB_WINDOW_NONE;
+}
+
+static
+xcb_window_t windowUnderCursor(bool includeDecorations = true)
+{
+    Xcb::ScopedCPointer<xcb_query_pointer_reply_t> pointerReply(
+        xcb_query_pointer_reply(Xcb::connection(), \
xcb_query_pointer_unchecked(Xcb::connection(), QX11Info::appRootWindow()), NULL)); +
+    if (pointerReply.isNull() || pointerReply->child == XCB_WINDOW_NONE) {
+        return QX11Info::appRootWindow();
+    }
+
+    if (includeDecorations) {
+        return pointerReply->child;
+    }
+
+    xcb_window_t window = findRealWindow(pointerReply->child);
+    return (window != XCB_WINDOW_NONE) ? window : pointerReply->child;
+}
+
+static
+bool hasShape()
+{
+#if XCB_SHAPE_FOUND
+    xcb_connection_t *c = Xcb::connection();
+    xcb_prefetch_extension_data(c, &xcb_shape_id);
+    const xcb_query_extension_reply_t *data = xcb_get_extension_data(c, \
&xcb_shape_id); +    return data->present;
+#else
+    return false;
+#endif
+}
+
+static
+QPixmap grabWindow(xcb_window_t child, int x, int y, uint w, uint h, uint border,
+                   QString *title = 0, QString *windowClass = 0)
+{
+    QPixmap pm(PixmapHelperXCB::grabWindow(QX11Info::appRootWindow(), x, y, w, h));
+
+    KWindowInfo winInfo(findRealWindow(child), NET::WMVisibleName, \
NET::WM2WindowClass); +
+    if (title) {
+        (*title) = winInfo.visibleName();
+    }
+
+    if (windowClass) {
+        (*windowClass) = winInfo.windowClassName();
+    }
+
+#if XCB_SHAPE_FOUND
+    if (!hasShape()) {
+        return pm;
+    }
+    Xcb::ScopedCPointer<xcb_shape_get_rectangles_reply_t> reply(
+        xcb_shape_get_rectangles_reply(Xcb::connection(),
+                                       \
xcb_shape_get_rectangles_unchecked(Xcb::connection(), child, XCB_SHAPE_SK_BOUNDING), \
+                                       NULL)); +    if (reply.isNull()) {
+        return pm;
+    }
+    //The ShapeBounding region is the outermost shape of the window;
+    //ShapeBounding - ShapeClipping is defined to be the border.
+    //Since the border area is part of the window, we use bounding
+    // to limit our work region
+    xcb_rectangle_t *rects = xcb_shape_get_rectangles_rectangles(reply.data());
+
+    //Create a QRegion from the rectangles describing the bounding mask.
+    QRegion contents;
+    for (uint32_t i = 0; i < reply->length; ++i) {
+        const xcb_rectangle_t &rect = rects[i];
+        contents += QRegion(rect.x, rect.y, rect.width, rect.height);
+    }
+
+    //Create the bounding box.
+    QRegion bbox(0, 0, w, h);
+
+    if (border > 0) {
+        contents.translate( border, border );
+        contents += QRegion( 0, 0, border, h );
+        contents += QRegion( 0, 0, w, border );
+        contents += QRegion( 0, h - border, w, border );
+        contents += QRegion( w - border, 0, border, h );
+    }
+
+    //Get the masked away area.
+    QRegion maskedAway = bbox - contents;
+    QVector<QRect> maskedAwayRects = maskedAway.rects();
+
+    //Construct a bitmap mask from the rectangles
+    QBitmap mask(w, h);
+    QPainter p(&mask);
+    p.fillRect(0, 0, w, h, Qt::color1);
+    for (int pos = 0; pos < maskedAwayRects.count(); pos++) {
+        p.fillRect(maskedAwayRects[pos], Qt::color0);
+    }
+    p.end();
+
+    pm.setMask(mask);
+#endif
+
+    return pm;
+}
+
+void WindowGrabber::platformSetup(QPixmap &pm, QRect &geom)
+{
+    int16_t x, y;
+    uint16_t w, h;
+
+    uint16_t border;
+    x = y = w = h = border = 0;
+    xcb_window_t child = XCB_WINDOW_NONE;
+    {
+        Xcb::ServerGrabber grabber;
+        child = windowUnderCursor();
+        Xcb::WindowGeometry geo(child);
+        if (!geo.isNull()) {
+            x = geo->x;
+            y = geo->y;
+            w = geo->width;
+            h = geo->height;
+            border = geo->border_width;
+        }
+    }
+
+    geom = QRect(x, y, w, h);
+    pm = grabWindow(child, x, y, w, h, border, &title, &windowClass);
+    getWindowsRecursive(&windows, child);
+}
+
+QPixmap WindowGrabber::grabCurrent(bool includeDecorations)
+{
+    Xcb::ServerGrabber grabber;
+    xcb_window_t child = windowUnderCursor(includeDecorations);
+    if (child == XCB_WINDOW_NONE) {
+        return QPixmap();
+    }
+    Xcb::Tree tree(child);
+    Xcb::WindowGeometry geo(child);
+
+    if (tree.isNull() || geo.isNull()) {
+        return QPixmap();
+    }
+
+    Xcb::ScopedCPointer<xcb_translate_coordinates_reply_t> \
reply(xcb_translate_coordinates_reply( +        Xcb::connection(),
+        xcb_translate_coordinates_unchecked(Xcb::connection(), tree->parent, \
QX11Info::appRootWindow(), geo->x, geo->y), +        NULL));
+    if (reply.isNull()) {
+        return QPixmap();
+    }
+
+    windowPosition = QPoint(reply->dst_x, reply->dst_y);
+    return grabWindow(child, reply->dst_x, reply->dst_y, geo->width, geo->height, \
geo->border_width, &title, &windowClass); +}


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic