diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index d8facdbb84..0ad9c97521 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -678,85 +678,88 @@ void QXcbScreen::updateRefreshRate(xcb_randr_mode_t mode) } } -QPixmap QXcbScreen::grabWindow(WId window, int x, int y, int width, int height) const +static xcb_get_geometry_reply_t *getGeometryUnchecked(xcb_connection_t *connection, xcb_window_t window) +{ + const xcb_get_geometry_cookie_t geometry_cookie = xcb_get_geometry_unchecked(connection, window); + return xcb_get_geometry_reply(connection, geometry_cookie, NULL); +} + +static inline bool translate(xcb_connection_t *connection, xcb_window_t child, xcb_window_t parent, + int *x, int *y) +{ + const xcb_translate_coordinates_cookie_t translate_cookie = + xcb_translate_coordinates_unchecked(connection, child, parent, *x, *y); + xcb_translate_coordinates_reply_t *translate_reply = + xcb_translate_coordinates_reply(connection, translate_cookie, NULL); + if (!translate_reply) + return false; + *x = translate_reply->dst_x; + *y = translate_reply->dst_y; + free(translate_reply); + return true; +} + +QPixmap QXcbScreen::grabWindow(WId window, int xIn, int yIn, int width, int height) const { if (width == 0 || height == 0) return QPixmap(); - // TODO: handle multiple screens + int x = xIn; + int y = yIn; QXcbScreen *screen = const_cast(this); xcb_window_t root = screen->root(); - if (window == 0) - window = root; - - xcb_get_geometry_cookie_t geometry_cookie = xcb_get_geometry_unchecked(xcb_connection(), window); - - xcb_get_geometry_reply_t *reply = - xcb_get_geometry_reply(xcb_connection(), geometry_cookie, NULL); - - if (!reply) { + xcb_get_geometry_reply_t *rootReply = getGeometryUnchecked(xcb_connection(), root); + if (!rootReply) return QPixmap(); + + const quint8 rootDepth = rootReply->depth; + free(rootReply); + + QSize windowSize; + quint8 effectiveDepth = 0; + if (window) { + xcb_get_geometry_reply_t *windowReply = getGeometryUnchecked(xcb_connection(), window); + if (!windowReply) + return QPixmap(); + windowSize = QSize(windowReply->width, windowReply->height); + effectiveDepth = windowReply->depth; + free(windowReply); + if (effectiveDepth == rootDepth) { + // 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 + if (!translate(xcb_connection(), window, root, &x, &y)) + return QPixmap(); + + window = root; + } + } else { + window = root; + effectiveDepth = rootDepth; + windowSize = m_geometry.size(); + x += m_geometry.x(); + y += m_geometry.y(); } if (width < 0) - width = reply->width - x; + width = windowSize.width() - xIn; if (height < 0) - height = reply->height - y; - - geometry_cookie = xcb_get_geometry_unchecked(xcb_connection(), root); - xcb_get_geometry_reply_t *root_reply = - xcb_get_geometry_reply(xcb_connection(), geometry_cookie, NULL); - - if (!root_reply) { - 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_unchecked(xcb_connection(), window, root, x, y); - - xcb_translate_coordinates_reply_t *translate_reply = - xcb_translate_coordinates_reply(xcb_connection(), translate_cookie, NULL); - - if (!translate_reply) { - 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; - } + height = windowSize.height() - yIn; xcb_get_window_attributes_reply_t *attributes_reply = xcb_get_window_attributes_reply(xcb_connection(), xcb_get_window_attributes_unchecked(xcb_connection(), window), NULL); - if (!attributes_reply) { - free(reply); + if (!attributes_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()); - xcb_create_pixmap(xcb_connection(), reply->depth, pixmap, window, width, height); + xcb_create_pixmap(xcb_connection(), effectiveDepth, pixmap, window, width, height); uint32_t gc_value_mask = XCB_GC_SUBWINDOW_MODE; uint32_t gc_value_list[] = { XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS }; @@ -766,9 +769,7 @@ QPixmap QXcbScreen::grabWindow(WId window, int x, int y, int width, int height) xcb_copy_area(xcb_connection(), window, pixmap, gc, x, y, 0, 0, width, height); - QPixmap result = qt_xcb_pixmapFromXPixmap(connection(), pixmap, width, height, reply->depth, visual); - - free(reply); + QPixmap result = qt_xcb_pixmapFromXPixmap(connection(), pixmap, width, height, effectiveDepth, visual); xcb_free_gc(xcb_connection(), gc); xcb_free_pixmap(xcb_connection(), pixmap);