Implemented QXcbIntegration::grabWindow().
parent
1f456b4cbb
commit
e99ab7de9b
|
|
@ -740,6 +740,21 @@ QByteArray QXcbConnection::atomName(xcb_atom_t atom)
|
|||
return QByteArray();
|
||||
}
|
||||
|
||||
const xcb_format_t *QXcbConnection::formatForDepth(uint8_t depth) const
|
||||
{
|
||||
xcb_format_iterator_t iterator =
|
||||
xcb_setup_pixmap_formats_iterator(m_setup);
|
||||
|
||||
while (iterator.rem) {
|
||||
xcb_format_t *format = iterator.data;
|
||||
if (format->depth == depth)
|
||||
return format;
|
||||
xcb_format_next(&iterator);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void QXcbConnection::sync()
|
||||
{
|
||||
// from xcb_aux_sync
|
||||
|
|
|
|||
|
|
@ -247,6 +247,8 @@ public:
|
|||
const char *displayName() const { return m_displayName.constData(); }
|
||||
|
||||
xcb_connection_t *xcb_connection() const { return m_connection; }
|
||||
const xcb_setup_t *setup() const { return m_setup; }
|
||||
const xcb_format_t *formatForDepth(uint8_t depth) const;
|
||||
|
||||
QXcbKeyboard *keyboard() const { return m_keyboard; }
|
||||
|
||||
|
|
|
|||
|
|
@ -125,14 +125,218 @@ QPlatformFontDatabase *QXcbIntegration::fontDatabase() const
|
|||
return m_fontDatabase;
|
||||
}
|
||||
|
||||
static QImage::Format imageFormatForVisual(QXcbConnection *connection, uint8_t depth, const xcb_visualtype_t *visual)
|
||||
{
|
||||
const xcb_format_t *format = connection->formatForDepth(depth);
|
||||
|
||||
if (!visual || !format)
|
||||
return QImage::Format_Invalid;
|
||||
|
||||
if (depth == 32 && format->bits_per_pixel == 32 && visual->red_mask == 0xff0000
|
||||
&& visual->green_mask == 0xff00 && visual->blue_mask == 0xff)
|
||||
return QImage::Format_ARGB32_Premultiplied;
|
||||
|
||||
if (depth == 24 && format->bits_per_pixel == 32 && visual->red_mask == 0xff0000
|
||||
&& visual->green_mask == 0xff00 && visual->blue_mask == 0xff)
|
||||
return QImage::Format_RGB32;
|
||||
|
||||
if (depth == 16 && format->bits_per_pixel == 16 && visual->red_mask == 0xf800
|
||||
&& visual->green_mask == 0x7e0 && visual->blue_mask == 0x1f)
|
||||
return QImage::Format_RGB16;
|
||||
|
||||
return QImage::Format_Invalid;
|
||||
}
|
||||
|
||||
QPixmap QXcbIntegration::grabWindow(WId window, int x, int y, int width, int height) const
|
||||
{
|
||||
Q_UNUSED(window);
|
||||
Q_UNUSED(x);
|
||||
Q_UNUSED(y);
|
||||
Q_UNUSED(width);
|
||||
Q_UNUSED(height);
|
||||
return QPixmap();
|
||||
if (width == 0 || height == 0)
|
||||
return QPixmap();
|
||||
|
||||
xcb_connection_t *connection = m_connection->xcb_connection();
|
||||
|
||||
xcb_get_geometry_cookie_t geometry_cookie = xcb_get_geometry(connection, window);
|
||||
|
||||
xcb_generic_error_t *error;
|
||||
xcb_get_geometry_reply_t *reply =
|
||||
xcb_get_geometry_reply(connection, geometry_cookie, &error);
|
||||
|
||||
if (!reply) {
|
||||
if (error) {
|
||||
m_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 = m_connection->screens().at(0);
|
||||
xcb_window_t root = screen->root();
|
||||
geometry_cookie = xcb_get_geometry(connection, root);
|
||||
xcb_get_geometry_reply_t *root_reply =
|
||||
xcb_get_geometry_reply(connection, geometry_cookie, &error);
|
||||
|
||||
if (!root_reply) {
|
||||
if (error) {
|
||||
m_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(connection, window, root, x, y);
|
||||
|
||||
xcb_translate_coordinates_reply_t *translate_reply =
|
||||
xcb_translate_coordinates_reply(connection, translate_cookie, &error);
|
||||
|
||||
if (!translate_reply) {
|
||||
if (error) {
|
||||
m_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(reply);
|
||||
reply = root_reply;
|
||||
} else {
|
||||
free(root_reply);
|
||||
root_reply = 0;
|
||||
}
|
||||
|
||||
xcb_get_window_attributes_reply_t *attributes_reply =
|
||||
xcb_get_window_attributes_reply(connection, xcb_get_window_attributes(connection, window), &error);
|
||||
|
||||
if (!attributes_reply) {
|
||||
if (error) {
|
||||
m_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(connection);
|
||||
error = xcb_request_check(connection, xcb_create_pixmap_checked(connection, reply->depth, pixmap, window, width, height));
|
||||
if (error) {
|
||||
m_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(connection);
|
||||
xcb_create_gc(connection, gc, pixmap, gc_value_mask, gc_value_list);
|
||||
|
||||
error = xcb_request_check(connection, xcb_copy_area_checked(connection, window, pixmap, gc, x, y, 0, 0, width, height));
|
||||
if (error) {
|
||||
m_connection->handleXcbError(error);
|
||||
free(error);
|
||||
}
|
||||
|
||||
xcb_get_image_cookie_t get_image_cookie =
|
||||
xcb_get_image(connection, XCB_IMAGE_FORMAT_Z_PIXMAP, pixmap, 0, 0, width, height, 0xffffffff);
|
||||
|
||||
xcb_get_image_reply_t *image_reply =
|
||||
xcb_get_image_reply(connection, get_image_cookie, &error);
|
||||
|
||||
xcb_free_gc(connection, gc);
|
||||
xcb_free_pixmap(connection, pixmap);
|
||||
|
||||
uint8_t depth = reply->depth;
|
||||
|
||||
free(reply);
|
||||
|
||||
if (!image_reply) {
|
||||
if (error) {
|
||||
m_connection->handleXcbError(error);
|
||||
free(error);
|
||||
}
|
||||
return QPixmap();
|
||||
}
|
||||
|
||||
uint8_t *data = xcb_get_image_data(image_reply);
|
||||
uint32_t length = xcb_get_image_data_length(image_reply);
|
||||
|
||||
QPixmap result;
|
||||
|
||||
QImage::Format format = imageFormatForVisual(m_connection, depth, visual);
|
||||
if (format != QImage::Format_Invalid) {
|
||||
uint32_t bytes_per_line = length / height;
|
||||
QImage image(const_cast<uint8_t *>(data), width, height, bytes_per_line, format);
|
||||
uint8_t image_byte_order = m_connection->setup()->image_byte_order;
|
||||
|
||||
// we may have to swap the byte order
|
||||
if ((QSysInfo::ByteOrder == QSysInfo::LittleEndian && image_byte_order == XCB_IMAGE_ORDER_MSB_FIRST)
|
||||
|| (QSysInfo::ByteOrder == QSysInfo::BigEndian && image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST))
|
||||
{
|
||||
for (int i=0; i < image.height(); i++) {
|
||||
switch (format) {
|
||||
case QImage::Format_RGB16: {
|
||||
ushort *p = (ushort*)image.scanLine(i);
|
||||
ushort *end = p + image.width();
|
||||
while (p < end) {
|
||||
*p = ((*p << 8) & 0xff00) | ((*p >> 8) & 0x00ff);
|
||||
p++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QImage::Format_RGB32: // fall-through
|
||||
case QImage::Format_ARGB32_Premultiplied: {
|
||||
uint *p = (uint*)image.scanLine(i);
|
||||
uint *end = p + image.width();
|
||||
while (p < end) {
|
||||
*p = ((*p << 24) & 0xff000000) | ((*p << 8) & 0x00ff0000)
|
||||
| ((*p >> 8) & 0x0000ff00) | ((*p >> 24) & 0x000000ff);
|
||||
p++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fix-up alpha channel
|
||||
if (format == QImage::Format_RGB32) {
|
||||
QRgb *p = (QRgb *)image.bits();
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int x = 0; x < width; ++x)
|
||||
p[x] |= 0xff000000;
|
||||
p += bytes_per_line / 4;
|
||||
}
|
||||
}
|
||||
|
||||
image.detach();
|
||||
result = QPixmap::fromImage(image);
|
||||
}
|
||||
|
||||
free(image_reply);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -122,12 +122,37 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int num
|
|||
32,
|
||||
1,
|
||||
&m_clientLeader), connection);
|
||||
|
||||
xcb_depth_iterator_t depth_iterator =
|
||||
xcb_screen_allowed_depths_iterator(screen);
|
||||
|
||||
while (depth_iterator.rem) {
|
||||
xcb_depth_t *depth = depth_iterator.data;
|
||||
xcb_visualtype_iterator_t visualtype_iterator =
|
||||
xcb_depth_visuals_iterator(depth);
|
||||
|
||||
while (visualtype_iterator.rem) {
|
||||
xcb_visualtype_t *visualtype = visualtype_iterator.data;
|
||||
m_visuals.insert(visualtype->visual_id, *visualtype);
|
||||
xcb_visualtype_next(&visualtype_iterator);
|
||||
}
|
||||
|
||||
xcb_depth_next(&depth_iterator);
|
||||
}
|
||||
}
|
||||
|
||||
QXcbScreen::~QXcbScreen()
|
||||
{
|
||||
}
|
||||
|
||||
const xcb_visualtype_t *QXcbScreen::visualForId(xcb_visualid_t visualid) const
|
||||
{
|
||||
QMap<xcb_visualid_t, xcb_visualtype_t>::const_iterator it = m_visuals.find(visualid);
|
||||
if (it == m_visuals.constEnd())
|
||||
return 0;
|
||||
return &*it;
|
||||
}
|
||||
|
||||
QRect QXcbScreen::geometry() const
|
||||
{
|
||||
return QRect(0, 0, m_screen->width_in_pixels, m_screen->height_in_pixels);
|
||||
|
|
|
|||
|
|
@ -72,12 +72,15 @@ public:
|
|||
QString windowManagerName() const { return m_windowManagerName; }
|
||||
bool syncRequestSupported() const { return m_syncRequestSupported; }
|
||||
|
||||
const xcb_visualtype_t *visualForId(xcb_visualid_t) const;
|
||||
|
||||
private:
|
||||
xcb_screen_t *m_screen;
|
||||
int m_number;
|
||||
QString m_windowManagerName;
|
||||
bool m_syncRequestSupported;
|
||||
xcb_window_t m_clientLeader;
|
||||
QMap<xcb_visualid_t, xcb_visualtype_t> m_visuals;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue