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:
parent
9ba16336c5
commit
b6967d0c11
@ -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)
|
if (width == 0 || height == 0)
|
||||||
return QPixmap();
|
return QPixmap();
|
||||||
|
|
||||||
// TODO: handle multiple screens
|
int x = xIn;
|
||||||
|
int y = yIn;
|
||||||
QXcbScreen *screen = const_cast<QXcbScreen *>(this);
|
QXcbScreen *screen = const_cast<QXcbScreen *>(this);
|
||||||
xcb_window_t root = screen->root();
|
xcb_window_t root = screen->root();
|
||||||
|
|
||||||
if (window == 0)
|
xcb_get_geometry_reply_t *rootReply = getGeometryUnchecked(xcb_connection(), root);
|
||||||
window = root;
|
if (!rootReply)
|
||||||
|
|
||||||
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) {
|
|
||||||
return QPixmap();
|
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)
|
if (width < 0)
|
||||||
width = reply->width - x;
|
width = windowSize.width() - xIn;
|
||||||
if (height < 0)
|
if (height < 0)
|
||||||
height = reply->height - y;
|
height = windowSize.height() - yIn;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
xcb_get_window_attributes_reply_t *attributes_reply =
|
xcb_get_window_attributes_reply_t *attributes_reply =
|
||||||
xcb_get_window_attributes_reply(xcb_connection(), xcb_get_window_attributes_unchecked(xcb_connection(), window), NULL);
|
xcb_get_window_attributes_reply(xcb_connection(), xcb_get_window_attributes_unchecked(xcb_connection(), window), NULL);
|
||||||
|
|
||||||
if (!attributes_reply) {
|
if (!attributes_reply)
|
||||||
free(reply);
|
|
||||||
return QPixmap();
|
return QPixmap();
|
||||||
}
|
|
||||||
|
|
||||||
const xcb_visualtype_t *visual = screen->visualForId(attributes_reply->visual);
|
const xcb_visualtype_t *visual = screen->visualForId(attributes_reply->visual);
|
||||||
free(attributes_reply);
|
free(attributes_reply);
|
||||||
|
|
||||||
xcb_pixmap_t pixmap = xcb_generate_id(xcb_connection());
|
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_mask = XCB_GC_SUBWINDOW_MODE;
|
||||||
uint32_t gc_value_list[] = { XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS };
|
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);
|
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);
|
QPixmap result = qt_xcb_pixmapFromXPixmap(connection(), pixmap, width, height, effectiveDepth, visual);
|
||||||
|
|
||||||
free(reply);
|
|
||||||
xcb_free_gc(xcb_connection(), gc);
|
xcb_free_gc(xcb_connection(), gc);
|
||||||
xcb_free_pixmap(xcb_connection(), pixmap);
|
xcb_free_pixmap(xcb_connection(), pixmap);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user