XCB QPA: Fix QScreen::grabWindow(0) to return the current screen

Previously, the code queried the window to be grabbed for the geometry
and thus returned the entire virtual desktop for multi screen setups.

Use the QPlatformScreen's geometry in case of WID = 0.

Task-number: QTBUG-58110
Change-Id: I3a9c0b0b3ea057f5e58f272f5c3fd40fafc073ba
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
Friedemann Kleint 2017-01-13 09:56:59 +01:00
parent 9ba16336c5
commit b6967d0c11

View File

@ -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<QXcbScreen *>(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);