diff options
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbintegration.cpp')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbintegration.cpp | 220 |
1 files changed, 203 insertions, 17 deletions
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 12b63f36ea..fcc17b28b2 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -43,14 +43,20 @@ #include "qxcbconnection.h" #include "qxcbscreen.h" #include "qxcbwindow.h" -#include "qxcbwindowsurface.h" +#include "qxcbbackingstore.h" #include "qxcbnativeinterface.h" +#include "qxcbclipboard.h" +#include "qxcbdrag.h" +#include "qxcbimage.h" + +#include <QtPlatformSupport/private/qgenericunixprintersupport_p.h> #include <xcb/xcb.h> #include <private/qpixmap_raster_p.h> -#include "qgenericunixfontdatabase.h" +#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> +#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> #include <stdio.h> @@ -58,14 +64,28 @@ #include <EGL/egl.h> #endif +#if defined(XCB_USE_GLX) +#include "qglxintegration.h" +#elif defined(XCB_USE_EGL) +#include "qxcbeglsurface.h" +#include <QtPlatformSupport/private/qeglplatformcontext_p.h> +#endif + +#define XCB_USE_IBUS +#if defined(XCB_USE_IBUS) +#include "QtPlatformSupport/qibusplatforminputcontext.h" +#endif + QXcbIntegration::QXcbIntegration() - : m_connection(new QXcbConnection) + : m_connection(new QXcbConnection), m_printerSupport(new QGenericUnixPrinterSupport) { foreach (QXcbScreen *screen, m_connection->screens()) m_screens << screen; m_fontDatabase = new QGenericUnixFontDatabase(); m_nativeInterface = new QXcbNativeInterface; + + m_inputContext = 0; } QXcbIntegration::~QXcbIntegration() @@ -87,16 +107,53 @@ QPixmapData *QXcbIntegration::createPixmapData(QPixmapData::PixelType type) cons return new QRasterPixmapData(type); } -QPlatformWindow *QXcbIntegration::createPlatformWindow(QWidget *widget, WId winId) const +QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const { - Q_UNUSED(winId); - return new QXcbWindow(widget); + return new QXcbWindow(window); } -QWindowSurface *QXcbIntegration::createWindowSurface(QWidget *widget, WId winId) const +#if defined(XCB_USE_EGL) +class QEGLXcbPlatformContext : public QEGLPlatformContext +{ +public: + QEGLXcbPlatformContext(const QSurfaceFormat &glFormat, QPlatformGLContext *share, EGLDisplay display) + : QEGLPlatformContext(glFormat, share, display) + { + } + + EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) + { + return static_cast<QXcbWindow *>(surface)->eglSurface()->surface(); + } +}; +#endif + +QPlatformGLContext *QXcbIntegration::createPlatformGLContext(const QSurfaceFormat &glFormat, QPlatformGLContext *share) const { - Q_UNUSED(winId); - return new QXcbWindowSurface(widget); +#if defined(XCB_USE_GLX) + return new QGLXContext(static_cast<QXcbScreen *>(m_screens.at(0)), glFormat, share); +#elif defined(XCB_USE_EGL) + return new QEGLXcbPlatformContext(glFormat, share, m_connection->egl_display()); +#elif defined(XCB_USE_DRI2) + return new QDri2Context(glFormat, share); +#endif +} + +QPlatformBackingStore *QXcbIntegration::createPlatformBackingStore(QWindow *window) const +{ + return new QXcbBackingStore(window); +} + +QAbstractEventDispatcher *QXcbIntegration::createEventDispatcher() const +{ + QAbstractEventDispatcher *eventDispatcher = createUnixEventDispatcher(); + m_connection->setEventDispatcher(eventDispatcher); +#ifdef XCB_USE_IBUS + // A bit hacky to do this here, but we need an eventloop before we can instantiate + // the input context. + const_cast<QXcbIntegration *>(this)->m_inputContext = new QIBusPlatformInputContext; +#endif + return eventDispatcher; } QList<QPlatformScreen *> QXcbIntegration::screens() const @@ -104,7 +161,7 @@ QList<QPlatformScreen *> QXcbIntegration::screens() const return m_screens; } -void QXcbIntegration::moveToScreen(QWidget *window, int screen) +void QXcbIntegration::moveToScreen(QWindow *window, int screen) { Q_UNUSED(window); Q_UNUSED(screen); @@ -122,14 +179,123 @@ QPlatformFontDatabase *QXcbIntegration::fontDatabase() const 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(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(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); + } + + QPixmap result = qt_xcb_pixmapFromXPixmap(m_connection, pixmap, width, height, reply->depth, visual); + + free(reply); + xcb_free_gc(connection, gc); + xcb_free_pixmap(connection, pixmap); + + return result; +} bool QXcbIntegration::hasOpenGL() const { @@ -149,3 +315,23 @@ QPlatformNativeInterface * QXcbIntegration::nativeInterface() const { return m_nativeInterface; } + +QPlatformPrinterSupport *QXcbIntegration::printerSupport() const +{ + return m_printerSupport; +} + +QPlatformClipboard *QXcbIntegration::clipboard() const +{ + return m_connection->clipboard(); +} + +QPlatformDrag *QXcbIntegration::drag() const +{ + return m_connection->drag(); +} + +QPlatformInputContext *QXcbIntegration::inputContext() const +{ + return m_inputContext; +} |