summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb/qxcbscreen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbscreen.cpp')
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp125
1 files changed, 125 insertions, 0 deletions
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 6c3d1813b0..42259feda8 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -42,6 +42,7 @@
#include "qxcbscreen.h"
#include "qxcbwindow.h"
#include "qxcbcursor.h"
+#include "qxcbimage.h"
#include <stdio.h>
@@ -150,6 +151,7 @@ QXcbScreen::~QXcbScreen()
delete m_cursor;
}
+
QWindow *QXcbScreen::topLevelAt(const QPoint &p) const
{
xcb_window_t root = m_screen->root;
@@ -227,3 +229,126 @@ int QXcbScreen::screenNumber() const
{
return m_number;
}
+
+QPixmap QXcbScreen::grabWindow(WId window, int x, int y, int width, int height) const
+{
+ if (width == 0 || height == 0)
+ return QPixmap();
+
+ xcb_get_geometry_cookie_t geometry_cookie = xcb_get_geometry(xcb_connection(), window);
+
+ xcb_generic_error_t *error;
+ xcb_get_geometry_reply_t *reply =
+ xcb_get_geometry_reply(xcb_connection(), geometry_cookie, &error);
+
+ if (!reply) {
+ if (error) {
+ connection()->handleXcbError(error);
+ free(error);
+ }
+ return QPixmap();
+ }
+
+ if (width < 0)
+ width = reply->width - x;
+ if (height < 0)
+ height = reply->height - y;
+
+ // TODO: handle multiple screens
+ QXcbScreen *screen = const_cast<QXcbScreen *>(this);
+ xcb_window_t root = screen->root();
+ geometry_cookie = xcb_get_geometry(xcb_connection(), root);
+ xcb_get_geometry_reply_t *root_reply =
+ xcb_get_geometry_reply(xcb_connection(), geometry_cookie, &error);
+
+ if (!root_reply) {
+ if (error) {
+ connection()->handleXcbError(error);
+ free(error);
+ }
+ free(reply);
+ return QPixmap();
+ }
+
+ if (reply->depth == root_reply->depth) {
+ // if the depth of the specified window and the root window are the
+ // same, grab pixels from the root window (so that we get the any
+ // overlapping windows and window manager frames)
+
+ // map x and y to the root window
+ xcb_translate_coordinates_cookie_t translate_cookie =
+ xcb_translate_coordinates(xcb_connection(), window, root, x, y);
+
+ xcb_translate_coordinates_reply_t *translate_reply =
+ xcb_translate_coordinates_reply(xcb_connection(), translate_cookie, &error);
+
+ if (!translate_reply) {
+ if (error) {
+ connection()->handleXcbError(error);
+ free(error);
+ }
+ free(reply);
+ free(root_reply);
+ return QPixmap();
+ }
+
+ x = translate_reply->dst_x;
+ y = translate_reply->dst_y;
+
+ window = root;
+
+ free(translate_reply);
+ free(reply);
+ reply = root_reply;
+ } else {
+ free(root_reply);
+ root_reply = 0;
+ }
+
+ xcb_get_window_attributes_reply_t *attributes_reply =
+ xcb_get_window_attributes_reply(xcb_connection(), xcb_get_window_attributes(xcb_connection(), window), &error);
+
+ if (!attributes_reply) {
+ if (error) {
+ connection()->handleXcbError(error);
+ free(error);
+ }
+ free(reply);
+ return QPixmap();
+ }
+
+ const xcb_visualtype_t *visual = screen->visualForId(attributes_reply->visual);
+ free(attributes_reply);
+
+ xcb_pixmap_t pixmap = xcb_generate_id(xcb_connection());
+ error = xcb_request_check(xcb_connection(), xcb_create_pixmap_checked(xcb_connection(), reply->depth, pixmap, window, width, height));
+ if (error) {
+ connection()->handleXcbError(error);
+ free(error);
+ }
+
+ uint32_t gc_value_mask = XCB_GC_SUBWINDOW_MODE;
+ uint32_t gc_value_list[] = { XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS };
+
+ xcb_gcontext_t gc = xcb_generate_id(xcb_connection());
+ xcb_create_gc(xcb_connection(), gc, pixmap, gc_value_mask, gc_value_list);
+
+ error = xcb_request_check(xcb_connection(), xcb_copy_area_checked(xcb_connection(), window, pixmap, gc, x, y, 0, 0, width, height));
+ if (error) {
+ connection()->handleXcbError(error);
+ free(error);
+ }
+
+ QPixmap result = qt_xcb_pixmapFromXPixmap(connection(), pixmap, width, height, reply->depth, visual);
+
+ free(reply);
+ xcb_free_gc(xcb_connection(), gc);
+ xcb_free_pixmap(xcb_connection(), pixmap);
+
+ return result;
+}
+
+QString QXcbScreen::name() const
+{
+ return connection()->displayName() + QLatin1String(".") + QString::number(screenNumber());
+}