[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