diff options
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbscreen.cpp')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbscreen.cpp | 125 |
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()); +} |