diff options
Diffstat (limited to 'src/plugins/platforms')
136 files changed, 6488 insertions, 4146 deletions
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index bfa147f948..5573b19fcd 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -7,23 +7,29 @@ OBJECTIVE_SOURCES = main.mm \ qcocoawindowsurface.mm \ qcocoawindow.mm \ qnsview.mm \ - qcocoaeventloopintegration.mm \ qcocoaautoreleasepool.mm \ - qnswindowdelegate.mm + qnswindowdelegate.mm \ + qcocoaglcontext.mm \ + qcocoanativeinterface.mm + OBJECTIVE_HEADERS = qcocoaintegration.h \ qcocoawindowsurface.h \ qcocoawindow.h \ qnsview.h \ - qcocoaeventloopintegration.h \ qcocoaautoreleasepool.h \ - qnswindowdelegate.h + qnswindowdelegate.h \ + qcocoaglcontext.h \ + qcocoanativeinterface.h + +DEFINES += QT_BUILD_COCOA_LIB #add libz for freetype. LIBS += -lz LIBS += -framework cocoa -include(../fontdatabases/coretext/coretext.pri) +QT += core-private gui-private platformsupport-private + +CONFIG += qpa/basicunixfontdatabase target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target - diff --git a/src/plugins/platforms/cocoa/qcocoaeventloopintegration.mm b/src/plugins/platforms/cocoa/qcocoaeventloopintegration.mm deleted file mode 100644 index ac0b75e9ea..0000000000 --- a/src/plugins/platforms/cocoa/qcocoaeventloopintegration.mm +++ /dev/null @@ -1,112 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qcocoaeventloopintegration.h" - -#import <Cocoa/Cocoa.h> - -#include "qcocoaautoreleasepool.h" - -#include <QtCore/QElapsedTimer> - -#include <QDebug> -#include <QApplication> - -void wakeupCallback ( void * ) { - QPlatformEventLoopIntegration::processEvents(); -} - -void timerCallback( CFRunLoopTimerRef timer, void *info) -{ - QPlatformEventLoopIntegration::processEvents(); - QCocoaEventLoopIntegration *eventLoopIntegration = - static_cast<QCocoaEventLoopIntegration *>(info); - qint64 nextTime = eventLoopIntegration->nextTimerEvent(); - CFAbsoluteTime nexttime = CFAbsoluteTimeGetCurrent(); - nexttime = nexttime + (double(nextTime)/1000); - CFRunLoopTimerSetNextFireDate(timer,nexttime); -} - -QCocoaEventLoopIntegration::QCocoaEventLoopIntegration() : - QPlatformEventLoopIntegration() -{ - [NSApplication sharedApplication]; - m_sourceContext.version = 0; - m_sourceContext.info = this; - m_sourceContext.retain = 0; - m_sourceContext.release = 0; - m_sourceContext.copyDescription = 0; - m_sourceContext.equal = 0; - m_sourceContext.hash = 0; - m_sourceContext.schedule = 0; - m_sourceContext.cancel = 0; - m_sourceContext.perform = wakeupCallback; - - m_source = CFRunLoopSourceCreate(0,0,&m_sourceContext); - CFRunLoopAddSource(CFRunLoopGetMain(),m_source,kCFRunLoopCommonModes); - - m_timerContext.version = 0; - m_timerContext.info = this; - m_timerContext.retain = 0; - m_timerContext.release = 0; - m_timerContext.copyDescription = 0; - CFAbsoluteTime fireDate = CFAbsoluteTimeGetCurrent (); - CFTimeInterval interval = 30; - - CFRunLoopTimerRef m_timerSource = CFRunLoopTimerCreate(0,fireDate,interval,0,0,timerCallback,&m_timerContext); - CFRunLoopAddTimer(CFRunLoopGetMain(),m_timerSource,kCFRunLoopCommonModes); -} - -void QCocoaEventLoopIntegration::startEventLoop() -{ - [[NSApplication sharedApplication] run]; -} - -void QCocoaEventLoopIntegration::quitEventLoop() -{ - [[NSApplication sharedApplication] terminate:nil]; -} - -void QCocoaEventLoopIntegration::qtNeedsToProcessEvents() -{ - CFRunLoopSourceSignal(m_source); -} - diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h new file mode 100644 index 0000000000..01d931b662 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h @@ -0,0 +1,54 @@ +#ifndef QCOCOAGLCONTEXT_H +#define QCOCOAGLCONTEXT_H + +#include <QtCore/QWeakPointer> +#include <QtGui/QPlatformGLContext> +#include <QtGui/QGuiGLContext> +#include <QtGui/QWindow> + +#include <Cocoa/Cocoa.h> + +QT_BEGIN_NAMESPACE + +class QCocoaGLSurface : public QPlatformGLSurface +{ +public: + QCocoaGLSurface(const QGuiGLFormat &format, QWindow *window) + : QPlatformGLSurface(format) + , window(window) + { + } + + QWindow *window; +}; + +class QCocoaGLContext : public QPlatformGLContext +{ +public: + QCocoaGLContext(const QGuiGLFormat &format, QPlatformGLContext *share); + + QGuiGLFormat format() const; + + void swapBuffers(const QPlatformGLSurface &surface); + + bool makeCurrent(const QPlatformGLSurface &surface); + void doneCurrent(); + + void (*getProcAddress(const QByteArray &procName)) (); + + void update(); + + static NSOpenGLPixelFormat *createNSOpenGLPixelFormat(); + NSOpenGLContext *nsOpenGLContext() const; + +private: + void setActiveWindow(QWindow *window); + + NSOpenGLContext *m_context; + QGuiGLFormat m_format; + QWeakPointer<QWindow> m_currentWindow; +}; + +QT_END_NAMESPACE + +#endif // QCOCOAGLCONTEXT_H diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm new file mode 100644 index 0000000000..f9cda1bb37 --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -0,0 +1,105 @@ +#include "qcocoaglcontext.h" +#include "qcocoawindow.h" +#include <qdebug.h> +#include <QtCore/private/qcore_mac_p.h> + +#import <Cocoa/Cocoa.h> + +QCocoaGLContext::QCocoaGLContext(const QGuiGLFormat &format, QPlatformGLContext *share) + : m_format(format) +{ + NSOpenGLPixelFormat *pixelFormat = createNSOpenGLPixelFormat(); + NSOpenGLContext *actualShare = share ? static_cast<QCocoaGLContext *>(share)->m_context : 0; + + m_context = [NSOpenGLContext alloc]; + [m_context initWithFormat:pixelFormat shareContext:actualShare]; +} + +// Match up with createNSOpenGLPixelFormat! +QGuiGLFormat QCocoaGLContext::format() const +{ + return m_format; +} + +void QCocoaGLContext::swapBuffers(const QPlatformGLSurface &surface) +{ + QWindow *window = static_cast<const QCocoaGLSurface &>(surface).window; + setActiveWindow(window); + + [m_context flushBuffer]; +} + +bool QCocoaGLContext::makeCurrent(const QPlatformGLSurface &surface) +{ + QWindow *window = static_cast<const QCocoaGLSurface &>(surface).window; + setActiveWindow(window); + + [m_context makeCurrentContext]; + return true; +} + +void QCocoaGLContext::setActiveWindow(QWindow *window) +{ + if (window == m_currentWindow.data()) + return; + + if (m_currentWindow) + static_cast<QCocoaWindow *>(m_currentWindow.data()->handle())->setCurrentContext(0); + + Q_ASSERT(window->handle()); + + m_currentWindow = window; + + QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); + cocoaWindow->setCurrentContext(this); + + NSView *view = cocoaWindow->windowSurfaceView(); + [m_context setView:view]; +} + +void QCocoaGLContext::doneCurrent() +{ + if (m_currentWindow) + static_cast<QCocoaWindow *>(m_currentWindow.data()->handle())->setCurrentContext(0); + + m_currentWindow.clear(); + + [NSOpenGLContext clearCurrentContext]; +} + +void (*QCocoaGLContext::getProcAddress(const QByteArray &procName)) () +{ + CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, + CFSTR("/System/Library/Frameworks/OpenGL.framework"), kCFURLPOSIXPathStyle, false); + CFBundleRef bundle = CFBundleCreate(kCFAllocatorDefault, url); + CFStringRef procNameCF = QCFString::toCFStringRef(QString::fromAscii(procName.constData())); + void *proc = CFBundleGetFunctionPointerForName(bundle, procNameCF); + CFRelease(url); + CFRelease(bundle); + CFRelease(procNameCF); + return (void (*) ())proc; +} + +void QCocoaGLContext::update() +{ + [m_context update]; +} + +NSOpenGLPixelFormat *QCocoaGLContext::createNSOpenGLPixelFormat() +{ + NSOpenGLPixelFormatAttribute attrs[] = + { + NSOpenGLPFADoubleBuffer, + NSOpenGLPFADepthSize, 32, + 0 + }; + + NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; + return pixelFormat; +} + +NSOpenGLContext *QCocoaGLContext::nsOpenGLContext() const +{ + return m_context; +} + diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index 120bee46b7..59008b4e3f 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -77,15 +77,15 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const; QPixmapData *createPixmapData(QPixmapData::PixelType type) const; - QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId = 0) const; - QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const; + QPlatformWindow *createPlatformWindow(QWindow *window) const; + QPlatformGLContext *createPlatformGLContext(const QGuiGLFormat &glFormat, QPlatformGLContext *share) const; + QWindowSurface *createWindowSurface(QWindow *widget, WId winId) const; QList<QPlatformScreen *> screens() const { return mScreens; } QPlatformFontDatabase *fontDatabase() const; - QPlatformEventLoopIntegration *createEventLoopIntegration() const; - + QPlatformNativeInterface *nativeInterface() const; private: QList<QPlatformScreen *> mScreens; QPlatformFontDatabase *mFontDb; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 086f7b62e9..dfe225ff2e 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -43,11 +43,9 @@ #include "qcocoawindow.h" #include "qcocoawindowsurface.h" -#include "qcocoaeventloopintegration.h" +#include "qcocoanativeinterface.h" -#include "qcoretextfontdatabase.h" - -#include <QtGui/QApplication> +#include "qbasicunixfontdatabase.h" #include <private/qpixmap_raster_p.h> @@ -74,7 +72,7 @@ QCocoaScreen::~QCocoaScreen() } QCocoaIntegration::QCocoaIntegration() - : mFontDb(new QCoreTextFontDatabase()) + : mFontDb(new QBasicUnixFontDatabase()) { mPool = new QCocoaAutoReleasePool; @@ -98,6 +96,7 @@ bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) cons { switch (cap) { case ThreadedPixmaps: return true; + case OpenGL : return true; default: return QPlatformIntegration::hasCapability(cap); } } @@ -109,15 +108,19 @@ QPixmapData *QCocoaIntegration::createPixmapData(QPixmapData::PixelType type) co return new QRasterPixmapData(type); } -QPlatformWindow *QCocoaIntegration::createPlatformWindow(QWidget *widget, WId winId) const +QPlatformWindow *QCocoaIntegration::createPlatformWindow(QWindow *window) const { - Q_UNUSED(winId); - return new QCocoaWindow(widget); + return new QCocoaWindow(window); } -QWindowSurface *QCocoaIntegration::createWindowSurface(QWidget *widget, WId winId) const +QPlatformGLContext *QCocoaIntegration::createPlatformGLContext(const QGuiGLFormat &glFormat, QPlatformGLContext *share) const { - return new QCocoaWindowSurface(widget,winId); + return new QCocoaGLContext(glFormat, share); +} + +QWindowSurface *QCocoaIntegration::createWindowSurface(QWindow *window, WId winId) const +{ + return new QCocoaWindowSurface(window, winId); } QPlatformFontDatabase *QCocoaIntegration::fontDatabase() const @@ -125,8 +128,9 @@ QPlatformFontDatabase *QCocoaIntegration::fontDatabase() const return mFontDb; } -QPlatformEventLoopIntegration *QCocoaIntegration::createEventLoopIntegration() const +QPlatformNativeInterface *QCocoaIntegration::nativeInterface() const { - return new QCocoaEventLoopIntegration(); + return new QCocoaNativeInterface(); } + QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglconvenience/qxlibeglintegration.h b/src/plugins/platforms/cocoa/qcocoanativeinterface.h index 1d02ab8677..f8216d8e61 100644 --- a/src/plugins/platforms/eglconvenience/qxlibeglintegration.h +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.h @@ -39,15 +39,17 @@ ** ****************************************************************************/ -#ifndef QTESTLITEEGLINTEGRATION_H -#define QTESTLITEEGLINTEGRATION_H +#ifndef QCOCOANATIVEINTERFACE_H +#define QCOCOANATIVEINTERFACE_H -#include "qeglconvenience.h" +#include <QtGui/QPlatformNativeInterface> -class QXlibEglIntegration +class QWidget; + +class QCocoaNativeInterface : public QPlatformNativeInterface { public: - static VisualID getCompatibleVisualId(Display *display, EGLDisplay eglDisplay, EGLConfig config); + void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window); }; -#endif // QTESTLITEEGLINTEGRATION_H +#endif // QCOCOANATIVEINTERFACE_H diff --git a/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.h b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index 61700e391a..87d0ec4a0c 100644 --- a/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.h +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm @@ -39,18 +39,22 @@ ** ****************************************************************************/ -#ifndef QFONTCONFIGDATABASE_H -#define QFONTCONFIGDATABASE_H +#include "qcocoanativeinterface.h" +#include "qcocoaglcontext.h" +#include "qcocoawindow.h" +#include <qbytearray.h> +#include <qwindow.h> +#include "qplatformwindow_qpa.h" +#include "qguiglformat_qpa.h" +#include "qplatformglcontext_qpa.h" +#include "qguiglcontext_qpa.h" +#include <qdebug.h> -#include <QPlatformFontDatabase> -#include "qbasicunixfontdatabase.h" - -class QFontconfigDatabase : public QBasicUnixFontDatabase +void *QCocoaNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) { -public: - void populateFontDatabase(); - QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle); - QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const; -}; + if (resourceString == "nsopenglcontext") { -#endif // QFONTCONFIGDATABASE_H + static_cast<QCocoaWindow *>(window->handle())->currentContext()->nsOpenGLContext(); + } + return 0; +} diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 9e7e68b7d2..9d7d37c2ee 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -46,27 +46,41 @@ #include <QPlatformWindow> +#include "qcocoaglcontext.h" +#include "qnsview.h" + QT_BEGIN_NAMESPACE class QCocoaWindow : public QPlatformWindow { public: - QCocoaWindow(QWidget *tlw); + QCocoaWindow(QWindow *tlw); ~QCocoaWindow(); void setGeometry(const QRect &rect); - void setVisible(bool visible); + void setWindowTitle(const QString &title); + void raise(); + void lower(); WId winId() const; - NSView *contentView() const; - void setContentView(NSView *contentView); + NSView *windowSurfaceView() const; + void windowDidMove(); void windowDidResize(); + QPlatformGLSurface *createGLSurface() const; + + void setCurrentContext(QCocoaGLContext *context); + QCocoaGLContext *currentContext() const; + private: + friend class QCocoaWindowSurface; NSWindow *m_nsWindow; + QNSView *m_contentView; + NSView *m_windowSurfaceView; + QCocoaGLContext *m_glContext; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index a2fdce3520..874790a128 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -41,17 +41,17 @@ #include "qcocoawindow.h" #include "qnswindowdelegate.h" #include "qcocoaautoreleasepool.h" - -#include <QWidget> - -#include <QtGui/QApplication> +#include "qcocoaglcontext.h" +#include "qnsview.h" +#include <QtCore/private/qcore_mac_p.h> #include <QWindowSystemInterface> #include <QDebug> -QCocoaWindow::QCocoaWindow(QWidget *tlw) +QCocoaWindow::QCocoaWindow(QWindow *tlw) : QPlatformWindow(tlw) + , m_glContext(0) { QCocoaAutoReleasePool pool; const QRect geo = tlw->geometry(); @@ -65,12 +65,26 @@ QCocoaWindow::QCocoaWindow(QWidget *tlw) QNSWindowDelegate *delegate = [[QNSWindowDelegate alloc] initWithQCocoaWindow:this]; [m_nsWindow setDelegate:delegate]; - [m_nsWindow makeKeyAndOrderFront:nil]; [m_nsWindow setAcceptsMouseMovedEvents:YES]; + + m_contentView = [[QNSView alloc] initWithQWindow:tlw]; + + if (tlw->surfaceType() == QWindow::OpenGLSurface) { + NSRect glFrame = NSMakeRect(0, 0, geo.width(), geo.height()); + m_windowSurfaceView = [[NSOpenGLView alloc] initWithFrame : glFrame pixelFormat : QCocoaGLContext::createNSOpenGLPixelFormat() ]; + [m_contentView setAutoresizesSubviews : YES]; + [m_windowSurfaceView setAutoresizingMask : (NSViewWidthSizable | NSViewHeightSizable)]; + [m_contentView addSubview : m_windowSurfaceView]; + } else { + m_windowSurfaceView = m_contentView; + } + + [m_nsWindow setContentView:m_contentView]; } QCocoaWindow::~QCocoaWindow() { + } void QCocoaWindow::setGeometry(const QRect &rect) @@ -79,16 +93,41 @@ void QCocoaWindow::setGeometry(const QRect &rect) NSRect bounds = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height()); [[m_nsWindow contentView]setFrameSize:bounds.size]; + + if (m_glContext) + m_glContext->update(); } void QCocoaWindow::setVisible(bool visible) { - Q_UNUSED(visible); + if (visible) { + [m_nsWindow makeKeyAndOrderFront:nil]; + } else { + [m_nsWindow orderOut:nil]; + } +} + +void QCocoaWindow::setWindowTitle(const QString &title) +{ + CFStringRef windowTitle = QCFString::toCFStringRef(title); + [m_nsWindow setTitle: reinterpret_cast<const NSString *>(windowTitle)]; + CFRelease(windowTitle); +} + +void QCocoaWindow::raise() +{ + // ### handle spaces (see Qt 4 raise_sys in qwidget_mac.mm) + [m_nsWindow orderFront]; +} + +void QCocoaWindow::lower() +{ + [m_nsWindow orderBack]; } WId QCocoaWindow::winId() const { - return WId([m_nsWindow windowNumber]); + return WId(m_nsWindow); } NSView *QCocoaWindow::contentView() const @@ -96,9 +135,15 @@ NSView *QCocoaWindow::contentView() const return [m_nsWindow contentView]; } -void QCocoaWindow::setContentView(NSView *contentView) +NSView *QCocoaWindow::windowSurfaceView() const +{ + return m_windowSurfaceView; +} + +void QCocoaWindow::windowDidMove() { - [m_nsWindow setContentView:contentView]; + if (m_glContext) + m_glContext->update(); } void QCocoaWindow::windowDidResize() @@ -106,5 +151,25 @@ void QCocoaWindow::windowDidResize() //jlind: XXX This isn't ideal. Eventdispatcher does not run when resizing... NSRect rect = [[m_nsWindow contentView]frame]; QRect geo(rect.origin.x,rect.origin.y,rect.size.width,rect.size.height); - QWindowSystemInterface::handleGeometryChange(widget(),geo); + QWindowSystemInterface::handleGeometryChange(window(),geo); + + if (m_glContext) + m_glContext->update(); +} + +QPlatformGLSurface *QCocoaWindow::createGLSurface() const +{ + Q_ASSERT(window()->surfaceType() == QWindow::OpenGLSurface); + return new QCocoaGLSurface(window()->glFormat(), window()); } + +void QCocoaWindow::setCurrentContext(QCocoaGLContext *context) +{ + m_glContext = context; +} + +QCocoaGLContext *QCocoaWindow::currentContext() const +{ + return m_glContext; +} + diff --git a/src/plugins/platforms/cocoa/qcocoawindowsurface.h b/src/plugins/platforms/cocoa/qcocoawindowsurface.h index 95eea2b7ea..01c6ccde3e 100644 --- a/src/plugins/platforms/cocoa/qcocoawindowsurface.h +++ b/src/plugins/platforms/cocoa/qcocoawindowsurface.h @@ -54,18 +54,16 @@ QT_BEGIN_NAMESPACE class QCocoaWindowSurface : public QWindowSurface { public: - QCocoaWindowSurface(QWidget *window, WId wid); + QCocoaWindowSurface(QWindow *window, WId wid); ~QCocoaWindowSurface(); QPaintDevice *paintDevice(); - void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + void flush(QWindow *widget, const QRegion ®ion, const QPoint &offset); void resize (const QSize &size); private: - QCocoaWindow *m_cocoaWindow; QImage *m_image; - QNSView *m_contentView; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoawindowsurface.mm b/src/plugins/platforms/cocoa/qcocoawindowsurface.mm index 16bb327196..9a4b42b31e 100644 --- a/src/plugins/platforms/cocoa/qcocoawindowsurface.mm +++ b/src/plugins/platforms/cocoa/qcocoawindowsurface.mm @@ -42,7 +42,6 @@ #include "qcocoawindowsurface.h" #include <QtCore/qdebug.h> - #include <QtGui/QPainter> QT_BEGIN_NAMESPACE @@ -56,17 +55,16 @@ QRect flipedRect(const QRect &sourceRect,int height) return flippedRect; } -QCocoaWindowSurface::QCocoaWindowSurface(QWidget *window, WId wId) +QCocoaWindowSurface::QCocoaWindowSurface(QWindow *window, WId wId) : QWindowSurface(window) { - m_cocoaWindow = static_cast<QCocoaWindow *>(window->platformWindow()); + Q_UNUSED(wId); + m_cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); const QRect geo = window->geometry(); NSRect rect = NSMakeRect(geo.x(),geo.y(),geo.width(),geo.height()); - m_contentView = [[QNSView alloc] initWithWidget:window]; - m_cocoaWindow->setContentView(m_contentView); - m_image = new QImage(window->size(),QImage::Format_ARGB32); + m_image = new QImage(window->geometry().size(),QImage::Format_ARGB32); } QCocoaWindowSurface::~QCocoaWindowSurface() @@ -79,7 +77,7 @@ QPaintDevice *QCocoaWindowSurface::paintDevice() return m_image; } -void QCocoaWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +void QCocoaWindowSurface::flush(QWindow *widget, const QRegion ®ion, const QPoint &offset) { Q_UNUSED(widget); Q_UNUSED(offset); @@ -87,7 +85,7 @@ void QCocoaWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QP QRect geo = region.boundingRect(); NSRect rect = NSMakeRect(geo.x(), geo.y(), geo.width(), geo.height()); - [m_contentView displayRect:rect]; + [m_cocoaWindow->m_windowSurfaceView displayRect:rect]; } void QCocoaWindowSurface::resize(const QSize &size) @@ -96,8 +94,7 @@ void QCocoaWindowSurface::resize(const QSize &size) delete m_image; m_image = new QImage(size,QImage::Format_ARGB32_Premultiplied); NSSize newSize = NSMakeSize(size.width(),size.height()); - [m_contentView setImage:m_image]; - + [m_cocoaWindow->m_windowSurfaceView setImage:m_image]; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index 69a11134bd..0b96928d5b 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -48,17 +48,18 @@ @interface QNSView : NSView { CGImageRef m_cgImage; - QWidget *m_widget; + QWindow *m_window; Qt::MouseButtons m_buttons; } - (id)init; -- (id)initWithWidget:(QWidget *)widget; +- (id)initWithQWindow:(QWindow *)window; - (void)setImage:(QImage *)image; - (void)drawRect:(NSRect)dirtyRect; - (BOOL)isFlipped; +- (BOOL)acceptsFirstResponder; - (void)handleMouseEvent:(NSEvent *)theEvent; - (void)mouseDown:(NSEvent *)theEvent; @@ -74,6 +75,12 @@ - (void)otherMouseDragged:(NSEvent *)theEvent; - (void)otherMouseUp:(NSEvent *)theEvent; +- (int) convertKeyCode : (QChar)keyCode; +- (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags; +- (void)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType; +- (void)keyDown:(NSEvent *)theEvent; +- (void)keyUp:(NSEvent *)theEvent; + @end #endif //QNSVIEW_H diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 037cbdb5d6..5d7fd05b1f 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -52,16 +52,16 @@ self = [super init]; if (self) { m_cgImage = 0; - m_widget = 0; + m_window = 0; m_buttons = Qt::NoButton; } return self; } -- (id)initWithWidget:(QWidget *)widget { +- (id)initWithQWindow:(QWindow *)widget { self = [self init]; if (self) { - m_widget = widget; + m_window = widget; } return self; } @@ -130,48 +130,55 @@ return YES; } +- (BOOL)acceptsFirstResponder +{ + return YES; +} + - (void)handleMouseEvent:(NSEvent *)theEvent; { - NSPoint point = [self convertPoint: [theEvent locationInWindow] fromView: nil]; - QPoint qt_localPoint(point.x,point.y); + NSPoint windowPoint = [self convertPoint: [theEvent locationInWindow] fromView: nil]; + QPoint qt_windowPoint(windowPoint.x, windowPoint.y); NSTimeInterval timestamp = [theEvent timestamp]; ulong qt_timestamp = timestamp * 1000; - QWindowSystemInterface::handleMouseEvent(m_widget,qt_timestamp,qt_localPoint,QPoint(),m_buttons); + // ### Should the points be windowPoint and screenPoint? + QWindowSystemInterface::handleMouseEvent(m_window, qt_timestamp, qt_windowPoint, qt_windowPoint, m_buttons); +} +- (void)mouseDown:(NSEvent *)theEvent +{ + m_buttons |= Qt::LeftButton; + [self handleMouseEvent:theEvent]; +} + +- (void)mouseDragged:(NSEvent *)theEvent +{ + if (!(m_buttons & Qt::LeftButton)) + qWarning("Internal Mousebutton tracking invalid(missing Qt::LeftButton"); + [self handleMouseEvent:theEvent]; +} + +- (void)mouseUp:(NSEvent *)theEvent +{ + m_buttons &= QFlag(~int(Qt::LeftButton)); + [self handleMouseEvent:theEvent]; } - - (void)mouseDown:(NSEvent *)theEvent - { - m_buttons |= Qt::LeftButton; - [self handleMouseEvent:theEvent]; - } - - (void)mouseDragged:(NSEvent *)theEvent - { - if (!(m_buttons & Qt::LeftButton)) - qWarning("Internal Mousebutton tracking invalid(missing Qt::LeftButton"); - [self handleMouseEvent:theEvent]; - } - - (void)mouseUp:(NSEvent *)theEvent - { - m_buttons &= QFlag(~int(Qt::LeftButton)); - [self handleMouseEvent:theEvent]; - } - (void)mouseMoved:(NSEvent *)theEvent { - qDebug() << "mouseMove"; [self handleMouseEvent:theEvent]; } - (void)mouseEntered:(NSEvent *)theEvent { Q_UNUSED(theEvent); - QWindowSystemInterface::handleEnterEvent(m_widget); + QWindowSystemInterface::handleEnterEvent(m_window); } - (void)mouseExited:(NSEvent *)theEvent { Q_UNUSED(theEvent); - QWindowSystemInterface::handleLeaveEvent(m_widget); + QWindowSystemInterface::handleLeaveEvent(m_window); } - (void)rightMouseDown:(NSEvent *)theEvent { @@ -206,6 +213,84 @@ [self handleMouseEvent:theEvent]; } +- (int) convertKeyCode : (QChar)keyChar +{ + if (keyChar.isLower()) + keyChar = keyChar.toUpper(); + int keyCode = keyChar.unicode(); + + int qtKeyCode = Qt::Key(keyCode); // default case, overrides below + switch (keyCode) { + case NSEnterCharacter: qtKeyCode = Qt::Key_Enter; break; + case NSBackspaceCharacter: qtKeyCode = Qt::Key_Backspace; break; + case NSTabCharacter: qtKeyCode = Qt::Key_Tab; break; + case NSNewlineCharacter: qtKeyCode = Qt::Key_Return; break; + case NSCarriageReturnCharacter: qtKeyCode = Qt::Key_Return; break; + case NSBackTabCharacter: qtKeyCode = Qt::Key_Backtab; break; + case 27 : qtKeyCode = Qt::Key_Escape; break; + case NSDeleteCharacter : qtKeyCode = Qt::Key_Backspace; break; // Cocoa sends us delete when pressing backspace. + case NSUpArrowFunctionKey: qtKeyCode = Qt::Key_Up; break; + case NSDownArrowFunctionKey: qtKeyCode = Qt::Key_Down; break; + case NSLeftArrowFunctionKey: qtKeyCode = Qt::Key_Left; break; + case NSRightArrowFunctionKey: qtKeyCode = Qt::Key_Right; break; + case NSInsertFunctionKey: qtKeyCode = Qt::Key_Insert; break; + case NSDeleteFunctionKey: qtKeyCode = Qt::Key_Delete; break; + case NSHomeFunctionKey: qtKeyCode = Qt::Key_Home; break; + case NSEndFunctionKey: qtKeyCode = Qt::Key_End; break; + case NSPageUpFunctionKey: qtKeyCode = Qt::Key_PageUp; break; + case NSPageDownFunctionKey: qtKeyCode = Qt::Key_PageDown; break; + case NSPrintScreenFunctionKey: qtKeyCode = Qt::Key_Print; break; + case NSScrollLockFunctionKey: qtKeyCode = Qt::Key_ScrollLock; break; + case NSPauseFunctionKey: qtKeyCode = Qt::Key_Pause; break; + case NSSysReqFunctionKey: qtKeyCode = Qt::Key_SysReq; break; + case NSMenuFunctionKey: qtKeyCode = Qt::Key_Menu; break; + case NSHelpFunctionKey: qtKeyCode = Qt::Key_Help; break; + default : break; + } + + // handle all function keys (F1-F35) + if (keyCode >= NSF1FunctionKey && keyCode <= NSF35FunctionKey) + qtKeyCode = Qt::Key_F1 + (keyCode - NSF1FunctionKey); + return qtKeyCode; +} + +- (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags +{ + Qt::KeyboardModifiers qtMods =Qt::NoModifier; + if (modifierFlags & NSShiftKeyMask) + qtMods |= Qt::ShiftModifier; + if (modifierFlags & NSControlKeyMask) + qtMods |= Qt::MetaModifier; + if (modifierFlags & NSAlternateKeyMask) + qtMods |= Qt::AltModifier; + if (modifierFlags & NSCommandKeyMask) + qtMods |= Qt::ControlModifier; + if (modifierFlags & NSNumericPadKeyMask) + qtMods |= Qt::KeypadModifier; + return qtMods; +} + +- (void)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType +{ + NSTimeInterval timestamp = [theEvent timestamp]; + ulong qt_timestamp = timestamp * 1000; + QString characters = QString::fromUtf8([[theEvent characters] UTF8String]); + Qt::KeyboardModifiers modifiers = [self convertKeyModifiers : [theEvent modifierFlags]]; + QChar ch([[theEvent charactersIgnoringModifiers] characterAtIndex:0]); + int keyCode = [self convertKeyCode : ch]; + + QWindowSystemInterface::handleKeyEvent(m_window, qt_timestamp, QEvent::Type(eventType), keyCode, modifiers, characters); +} + +- (void)keyDown:(NSEvent *)theEvent +{ + [self handleKeyEvent : theEvent eventType :int(QEvent::KeyPress)]; +} + +- (void)keyUp:(NSEvent *)theEvent +{ + [self handleKeyEvent : theEvent eventType :int(QEvent::KeyRelease)]; +} @end diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.h b/src/plugins/platforms/cocoa/qnswindowdelegate.h index cf296c4a8b..5cd226a71d 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.h +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.h @@ -46,6 +46,26 @@ #include "qcocoawindow.h" +#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5 +@protocol NSWindowDelegate <NSObject> +//- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize; +//- (void)windowDidMiniaturize:(NSNotification*)notification; +- (void)windowDidResize:(NSNotification *)notification; +- (void)windowWillClose:(NSNotification *)notification; +//- (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)defaultFrame; +- (void)windowDidMove:(NSNotification *)notification; +//- (BOOL)windowShouldClose:(id)window; +//- (void)windowDidDeminiaturize:(NSNotification *)notification; +//- (void)windowDidBecomeMain:(NSNotification*)notification; +//- (void)windowDidResignMain:(NSNotification*)notification; +//- (void)windowDidBecomeKey:(NSNotification*)notification; +//- (void)windowDidResignKey:(NSNotification*)notification; +//- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu; +//- (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard; +//- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame; +@end +#endif + @interface QNSWindowDelegate : NSObject <NSWindowDelegate> { QCocoaWindow *m_cocoaWindow; @@ -54,6 +74,7 @@ - (id)initWithQCocoaWindow: (QCocoaWindow *) cocoaWindow; - (void)windowDidResize:(NSNotification *)notification; +- (void)windowDidMove:(NSNotification *)notification; - (void)windowWillClose:(NSNotification *)notification; @end diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index 887b08f6d2..6521db5cf7 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm @@ -64,10 +64,18 @@ } } +- (void)windowDidMove:(NSNotification *)notification +{ + Q_UNUSED(notification); + if (m_cocoaWindow) { + m_cocoaWindow->windowDidMove(); + } +} + - (void)windowWillClose:(NSNotification *)notification { Q_UNUSED(notification); - QWindowSystemInterface::handleCloseEvent(m_cocoaWindow->widget()); + QWindowSystemInterface::handleCloseEvent(m_cocoaWindow->window()); } @end diff --git a/src/plugins/platforms/eglconvenience/eglconvenience.pri b/src/plugins/platforms/eglconvenience/eglconvenience.pri deleted file mode 100644 index 322d4e4633..0000000000 --- a/src/plugins/platforms/eglconvenience/eglconvenience.pri +++ /dev/null @@ -1,7 +0,0 @@ -INCLUDEPATH += $$PWD - -SOURCES += \ - $$PWD/qeglconvenience.cpp - -HEADERS += \ - $$PWD/qeglconvenience.h diff --git a/src/plugins/platforms/eglconvenience/qeglconvenience.cpp b/src/plugins/platforms/eglconvenience/qeglconvenience.cpp deleted file mode 100644 index 69747a87e8..0000000000 --- a/src/plugins/platforms/eglconvenience/qeglconvenience.cpp +++ /dev/null @@ -1,324 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qeglconvenience.h" - -QT_BEGIN_NAMESPACE - -QVector<EGLint> q_createConfigAttributesFromFormat(const QPlatformWindowFormat &format) -{ - int redSize = format.redBufferSize(); - int greenSize = format.greenBufferSize(); - int blueSize = format.blueBufferSize(); - int alphaSize = format.alphaBufferSize(); - int depthSize = format.depthBufferSize(); - int stencilSize = format.stencilBufferSize(); - int sampleCount = format.samples(); - - // QPlatformWindowFormat uses a magic value of -1 to indicate "don't care", even when a buffer of that - // type has been requested. So we must check QPlatformWindowFormat's booleans too if size is -1: - if (format.alpha() && alphaSize <= 0) - alphaSize = 1; - if (format.depth() && depthSize <= 0) - depthSize = 1; - if (format.stencil() && stencilSize <= 0) - stencilSize = 1; - if (format.sampleBuffers() && sampleCount <= 0) - sampleCount = 1; - - // We want to make sure 16-bit configs are chosen over 32-bit configs as they will provide - // the best performance. The EGL config selection algorithm is a bit stange in this regard: - // The selection criteria for EGL_BUFFER_SIZE is "AtLeast", so we can't use it to discard - // 32-bit configs completely from the selection. So it then comes to the sorting algorithm. - // The red/green/blue sizes have a sort priority of 3, so they are sorted by first. The sort - // order is special and described as "by larger _total_ number of color bits.". So EGL will - // put 32-bit configs in the list before the 16-bit configs. However, the spec also goes on - // to say "If the requested number of bits in attrib_list for a particular component is 0, - // then the number of bits for that component is not considered". This part of the spec also - // seems to imply that setting the red/green/blue bits to zero means none of the components - // are considered and EGL disregards the entire sorting rule. It then looks to the next - // highest priority rule, which is EGL_BUFFER_SIZE. Despite the selection criteria being - // "AtLeast" for EGL_BUFFER_SIZE, it's sort order is "smaller" meaning 16-bit configs are - // put in the list before 32-bit configs. So, to make sure 16-bit is preffered over 32-bit, - // we must set the red/green/blue sizes to zero. This has an unfortunate consequence that - // if the application sets the red/green/blue size to 5/6/5 on the QPlatformWindowFormat, - // they will probably get a 32-bit config, even when there's an RGB565 config available. - - // Now normalize the values so -1 becomes 0 - redSize = redSize > 0 ? redSize : 0; - greenSize = greenSize > 0 ? greenSize : 0; - blueSize = blueSize > 0 ? blueSize : 0; - alphaSize = alphaSize > 0 ? alphaSize : 0; - depthSize = depthSize > 0 ? depthSize : 0; - stencilSize = stencilSize > 0 ? stencilSize : 0; - sampleCount = sampleCount > 0 ? sampleCount : 0; - - QVector<EGLint> configAttributes; - - configAttributes.append(EGL_RED_SIZE); - configAttributes.append(redSize); - - configAttributes.append(EGL_GREEN_SIZE); - configAttributes.append(greenSize); - - configAttributes.append(EGL_BLUE_SIZE); - configAttributes.append(blueSize); - - configAttributes.append(EGL_ALPHA_SIZE); - configAttributes.append(alphaSize); - - configAttributes.append(EGL_DEPTH_SIZE); - configAttributes.append(depthSize); - - configAttributes.append(EGL_STENCIL_SIZE); - configAttributes.append(stencilSize); - - configAttributes.append(EGL_SAMPLES); - configAttributes.append(sampleCount); - - configAttributes.append(EGL_SAMPLE_BUFFERS); - configAttributes.append(sampleCount? 1:0); - - return configAttributes; -} - -bool q_reduceConfigAttributes(QVector<EGLint> *configAttributes) -{ - int i = -1; - // Reduce the complexity of a configuration request to ask for less - // because the previous request did not result in success. Returns - // true if the complexity was reduced, or false if no further - // reductions in complexity are possible. - - i = configAttributes->indexOf(EGL_SWAP_BEHAVIOR); - if (i >= 0) { - configAttributes->remove(i,2); - } - -#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT - // For OpenVG, we sometimes try to create a surface using a pre-multiplied format. If we can't - // find a config which supports pre-multiplied formats, remove the flag on the surface type: - - i = configAttributes->indexOf(EGL_SURFACE_TYPE); - if (i >= 0) { - EGLint surfaceType = configAttributes->at(i +1); - if (surfaceType & EGL_VG_ALPHA_FORMAT_PRE_BIT) { - surfaceType ^= EGL_VG_ALPHA_FORMAT_PRE_BIT; - configAttributes->replace(i+1,surfaceType); - return true; - } - } -#endif - - // EGL chooses configs with the highest color depth over - // those with smaller (but faster) lower color depths. One - // way around this is to set EGL_BUFFER_SIZE to 16, which - // trumps the others. Of course, there may not be a 16-bit - // config available, so it's the first restraint we remove. - i = configAttributes->indexOf(EGL_BUFFER_SIZE); - if (i >= 0) { - if (configAttributes->at(i+1) == 16) { - configAttributes->remove(i,2); - return true; - } - } - - i = configAttributes->indexOf(EGL_SAMPLE_BUFFERS); - if (i >= 0) { - configAttributes->remove(i,2); - i = configAttributes->indexOf(EGL_SAMPLES); - if (i >= 0) { - configAttributes->remove(i,2); - } - return true; - } - - i = configAttributes->indexOf(EGL_ALPHA_SIZE); - if (i >= 0) { - configAttributes->remove(i,2); -#if defined(EGL_BIND_TO_TEXTURE_RGBA) && defined(EGL_BIND_TO_TEXTURE_RGB) - i = configAttributes->indexOf(EGL_BIND_TO_TEXTURE_RGBA); - if (i >= 0) { - configAttributes->replace(i,EGL_BIND_TO_TEXTURE_RGB); - configAttributes->replace(i+1,TRUE); - - } -#endif - return true; - } - - i = configAttributes->indexOf(EGL_STENCIL_SIZE); - if (i >= 0) { - configAttributes->remove(i,2); - return true; - } - i = configAttributes->indexOf(EGL_DEPTH_SIZE); - if (i >= 0) { - configAttributes->remove(i,2); - return true; - } -#ifdef EGL_BIND_TO_TEXTURE_RGB - i = configAttributes->indexOf(EGL_BIND_TO_TEXTURE_RGB); - if (i >= 0) { - configAttributes->remove(i,2); - return true; - } -#endif - - return false; -} - -EGLConfig q_configFromQPlatformWindowFormat(EGLDisplay display, const QPlatformWindowFormat &format, bool highestPixelFormat, int surfaceType) -{ - EGLConfig cfg = 0; - QVector<EGLint> configureAttributes = q_createConfigAttributesFromFormat(format); - configureAttributes.append(EGL_SURFACE_TYPE); //we only support eglconfigs for windows for now - configureAttributes.append(surfaceType); - - configureAttributes.append(EGL_RENDERABLE_TYPE); - if (format.windowApi() == QPlatformWindowFormat::OpenVG) { - configureAttributes.append(EGL_OPENVG_BIT); - } else { - configureAttributes.append(EGL_OPENGL_ES2_BIT); - } - configureAttributes.append(EGL_NONE); - - do { - // Get the number of matching configurations for this set of properties. - EGLint matching = 0; - if (!eglChooseConfig(display, configureAttributes.constData(), 0, 0, &matching) || !matching) - continue; - - // If we want the best pixel format, then return the first - // matching configuration. - if (highestPixelFormat) { - eglChooseConfig(display, configureAttributes.constData(), &cfg, 1, &matching); - if (matching < 1) - continue; - return cfg; - } - - // Fetch all of the matching configurations and find the - // first that matches the pixel format we wanted. - int i = configureAttributes.indexOf(EGL_RED_SIZE); - int confAttrRed = configureAttributes.at(i+1); - i = configureAttributes.indexOf(EGL_GREEN_SIZE); - int confAttrGreen = configureAttributes.at(i+1); - i = configureAttributes.indexOf(EGL_BLUE_SIZE); - int confAttrBlue = configureAttributes.at(i+1); - i = configureAttributes.indexOf(EGL_ALPHA_SIZE); - int confAttrAlpha = configureAttributes.at(i+1); - - EGLint size = matching; - EGLConfig *configs = new EGLConfig [size]; - eglChooseConfig(display, configureAttributes.constData(), configs, size, &matching); - for (EGLint index = 0; index < size; ++index) { - EGLint red, green, blue, alpha; - eglGetConfigAttrib(display, configs[index], EGL_RED_SIZE, &red); - eglGetConfigAttrib(display, configs[index], EGL_GREEN_SIZE, &green); - eglGetConfigAttrib(display, configs[index], EGL_BLUE_SIZE, &blue); - eglGetConfigAttrib(display, configs[index], EGL_ALPHA_SIZE, &alpha); - if (red == confAttrRed && - green == confAttrGreen && - blue == confAttrBlue && - (confAttrAlpha == 0 || - alpha == confAttrAlpha)) { - cfg = configs[index]; - delete [] configs; - return cfg; - } - } - delete [] configs; - } while (q_reduceConfigAttributes(&configureAttributes)); - qWarning("Cant find EGLConfig, returning null config"); - return 0; -} - -QPlatformWindowFormat qt_qPlatformWindowFormatFromConfig(EGLDisplay display, const EGLConfig config) -{ - QPlatformWindowFormat format; - EGLint redSize = 0; - EGLint greenSize = 0; - EGLint blueSize = 0; - EGLint alphaSize = 0; - EGLint depthSize = 0; - EGLint stencilSize = 0; - EGLint sampleCount = 0; - EGLint level = 0; - - eglGetConfigAttrib(display, config, EGL_RED_SIZE, &redSize); - eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &greenSize); - eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &blueSize); - eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &alphaSize); - eglGetConfigAttrib(display, config, EGL_DEPTH_SIZE, &depthSize); - eglGetConfigAttrib(display, config, EGL_STENCIL_SIZE, &stencilSize); - eglGetConfigAttrib(display, config, EGL_SAMPLES, &sampleCount); - eglGetConfigAttrib(display, config, EGL_LEVEL, &level); - - format.setRedBufferSize(redSize); - format.setGreenBufferSize(greenSize); - format.setBlueBufferSize(blueSize); - format.setAlphaBufferSize(alphaSize); - format.setDepthBufferSize(depthSize); - format.setStencilBufferSize(stencilSize); - format.setSamples(sampleCount); - format.setDirectRendering(true); // All EGL contexts are direct-rendered - format.setRgba(true); // EGL doesn't support colour index rendering - format.setStereo(false); // EGL doesn't support stereo buffers - format.setAccumBufferSize(0); // EGL doesn't support accululation buffers - - // Clear the EGL error state because some of the above may - // have errored out because the attribute is not applicable - // to the surface type. Such errors don't matter. - eglGetError(); - - return format; -} - -bool q_hasEglExtension(EGLDisplay display, const char* extensionName) -{ - QList<QByteArray> extensions = - QByteArray(reinterpret_cast<const char *> - (eglQueryString(display, EGL_EXTENSIONS))).split(' '); - return extensions.contains(extensionName); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglconvenience/qeglplatformcontext.cpp b/src/plugins/platforms/eglconvenience/qeglplatformcontext.cpp deleted file mode 100644 index 4d1d63e37f..0000000000 --- a/src/plugins/platforms/eglconvenience/qeglplatformcontext.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qeglplatformcontext.h" - - -#include <QtGui/QPlatformWindow> - -#include "qeglconvenience.h" - -#include <EGL/egl.h> - -QEGLPlatformContext::QEGLPlatformContext(EGLDisplay display, EGLConfig config, EGLint contextAttrs[], EGLSurface surface, EGLenum eglApi) - : QPlatformGLContext() - , m_eglDisplay(display) - , m_eglSurface(surface) - , m_eglApi(eglApi) -{ - if (m_eglSurface == EGL_NO_SURFACE) { - qWarning("Createing QEGLPlatformContext with no surface"); - } - - eglBindAPI(m_eglApi); - m_eglContext = eglCreateContext(m_eglDisplay,config, 0,contextAttrs); - if (m_eglContext == EGL_NO_CONTEXT) { - qWarning("Could not create the egl context\n"); - eglTerminate(m_eglDisplay); - qFatal("EGL error"); - } - - m_windowFormat = qt_qPlatformWindowFormatFromConfig(display,config); -} - -QEGLPlatformContext::~QEGLPlatformContext() -{ -#ifdef QEGL_EXTRA_DEBUG - qWarning("QEglContext::~QEglContext(): %p\n",this); -#endif - if (m_eglSurface != EGL_NO_SURFACE) { - doneCurrent(); - eglDestroySurface(m_eglDisplay, m_eglSurface); - m_eglSurface = EGL_NO_SURFACE; - } - - if (m_eglContext != EGL_NO_CONTEXT) { - eglDestroyContext(m_eglDisplay, m_eglContext); - m_eglContext = EGL_NO_CONTEXT; - } -} - -void QEGLPlatformContext::makeCurrent() -{ - QPlatformGLContext::makeCurrent(); -#ifdef QEGL_EXTRA_DEBUG - qWarning("QEglContext::makeCurrent: %p\n",this); -#endif - eglBindAPI(m_eglApi); - bool ok = eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext); - if (!ok) - qWarning("QEGLPlatformContext::makeCurrent: eglError: %d, this: %p \n", eglGetError(), this); -#ifdef QEGL_EXTRA_DEBUG - static bool showDebug = true; - if (showDebug) { - showDebug = false; - const char *str = (const char*)glGetString(GL_VENDOR); - qWarning("Vendor %s\n", str); - str = (const char*)glGetString(GL_RENDERER); - qWarning("Renderer %s\n", str); - str = (const char*)glGetString(GL_VERSION); - qWarning("Version %s\n", str); - - str = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION); - qWarning("Extensions %s\n",str); - - str = (const char*)glGetString(GL_EXTENSIONS); - qWarning("Extensions %s\n", str); - - } -#endif -} -void QEGLPlatformContext::doneCurrent() -{ - QPlatformGLContext::doneCurrent(); -#ifdef QEGL_EXTRA_DEBUG - qWarning("QEglContext::doneCurrent:%p\n",this); -#endif - eglBindAPI(m_eglApi); - bool ok = eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (!ok) - qWarning("QEGLPlatformContext::doneCurrent(): eglError: %d, this: %p \n", eglGetError(), this); -} -void QEGLPlatformContext::swapBuffers() -{ -#ifdef QEGL_EXTRA_DEBUG - qWarning("QEglContext::swapBuffers:%p\n",this); -#endif - eglBindAPI(m_eglApi); - bool ok = eglSwapBuffers(m_eglDisplay, m_eglSurface); - if (!ok) - qWarning("QEGLPlatformContext::swapBuffers(): eglError: %d, this: %p \n", eglGetError(), this); -} -void* QEGLPlatformContext::getProcAddress(const QString& procName) -{ -#ifdef QEGL_EXTRA_DEBUG - qWarning("QEglContext::getProcAddress%p\n",this); -#endif - eglBindAPI(m_eglApi); - return (void *)eglGetProcAddress(qPrintable(procName)); -} - -QPlatformWindowFormat QEGLPlatformContext::platformWindowFormat() const -{ - return m_windowFormat; -} - -EGLContext QEGLPlatformContext::eglContext() const -{ - return m_eglContext; -} diff --git a/src/plugins/platforms/eglconvenience/qeglplatformcontext.h b/src/plugins/platforms/eglconvenience/qeglplatformcontext.h deleted file mode 100644 index 9be1480735..0000000000 --- a/src/plugins/platforms/eglconvenience/qeglplatformcontext.h +++ /dev/null @@ -1,71 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QOPENKODEGLINTEGRATION_H -#define QOPENKODEGLINTEGRATION_H - -#include <QtGui/QPlatformGLContext> -#include <EGL/egl.h> - -class QEGLPlatformContext : public QPlatformGLContext -{ -public: - QEGLPlatformContext(EGLDisplay display, EGLConfig config, EGLint contextAttrs[], EGLSurface surface, EGLenum eglApi); - ~QEGLPlatformContext(); - - void makeCurrent(); - void doneCurrent(); - void swapBuffers(); - void* getProcAddress(const QString& procName); - - QPlatformWindowFormat platformWindowFormat() const; - - EGLContext eglContext() const; -private: - EGLContext m_eglContext; - EGLDisplay m_eglDisplay; - EGLSurface m_eglSurface; - EGLenum m_eglApi; - - QPlatformWindowFormat m_windowFormat; -}; - -#endif //QOPENKODEGLINTEGRATION_H diff --git a/src/plugins/platforms/eglconvenience/qxlibeglintegration.cpp b/src/plugins/platforms/eglconvenience/qxlibeglintegration.cpp deleted file mode 100644 index cbd8f7d7c6..0000000000 --- a/src/plugins/platforms/eglconvenience/qxlibeglintegration.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qxlibeglintegration.h" - -static int countBits(unsigned long mask) -{ - int count = 0; - while (mask != 0) { - if (mask & 1) - ++count; - mask >>= 1; - } - return count; -} - -VisualID QXlibEglIntegration::getCompatibleVisualId(Display *display, EGLDisplay eglDisplay, EGLConfig config) -{ - VisualID visualId = 0; - EGLint eglValue = 0; - - EGLint configRedSize = 0; - eglGetConfigAttrib(eglDisplay, config, EGL_RED_SIZE, &configRedSize); - - EGLint configGreenSize = 0; - eglGetConfigAttrib(eglDisplay, config, EGL_GREEN_SIZE, &configGreenSize); - - EGLint configBlueSize = 0; - eglGetConfigAttrib(eglDisplay, config, EGL_BLUE_SIZE, &configBlueSize); - - EGLint configAlphaSize = 0; - eglGetConfigAttrib(eglDisplay, config, EGL_ALPHA_SIZE, &configAlphaSize); - - eglGetConfigAttrib(eglDisplay, config, EGL_CONFIG_ID, &eglValue); - int configId = eglValue; - - // See if EGL provided a valid VisualID: - eglGetConfigAttrib(eglDisplay, config, EGL_NATIVE_VISUAL_ID, &eglValue); - visualId = (VisualID)eglValue; - if (visualId) { - // EGL has suggested a visual id, so get the rest of the visual info for that id: - XVisualInfo visualInfoTemplate; - memset(&visualInfoTemplate, 0, sizeof(XVisualInfo)); - visualInfoTemplate.visualid = visualId; - - XVisualInfo *chosenVisualInfo; - int matchingCount = 0; - chosenVisualInfo = XGetVisualInfo(display, VisualIDMask, &visualInfoTemplate, &matchingCount); - if (chosenVisualInfo) { - // Skip size checks if implementation supports non-matching visual - // and config (http://bugreports.qt.nokia.com/browse/QTBUG-9444). - if (q_hasEglExtension(eglDisplay,"EGL_NV_post_convert_rounding")) { - XFree(chosenVisualInfo); - return visualId; - } - - int visualRedSize = countBits(chosenVisualInfo->red_mask); - int visualGreenSize = countBits(chosenVisualInfo->green_mask); - int visualBlueSize = countBits(chosenVisualInfo->blue_mask); - int visualAlphaSize = -1; // Need XRender to tell us the alpha channel size - - bool visualMatchesConfig = false; - if ( visualRedSize == configRedSize && - visualGreenSize == configGreenSize && - visualBlueSize == configBlueSize ) - { - // We need XRender to check the alpha channel size of the visual. If we don't have - // the alpha size, we don't check it against the EGL config's alpha size. - if (visualAlphaSize >= 0) - visualMatchesConfig = visualAlphaSize == configAlphaSize; - else - visualMatchesConfig = true; - } - - if (!visualMatchesConfig) { - if (visualAlphaSize >= 0) { - qWarning("Warning: EGL suggested using X Visual ID %d (ARGB%d%d%d%d) for EGL config %d (ARGB%d%d%d%d), but this is incompatable", - (int)visualId, visualAlphaSize, visualRedSize, visualGreenSize, visualBlueSize, - configId, configAlphaSize, configRedSize, configGreenSize, configBlueSize); - } else { - qWarning("Warning: EGL suggested using X Visual ID %d (RGB%d%d%d) for EGL config %d (RGB%d%d%d), but this is incompatable", - (int)visualId, visualRedSize, visualGreenSize, visualBlueSize, - configId, configRedSize, configGreenSize, configBlueSize); - } - visualId = 0; - } - } else { - qWarning("Warning: EGL suggested using X Visual ID %d for EGL config %d, but that isn't a valid ID", - (int)visualId, configId); - visualId = 0; - } - XFree(chosenVisualInfo); - } -#ifdef QT_DEBUG_X11_VISUAL_SELECTION - else - qDebug("EGL did not suggest a VisualID (EGL_NATIVE_VISUAL_ID was zero) for EGLConfig %d", configId); -#endif - - if (visualId) { -#ifdef QT_DEBUG_X11_VISUAL_SELECTION - if (configAlphaSize > 0) - qDebug("Using ARGB Visual ID %d provided by EGL for config %d", (int)visualId, configId); - else - qDebug("Using Opaque Visual ID %d provided by EGL for config %d", (int)visualId, configId); -#endif - return visualId; - } - - // Finally, try to - // use XGetVisualInfo and only use the bit depths to match on: - if (!visualId) { - XVisualInfo visualInfoTemplate; - memset(&visualInfoTemplate, 0, sizeof(XVisualInfo)); - XVisualInfo *matchingVisuals; - int matchingCount = 0; - - visualInfoTemplate.depth = configRedSize + configGreenSize + configBlueSize + configAlphaSize; - matchingVisuals = XGetVisualInfo(display, - VisualDepthMask, - &visualInfoTemplate, - &matchingCount); - if (!matchingVisuals) { - // Try again without taking the alpha channel into account: - visualInfoTemplate.depth = configRedSize + configGreenSize + configBlueSize; - matchingVisuals = XGetVisualInfo(display, - VisualDepthMask, - &visualInfoTemplate, - &matchingCount); - } - - if (matchingVisuals) { - visualId = matchingVisuals[0].visualid; - XFree(matchingVisuals); - } - } - - if (visualId) { -#ifdef QT_DEBUG_X11_VISUAL_SELECTION - qDebug("Using Visual ID %d provided by XGetVisualInfo for EGL config %d", (int)visualId, configId); -#endif - return visualId; - } - - qWarning("Unable to find an X11 visual which matches EGL config %d", configId); - return (VisualID)0; -} diff --git a/src/plugins/platforms/eglconvenience/xlibeglintegration.pri b/src/plugins/platforms/eglconvenience/xlibeglintegration.pri deleted file mode 100644 index 9404a70373..0000000000 --- a/src/plugins/platforms/eglconvenience/xlibeglintegration.pri +++ /dev/null @@ -1,7 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/qxlibeglintegration.h - -SOURCES += \ - $$PWD/qxlibeglintegration.cpp diff --git a/src/plugins/platforms/eglfs/eglfs.pro b/src/plugins/platforms/eglfs/eglfs.pro index 471cf63dd8..bcf5c6153a 100644 --- a/src/plugins/platforms/eglfs/eglfs.pro +++ b/src/plugins/platforms/eglfs/eglfs.pro @@ -25,7 +25,7 @@ HEADERS = qeglfsintegration.h \ qeglfswindowsurface.h \ qeglfsscreen.h -include(../fontdatabases/genericunix/genericunix.pri) +load(qpa/fontdatabases/genericunix) target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target diff --git a/src/plugins/platforms/eglfs/qeglfswindow.h b/src/plugins/platforms/eglfs/qeglfswindow.h index 95a9ff51b9..4e9a728772 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.h +++ b/src/plugins/platforms/eglfs/qeglfswindow.h @@ -46,7 +46,7 @@ #include "qeglfsscreen.h" #include <QPlatformWindow> -#include <QtGui/QWidget> +#include <QtWidgets/QWidget> QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/externalplugin.pri b/src/plugins/platforms/externalplugin.pri deleted file mode 100644 index 9b00acb4e9..0000000000 --- a/src/plugins/platforms/externalplugin.pri +++ /dev/null @@ -1,29 +0,0 @@ -# -# Lighthouse now has preliminarily support for building and -# loading platform plugins from outside the Qt source/build -# tree. -# -# 1) Building external plugins: -# Set QTDIR to the Qt build directory, copy this file to -# the plugin source repository and include it at the top -# of the plugin's pro file. Use QT_SOURCE_TREE if you -# want to pull in source code from Qt: -# -# include($$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/genericunix/genericunix.pri) -# -# 2) Loading external plugins: -# Specify the path to the directory containing the -# plugin on the command line, in addition to the -# platform name. -# -# ./wiggly -platformPluginPath /path/to/myPlugin -platform gullfaksA -# - -!exists($$(QTDIR)/.qmake.cache) { - error("Please set QTDIR to the Qt build directory") -} - -QT_SOURCE_TREE = $$fromfile($$(QTDIR)/.qmake.cache,QT_SOURCE_TREE) -QT_BUILD_TREE = $$fromfile($$(QTDIR)/.qmake.cache,QT_BUILD_TREE) - -load(qt_plugin) diff --git a/src/plugins/platforms/fb_base/fb_base.cpp b/src/plugins/platforms/fb_base/fb_base.cpp deleted file mode 100644 index a83d739083..0000000000 --- a/src/plugins/platforms/fb_base/fb_base.cpp +++ /dev/null @@ -1,507 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "fb_base.h" -#include <qpainter.h> -#include <qdebug.h> -#include <qbitmap.h> -#include <QPlatformCursor> -#include <QWindowSystemInterface> - -QPlatformSoftwareCursor::QPlatformSoftwareCursor(QPlatformScreen *scr) - : QPlatformCursor(scr), currentRect(QRect()), prevRect(QRect()) -{ - graphic = new QPlatformCursorImage(0, 0, 0, 0, 0, 0); - setCursor(Qt::ArrowCursor); -} - -QRect QPlatformSoftwareCursor::getCurrentRect() -{ - QRect rect = graphic->image()->rect().translated(-graphic->hotspot().x(), - -graphic->hotspot().y()); - rect.translate(QCursor::pos()); - QPoint screenOffset = screen->geometry().topLeft(); - rect.translate(-screenOffset); // global to local translation - return rect; -} - - -void QPlatformSoftwareCursor::pointerEvent(const QMouseEvent & e) -{ - Q_UNUSED(e); - QPoint screenOffset = screen->geometry().topLeft(); - currentRect = getCurrentRect(); - // global to local translation - if (onScreen || screen->geometry().intersects(currentRect.translated(screenOffset))) { - setDirty(); - } -} - -QRect QPlatformSoftwareCursor::drawCursor(QPainter & painter) -{ - dirty = false; - if (currentRect.isNull()) - return QRect(); - - // We need this because the cursor might be dirty due to moving off screen - QPoint screenOffset = screen->geometry().topLeft(); - // global to local translation - if (!currentRect.translated(screenOffset).intersects(screen->geometry())) - return QRect(); - - prevRect = currentRect; - painter.drawImage(prevRect, *graphic->image()); - onScreen = true; - return prevRect; -} - -QRect QPlatformSoftwareCursor::dirtyRect() -{ - if (onScreen) { - onScreen = false; - return prevRect; - } - return QRect(); -} - -void QPlatformSoftwareCursor::setCursor(Qt::CursorShape shape) -{ - graphic->set(shape); -} - -void QPlatformSoftwareCursor::setCursor(const QImage &image, int hotx, int hoty) -{ - graphic->set(image, hotx, hoty); -} - -void QPlatformSoftwareCursor::setCursor(const uchar *data, const uchar *mask, int width, int height, int hotX, int hotY) -{ - graphic->set(data, mask, width, height, hotX, hotY); -} - -void QPlatformSoftwareCursor::changeCursor(QCursor * widgetCursor, QWidget * widget) -{ - Q_UNUSED(widget); - Qt::CursorShape shape = widgetCursor->shape(); - - if (shape == Qt::BitmapCursor) { - // application supplied cursor - QPoint spot = widgetCursor->hotSpot(); - setCursor(widgetCursor->pixmap().toImage(), spot.x(), spot.y()); - } else { - // system cursor - setCursor(shape); - } - currentRect = getCurrentRect(); - QPoint screenOffset = screen->geometry().topLeft(); // global to local translation - if (onScreen || screen->geometry().intersects(currentRect.translated(screenOffset))) - setDirty(); -} - -QFbScreen::QFbScreen() : cursor(0), mGeometry(), mDepth(16), mFormat(QImage::Format_RGB16), mScreenImage(0), compositePainter(0), isUpToDate(false) -{ - mScreenImage = new QImage(mGeometry.size(), mFormat); - redrawTimer.setSingleShot(true); - redrawTimer.setInterval(0); - QObject::connect(&redrawTimer, SIGNAL(timeout()), this, SLOT(doRedraw())); -} - -void QFbScreen::setGeometry(QRect rect) -{ - delete mScreenImage; - mGeometry = rect; - mScreenImage = new QImage(mGeometry.size(), mFormat); - delete compositePainter; - compositePainter = 0; - invalidateRectCache(); -} - -void QFbScreen::setDepth(int depth) -{ - mDepth = depth; -} - -void QFbScreen::setPhysicalSize(QSize size) -{ - mPhysicalSize = size; -} - -void QFbScreen::setFormat(QImage::Format format) -{ - mFormat = format; - delete mScreenImage; - mScreenImage = new QImage(mGeometry.size(), mFormat); - delete compositePainter; - compositePainter = 0; -} - -QFbScreen::~QFbScreen() -{ - delete compositePainter; - delete mScreenImage; -} - -void QFbScreen::setDirty(const QRect &rect) -{ - QRect intersection = rect.intersected(mGeometry); - QPoint screenOffset = mGeometry.topLeft(); - repaintRegion += intersection.translated(-screenOffset); // global to local translation - if (!redrawTimer.isActive()) { - redrawTimer.start(); - } -} - -void QFbScreen::generateRects() -{ - cachedRects.clear(); - QPoint screenOffset = mGeometry.topLeft(); - QRegion remainingScreen(mGeometry.translated(-screenOffset)); // global to local translation - - for (int i = 0; i < windowStack.length(); i++) { - if (remainingScreen.isEmpty()) - break; - if (!windowStack[i]->visible()) - continue; - if (windowStack[i]->widget()->isMinimized()) - continue; - - if (!windowStack[i]->widget()->testAttribute(Qt::WA_TranslucentBackground)) { - QRect localGeometry = windowStack.at(i)->geometry().translated(-screenOffset); // global to local translation - remainingScreen -= localGeometry; - QRegion windowRegion(localGeometry); - windowRegion -= remainingScreen; - foreach(QRect rect, windowRegion.rects()) { - cachedRects += QPair<QRect, int>(rect, i); - } - } - } - foreach (QRect rect, remainingScreen.rects()) - cachedRects += QPair<QRect, int>(rect, -1); - isUpToDate = true; - return; -} - - - -QRegion QFbScreen::doRedraw() -{ - QPoint screenOffset = mGeometry.topLeft(); - - QRegion touchedRegion; - if (cursor && cursor->isDirty() && cursor->isOnScreen()) { - QRect lastCursor = cursor->dirtyRect(); - repaintRegion += lastCursor; - } - if (repaintRegion.isEmpty() && (!cursor || !cursor->isDirty())) { - return touchedRegion; - } - - QVector<QRect> rects = repaintRegion.rects(); - - if (!isUpToDate) - generateRects(); - - if (!compositePainter) - compositePainter = new QPainter(mScreenImage); - for (int rectIndex = 0; rectIndex < repaintRegion.numRects(); rectIndex++) { - QRegion rectRegion = rects[rectIndex]; - - for(int i = 0; i < cachedRects.length(); i++) { - QRect screenSubRect = cachedRects[i].first; - int layer = cachedRects[i].second; - QRegion intersect = rectRegion.intersected(screenSubRect); - - if (intersect.isEmpty()) - continue; - - rectRegion -= intersect; - - // we only expect one rectangle, but defensive coding... - foreach (QRect rect, intersect.rects()) { - bool firstLayer = true; - if (layer == -1) { - compositePainter->fillRect(rect, Qt::black); - firstLayer = false; - layer = windowStack.size() - 1; - } - - for (int layerIndex = layer; layerIndex != -1; layerIndex--) { - if (!windowStack[layerIndex]->visible()) - continue; - if (windowStack[layerIndex]->widget()->isMinimized()) - continue; - QRect windowRect = windowStack[layerIndex]->geometry().translated(-screenOffset); - QRect windowIntersect = rect.translated(-windowRect.left(), - -windowRect.top()); - compositePainter->drawImage(rect, windowStack[layerIndex]->surface->image(), - windowIntersect); - if (firstLayer) { - firstLayer = false; - } - } - } - } - } - - QRect cursorRect; - if (cursor && (cursor->isDirty() || repaintRegion.intersects(cursor->lastPainted()))) { - cursorRect = cursor->drawCursor(*compositePainter); - touchedRegion += cursorRect; - } - touchedRegion += repaintRegion; - repaintRegion = QRegion(); - - - -// qDebug() << "QFbScreen::doRedraw" << windowStack.size() << mScreenImage->size() << touchedRegion; - - - return touchedRegion; -} - -void QFbScreen::addWindow(QFbWindow *surface) -{ - windowStack.prepend(surface); - surface->mScreens.append(this); - invalidateRectCache(); - setDirty(surface->geometry()); -} - -void QFbScreen::removeWindow(QFbWindow * surface) -{ - windowStack.removeOne(surface); - surface->mScreens.removeOne(this); - invalidateRectCache(); - setDirty(surface->geometry()); -} - -void QFbWindow::raise() -{ - QList<QFbScreen *>::const_iterator i = mScreens.constBegin(); - QList<QFbScreen *>::const_iterator end = mScreens.constEnd(); - while (i != end) { - (*i)->raise(this); - ++i; - } -} - -void QFbScreen::raise(QPlatformWindow * surface) -{ - QFbWindow *s = static_cast<QFbWindow *>(surface); - int index = windowStack.indexOf(s); - if (index <= 0) - return; - windowStack.move(index, 0); - invalidateRectCache(); - setDirty(s->geometry()); -} - -void QFbWindow::lower() -{ - QList<QFbScreen *>::const_iterator i = mScreens.constBegin(); - QList<QFbScreen *>::const_iterator end = mScreens.constEnd(); - while (i != end) { - (*i)->lower(this); - ++i; - } -} - -void QFbScreen::lower(QPlatformWindow * surface) -{ - QFbWindow *s = static_cast<QFbWindow *>(surface); - int index = windowStack.indexOf(s); - if (index == -1 || index == (windowStack.size() - 1)) - return; - windowStack.move(index, windowStack.size() - 1); - invalidateRectCache(); - setDirty(s->geometry()); -} - -QWidget * QFbScreen::topLevelAt(const QPoint & p) const -{ - for(int i = 0; i < windowStack.size(); i++) { - if (windowStack[i]->geometry().contains(p, false) && - windowStack[i]->visible() && - !windowStack[i]->widget()->isMinimized()) { - return windowStack[i]->widget(); - } - } - return 0; -} - -QFbWindow::QFbWindow(QWidget *window) - :QPlatformWindow(window), - visibleFlag(false) -{ - static QAtomicInt winIdGenerator(1); - windowId = winIdGenerator.fetchAndAddRelaxed(1); -} - - -QFbWindow::~QFbWindow() -{ - QList<QFbScreen *>::const_iterator i = mScreens.constBegin(); - QList<QFbScreen *>::const_iterator end = mScreens.constEnd(); - while (i != end) { - (*i)->removeWindow(this); - ++i; - } -} - - -QFbWindowSurface::QFbWindowSurface(QFbScreen *screen, QWidget *window) - : QWindowSurface(window), - mScreen(screen) -{ - mImage = QImage(window->size(), mScreen->format()); - - platformWindow = static_cast<QFbWindow*>(window->platformWindow()); - platformWindow->surface = this; -} - -QFbWindowSurface::~QFbWindowSurface() -{ -} - -void QFbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) -{ - Q_UNUSED(widget); - Q_UNUSED(offset); - - -// qDebug() << "QFbWindowSurface::flush" << region; - - - platformWindow->repaint(region); -} - - -void QFbWindow::repaint(const QRegion ®ion) -{ - QRect currentGeometry = geometry(); - - QRect dirtyClient = region.boundingRect(); - QRect dirtyRegion(currentGeometry.left() + dirtyClient.left(), - currentGeometry.top() + dirtyClient.top(), - dirtyClient.width(), - dirtyClient.height()); - QList<QFbScreen *>::const_iterator i = mScreens.constBegin(); - QList<QFbScreen *>::const_iterator end = mScreens.constEnd(); - QRect oldGeometryLocal = oldGeometry; - oldGeometry = currentGeometry; - while (i != end) { - // If this is a move, redraw the previous location - if (oldGeometryLocal != currentGeometry) { - (*i)->setDirty(oldGeometryLocal); - } - (*i)->setDirty(dirtyRegion); - ++i; - } -} - -void QFbWindowSurface::resize(const QSize &size) -{ - // change the widget's QImage if this is a resize - if (mImage.size() != size) - mImage = QImage(size, mScreen->format()); - QWindowSurface::resize(size); -} - -void QFbWindow::setGeometry(const QRect &rect) -{ -// store previous geometry for screen update - oldGeometry = geometry(); - - - QList<QFbScreen *>::const_iterator i = mScreens.constBegin(); - QList<QFbScreen *>::const_iterator end = mScreens.constEnd(); - while (i != end) { - (*i)->invalidateRectCache(); - ++i; - } -//### QWindowSystemInterface::handleGeometryChange(window(), rect); - - QPlatformWindow::setGeometry(rect); -} - -bool QFbWindowSurface::scroll(const QRegion &area, int dx, int dy) -{ - return QWindowSurface::scroll(area, dx, dy); -} - -void QFbWindowSurface::beginPaint(const QRegion ®ion) -{ - Q_UNUSED(region); -} - -void QFbWindowSurface::endPaint(const QRegion ®ion) -{ - Q_UNUSED(region); -} - -void QFbWindow::setVisible(bool visible) -{ - visibleFlag = visible; - QList<QFbScreen *>::const_iterator i = mScreens.constBegin(); - QList<QFbScreen *>::const_iterator end = mScreens.constEnd(); - while (i != end) { - (*i)->invalidateRectCache(); - (*i)->setDirty(geometry()); - ++i; - } -} - -Qt::WindowFlags QFbWindow::setWindowFlags(Qt::WindowFlags type) -{ - flags = type; - QList<QFbScreen *>::const_iterator i = mScreens.constBegin(); - QList<QFbScreen *>::const_iterator end = mScreens.constEnd(); - while (i != end) { - (*i)->invalidateRectCache(); - ++i; - } - return flags; -} - -Qt::WindowFlags QFbWindow::windowFlags() const -{ - return flags; -} diff --git a/src/plugins/platforms/fb_base/fb_base.h b/src/plugins/platforms/fb_base/fb_base.h deleted file mode 100644 index 6b0b152482..0000000000 --- a/src/plugins/platforms/fb_base/fb_base.h +++ /dev/null @@ -1,210 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QLIGHTHOUSEGRAPHICSSCREEN_H -#define QLIGHTHOUSEGRAPHICSSCREEN_H - -#include <qrect.h> -#include <qimage.h> -#include <qtimer.h> -#include <qpainter.h> -#include <QPlatformCursor> -#include <QPlatformScreen> -#include <QPlatformWindow> -#include <QtGui/private/qwindowsurface_p.h> - -class QMouseEvent; -class QSize; -class QPainter; - -class QFbScreen; - -class QPlatformSoftwareCursor : public QPlatformCursor -{ -public: - QPlatformSoftwareCursor(QPlatformScreen * scr); - - // output methods - QRect dirtyRect(); - virtual QRect drawCursor(QPainter & painter); - - // input methods - virtual void pointerEvent(const QMouseEvent & event); - virtual void changeCursor(QCursor * widgetCursor, QWidget * widget); - - virtual void setDirty() { dirty = true; screen->setDirty(QRect()); } - virtual bool isDirty() { return dirty; } - virtual bool isOnScreen() { return onScreen; } - virtual QRect lastPainted() { return prevRect; } - -protected: - QPlatformCursorImage * graphic; - -private: - void setCursor(const uchar *data, const uchar *mask, int width, int height, int hotX, int hotY); - void setCursor(Qt::CursorShape shape); - void setCursor(const QImage &image, int hotx, int hoty); - QRect currentRect; // next place to draw the cursor - QRect prevRect; // last place the cursor was drawn - QRect getCurrentRect(); - bool dirty; - bool onScreen; -}; - -class QFbWindow; - -class QFbWindowSurface : public QWindowSurface -{ -public: - QFbWindowSurface(QFbScreen *screen, QWidget *window); - ~QFbWindowSurface(); - - virtual QPaintDevice *paintDevice() { return &mImage; } - virtual void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); - virtual bool scroll(const QRegion &area, int dx, int dy); - - virtual void beginPaint(const QRegion ®ion); - virtual void endPaint(const QRegion ®ion); - - - const QImage image() { return mImage; } - void resize(const QSize &size); - -protected: - friend class QFbWindow; - QFbWindow *platformWindow; - - QFbScreen *mScreen; - QImage mImage; -}; - - -class QFbWindow : public QPlatformWindow -{ -public: - - QFbWindow(QWidget *window); - ~QFbWindow(); - - - virtual void setVisible(bool visible); - virtual bool visible() { return visibleFlag; } - - virtual void raise(); - virtual void lower(); - - void setGeometry(const QRect &rect); - - virtual Qt::WindowFlags setWindowFlags(Qt::WindowFlags type); - virtual Qt::WindowFlags windowFlags() const; - - WId winId() const { return windowId; } - - virtual void repaint(const QRegion&); - -protected: - friend class QFbWindowSurface; - friend class QFbScreen; - QFbWindowSurface *surface; - QList<QFbScreen *> mScreens; - QRect oldGeometry; - bool visibleFlag; - Qt::WindowFlags flags; - - WId windowId; -}; - -class QFbScreen : public QPlatformScreen -{ - Q_OBJECT -public: - QFbScreen(); - ~QFbScreen(); - - virtual QRect geometry() const { return mGeometry; } - virtual int depth() const { return mDepth; } - virtual QImage::Format format() const { return mFormat; } - virtual QSize physicalSize() const { return mPhysicalSize; } - - virtual void setGeometry(QRect rect); - virtual void setDepth(int depth); - virtual void setFormat(QImage::Format format); - virtual void setPhysicalSize(QSize size); - - virtual void setDirty(const QRect &rect); - - virtual void removeWindow(QFbWindow * surface); - virtual void addWindow(QFbWindow * surface); - virtual void raise(QPlatformWindow * surface); - virtual void lower(QPlatformWindow * surface); - virtual QWidget * topLevelAt(const QPoint & p) const; - - QImage * image() const { return mScreenImage; } - QPaintDevice * paintDevice() const { return mScreenImage; } - -protected: - QList<QFbWindow *> windowStack; - QRegion repaintRegion; - QPlatformSoftwareCursor * cursor; - QTimer redrawTimer; - -protected slots: - virtual QRegion doRedraw(); - -protected: - QRect mGeometry; - int mDepth; - QImage::Format mFormat; - QSize mPhysicalSize; - QImage *mScreenImage; - -private: - QPainter * compositePainter; - void generateRects(); - QList<QPair<QRect, int> > cachedRects; - - void invalidateRectCache() { isUpToDate = false; } - friend class QFbWindowSurface; - friend class QFbWindow; - bool isUpToDate; -}; - -#endif // QLIGHTHOUSEGRAPHICSSCREEN_H diff --git a/src/plugins/platforms/fb_base/fb_base.pri b/src/plugins/platforms/fb_base/fb_base.pri deleted file mode 100644 index 41bd87fbca..0000000000 --- a/src/plugins/platforms/fb_base/fb_base.pri +++ /dev/null @@ -1,2 +0,0 @@ -SOURCES += ../fb_base/fb_base.cpp -HEADERS += ../fb_base/fb_base.h diff --git a/src/plugins/platforms/fb_base/fb_base.pro b/src/plugins/platforms/fb_base/fb_base.pro deleted file mode 100644 index 4ebd53b407..0000000000 --- a/src/plugins/platforms/fb_base/fb_base.pro +++ /dev/null @@ -1,23 +0,0 @@ -#------------------------------------------------- -# -# Project created by QtCreator 2009-11-05T13:22:31 -# -#------------------------------------------------- - -#QT -= core gui -TARGET = fb_base -#load(qt_plugin) - -DESTDIR = $$QT.gui.plugins/graphicssystems - -TEMPLATE = lib - -#DEFINES += STATIC_LIBRARY -CONFIG += staticlib - -SOURCES += fb_base.cpp - -HEADERS += fb_base.h - -target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems -INSTALLS += target diff --git a/src/plugins/platforms/fontdatabases/basicunix/basicunix.pri b/src/plugins/platforms/fontdatabases/basicunix/basicunix.pri deleted file mode 100644 index c1fbf3e411..0000000000 --- a/src/plugins/platforms/fontdatabases/basicunix/basicunix.pri +++ /dev/null @@ -1,88 +0,0 @@ -DEFINES += QT_NO_FONTCONFIG -HEADERS += \ - $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.h \ - $$QT_SOURCE_TREE/src/gui/text/qfontengine_ft_p.h - -SOURCES += \ - $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.cpp \ - $$QT_SOURCE_TREE/src/gui/text/qfontengine_ft.cpp - -DEFINES += QT_COMPILES_IN_HARFBUZZ - -INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/harfbuzz/src - -INCLUDEPATH += $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/basicunix - -CONFIG += opentype - -contains(QT_CONFIG, freetype) { - SOURCES += \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftbase.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftbbox.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftdebug.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftglyph.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftinit.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftmm.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/fttype1.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftsynth.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftbitmap.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/bdf/bdf.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/cache/ftcache.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/cff/cff.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/cid/type1cid.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/gzip/ftgzip.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/pcf/pcf.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/pfr/pfr.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/psaux/psaux.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/pshinter/pshinter.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/psnames/psmodule.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/raster/raster.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/sfnt/sfnt.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/smooth/smooth.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/truetype/truetype.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/type1/type1.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/type42/type42.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/winfonts/winfnt.c \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/lzw/ftlzw.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvalid.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvbase.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvgdef.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvjstf.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvcommn.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvgpos.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvgsub.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/otvalid/otvmod.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/afangles.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/afglobal.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/aflatin.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/afmodule.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/afdummy.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/afhints.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/afloader.c\ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/autofit/autofit.c - - symbian { - SOURCES += \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src/base/ftsystem.c - } else { - SOURCES += \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/builds/unix/ftsystem.c - INCLUDEPATH += \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/builds/unix - } - - INCLUDEPATH += \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/src \ - $$QT_SOURCE_TREE/src/3rdparty/freetype/include - - DEFINES += FT2_BUILD_LIBRARY - contains(QT_CONFIG, system-zlib) { - DEFINES += FT_CONFIG_OPTION_SYSTEM_ZLIB - } - - } else:contains(QT_CONFIG, system-freetype) { - # pull in the proper freetype2 include directory - include($$QT_SOURCE_TREE/config.tests/unix/freetype/freetype.pri) - LIBS_PRIVATE += -lfreetype - } - diff --git a/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.cpp b/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.cpp deleted file mode 100644 index 001d377ca0..0000000000 --- a/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.cpp +++ /dev/null @@ -1,328 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qbasicunixfontdatabase.h" - -#include <QtGui/private/qapplication_p.h> -#include <QtGui/QPlatformScreen> - -#include <QtCore/QFile> -#include <QtCore/QLibraryInfo> -#include <QtCore/QDir> - -#undef QT_NO_FREETYPE -#include <QtGui/private/qfontengine_ft_p.h> -#include <QtGui/private/qfontengine_p.h> - -#include <ft2build.h> -#include FT_TRUETYPE_TABLES_H - -#define SimplifiedChineseCsbBit 18 -#define TraditionalChineseCsbBit 20 -#define JapaneseCsbBit 17 -#define KoreanCsbBit 21 - -static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = { - // Any, - { 127, 127 }, - // Latin, - { 0, 127 }, - // Greek, - { 7, 127 }, - // Cyrillic, - { 9, 127 }, - // Armenian, - { 10, 127 }, - // Hebrew, - { 11, 127 }, - // Arabic, - { 13, 127 }, - // Syriac, - { 71, 127 }, - //Thaana, - { 72, 127 }, - //Devanagari, - { 15, 127 }, - //Bengali, - { 16, 127 }, - //Gurmukhi, - { 17, 127 }, - //Gujarati, - { 18, 127 }, - //Oriya, - { 19, 127 }, - //Tamil, - { 20, 127 }, - //Telugu, - { 21, 127 }, - //Kannada, - { 22, 127 }, - //Malayalam, - { 23, 127 }, - //Sinhala, - { 73, 127 }, - //Thai, - { 24, 127 }, - //Lao, - { 25, 127 }, - //Tibetan, - { 70, 127 }, - //Myanmar, - { 74, 127 }, - // Georgian, - { 26, 127 }, - // Khmer, - { 80, 127 }, - // SimplifiedChinese, - { 126, 127 }, - // TraditionalChinese, - { 126, 127 }, - // Japanese, - { 126, 127 }, - // Korean, - { 56, 127 }, - // Vietnamese, - { 0, 127 }, // same as latin1 - // Other, - { 126, 127 }, - // Ogham, - { 78, 127 }, - // Runic, - { 79, 127 }, - // Nko, - { 14, 127 }, -}; - -static QSupportedWritingSystems determineWritingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2]) -{ - QSupportedWritingSystems writingSystems; - bool hasScript = false; - - int i; - for(i = 0; i < QFontDatabase::WritingSystemsCount; i++) { - int bit = requiredUnicodeBits[i][0]; - int index = bit/32; - int flag = 1 << (bit&31); - if (bit != 126 && unicodeRange[index] & flag) { - bit = requiredUnicodeBits[i][1]; - index = bit/32; - - flag = 1 << (bit&31); - if (bit == 127 || unicodeRange[index] & flag) { - writingSystems.setSupported(QFontDatabase::WritingSystem(i)); - hasScript = true; - // qDebug("font %s: index=%d, flag=%8x supports script %d", familyName.latin1(), index, flag, i); - } - } - } - if(codePageRange[0] & (1 << SimplifiedChineseCsbBit)) { - writingSystems.setSupported(QFontDatabase::SimplifiedChinese); - hasScript = true; - //qDebug("font %s supports Simplified Chinese", familyName.latin1()); - } - if(codePageRange[0] & (1 << TraditionalChineseCsbBit)) { - writingSystems.setSupported(QFontDatabase::TraditionalChinese); - hasScript = true; - //qDebug("font %s supports Traditional Chinese", familyName.latin1()); - } - if(codePageRange[0] & (1 << JapaneseCsbBit)) { - writingSystems.setSupported(QFontDatabase::Japanese); - hasScript = true; - //qDebug("font %s supports Japanese", familyName.latin1()); - } - if(codePageRange[0] & (1 << KoreanCsbBit)) { - writingSystems.setSupported(QFontDatabase::Korean); - hasScript = true; - //qDebug("font %s supports Korean", familyName.latin1()); - } - if (!hasScript) - writingSystems.setSupported(QFontDatabase::Symbol); - - return writingSystems; -} - -static inline bool scriptRequiresOpenType(int script) -{ - return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala) - || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko); -} - -void QBasicUnixFontDatabase::populateFontDatabase() -{ - QPlatformFontDatabase::populateFontDatabase(); - QString fontpath = fontDir(); - - if(!QFile::exists(fontpath)) { - qFatal("QFontDatabase: Cannot find font directory %s - is Qt installed correctly?", - qPrintable(fontpath)); - } - - QDir dir(fontpath); - dir.setNameFilters(QStringList() << QLatin1String("*.ttf") - << QLatin1String("*.ttc") << QLatin1String("*.pfa") - << QLatin1String("*.pfb")); - dir.refresh(); - for (int i = 0; i < int(dir.count()); ++i) { - const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i])); -// qDebug() << "looking at" << file; - addTTFile(QByteArray(), file); - } -} - -QFontEngine *QBasicUnixFontDatabase::fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *usrPtr) -{ - QFontEngineFT *engine; - FontFile *fontfile = static_cast<FontFile *> (usrPtr); - QFontEngine::FaceId fid; - fid.filename = fontfile->fileName.toLocal8Bit(); - fid.index = fontfile->indexValue; - engine = new QFontEngineFT(fontDef); - - bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias); - QFontEngineFT::GlyphFormat format = antialias? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono; - if (!engine->init(fid,antialias,format)) { - delete engine; - engine = 0; - return engine; - } - if (engine->invalid()) { - delete engine; - engine = 0; - } else if (scriptRequiresOpenType(script)) { - HB_Face hbFace = engine->harfbuzzFace(); - if (!hbFace || !hbFace->supported_scripts[script]) { - delete engine; - engine = 0; - } - } - - return engine; -} - -QStringList QBasicUnixFontDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QUnicodeTables::Script &script) const -{ - Q_UNUSED(family); - Q_UNUSED(style); - Q_UNUSED(script); - return QStringList(); -} - -QStringList QBasicUnixFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName) -{ - return addTTFile(fontData,fileName.toLocal8Bit()); -} - -void QBasicUnixFontDatabase::releaseHandle(void *handle) -{ - FontFile *file = static_cast<FontFile *>(handle); - delete file; -} - -QStringList QBasicUnixFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file) -{ - extern FT_Library qt_getFreetype(); - FT_Library library = qt_getFreetype(); - - int index = 0; - int numFaces = 0; - QStringList families; - do { - FT_Face face; - FT_Error error; - if (!fontData.isEmpty()) { - error = FT_New_Memory_Face(library, (const FT_Byte *)fontData.constData(), fontData.size(), index, &face); - } else { - error = FT_New_Face(library, file.constData(), index, &face); - } - if (error != FT_Err_Ok) { - qDebug() << "FT_New_Face failed with index" << index << ":" << hex << error; - break; - } - numFaces = face->num_faces; - - QFont::Weight weight = QFont::Normal; - - QFont::Style style = QFont::StyleNormal; - if (face->style_flags & FT_STYLE_FLAG_ITALIC) - style = QFont::StyleItalic; - - if (face->style_flags & FT_STYLE_FLAG_BOLD) - weight = QFont::Bold; - - QSupportedWritingSystems writingSystems; - // detect symbol fonts - for (int i = 0; i < face->num_charmaps; ++i) { - FT_CharMap cm = face->charmaps[i]; - if (cm->encoding == ft_encoding_adobe_custom - || cm->encoding == ft_encoding_symbol) { - writingSystems.setSupported(QFontDatabase::Symbol); - break; - } - } - - TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2); - if (os2) { - quint32 unicodeRange[4] = { - os2->ulUnicodeRange1, os2->ulUnicodeRange2, os2->ulUnicodeRange3, os2->ulUnicodeRange4 - }; - quint32 codePageRange[2] = { - os2->ulCodePageRange1, os2->ulCodePageRange2 - }; - - writingSystems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); - } - - QString family = QString::fromAscii(face->family_name); - FontFile *fontFile = new FontFile; - fontFile->fileName = file; - fontFile->indexValue = index; - - QFont::Stretch stretch = QFont::Unstretched; - - registerFont(family,"",weight,style,stretch,true,true,0,writingSystems,fontFile); - - families.append(family); - - FT_Done_Face(face); - ++index; - } while (index < numFaces); - return families; -} diff --git a/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.h b/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.h deleted file mode 100644 index f7fc0e547b..0000000000 --- a/src/plugins/platforms/fontdatabases/basicunix/qbasicunixfontdatabase.h +++ /dev/null @@ -1,67 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QBASICUNIXFONTDATABASE_H -#define QBASICUNIXFONTDATABASE_H - -#include <QPlatformFontDatabase> -#include <QtCore/QByteArray> -#include <QtCore/QString> - -struct FontFile -{ - QString fileName; - int indexValue; -}; - -class QBasicUnixFontDatabase : public QPlatformFontDatabase -{ -public: - void populateFontDatabase(); - QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle); - QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QUnicodeTables::Script &script) const; - QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); - void releaseHandle(void *handle); - - static QStringList addTTFile(const QByteArray &fontData, const QByteArray &file); -}; - -#endif // QBASICUNIXFONTDATABASE_H diff --git a/src/plugins/platforms/fontdatabases/fontconfig/fontconfig.pri b/src/plugins/platforms/fontdatabases/fontconfig/fontconfig.pri deleted file mode 100644 index 19c74ed089..0000000000 --- a/src/plugins/platforms/fontdatabases/fontconfig/fontconfig.pri +++ /dev/null @@ -1,12 +0,0 @@ -include(../basicunix/basicunix.pri) - -HEADERS += \ - $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.h - -SOURCES += \ - $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.cpp - -INCLUDEPATH += $$QT_SOURCE_TREE/src/plugins/platforms/fontdatabases/fontconfig -LIBS_PRIVATE += -lfontconfig - - diff --git a/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.cpp deleted file mode 100644 index 377d6552d5..0000000000 --- a/src/plugins/platforms/fontdatabases/fontconfig/qfontconfigdatabase.cpp +++ /dev/null @@ -1,601 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qfontconfigdatabase.h" - -#include <QtCore/QList> -#include <QtGui/private/qfont_p.h> - -#include <QtCore/QElapsedTimer> - -#include <QtGui/private/qapplication_p.h> -#include <QtGui/QPlatformScreen> - -#include <QtGui/private/qfontengine_ft_p.h> -#include <QtGui/private/qfontengine_p.h> - - - -#include <ft2build.h> -#include FT_TRUETYPE_TABLES_H - -#include <fontconfig/fontconfig.h> - -#define SimplifiedChineseCsbBit 18 -#define TraditionalChineseCsbBit 20 -#define JapaneseCsbBit 17 -#define KoreanCsbBit 21 - -static inline bool requiresOpenType(int writingSystem) -{ - return ((writingSystem >= QFontDatabase::Syriac && writingSystem <= QFontDatabase::Sinhala) - || writingSystem == QFontDatabase::Khmer || writingSystem == QFontDatabase::Nko); -} -static inline bool scriptRequiresOpenType(int script) -{ - return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala) - || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko); -} - -static int getFCWeight(int fc_weight) -{ - int qtweight = QFont::Black; - if (fc_weight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_MEDIUM) / 2) - qtweight = QFont::Light; - else if (fc_weight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2) - qtweight = QFont::Normal; - else if (fc_weight <= (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2) - qtweight = QFont::DemiBold; - else if (fc_weight <= (FC_WEIGHT_BOLD + FC_WEIGHT_BLACK) / 2) - qtweight = QFont::Bold; - - return qtweight; -} - -static const char *specialLanguages[] = { - "en", // Common - "el", // Greek - "ru", // Cyrillic - "hy", // Armenian - "he", // Hebrew - "ar", // Arabic - "syr", // Syriac - "div", // Thaana - "hi", // Devanagari - "bn", // Bengali - "pa", // Gurmukhi - "gu", // Gujarati - "or", // Oriya - "ta", // Tamil - "te", // Telugu - "kn", // Kannada - "ml", // Malayalam - "si", // Sinhala - "th", // Thai - "lo", // Lao - "bo", // Tibetan - "my", // Myanmar - "ka", // Georgian - "ko", // Hangul - "", // Ogham - "", // Runic - "km", // Khmer - "" // N'Ko -}; -enum { SpecialLanguageCount = sizeof(specialLanguages) / sizeof(const char *) }; - -static const ushort specialChars[] = { - 0, // English - 0, // Greek - 0, // Cyrillic - 0, // Armenian - 0, // Hebrew - 0, // Arabic - 0, // Syriac - 0, // Thaana - 0, // Devanagari - 0, // Bengali - 0, // Gurmukhi - 0, // Gujarati - 0, // Oriya - 0, // Tamil - 0xc15, // Telugu - 0xc95, // Kannada - 0xd15, // Malayalam - 0xd9a, // Sinhala - 0, // Thai - 0, // Lao - 0, // Tibetan - 0x1000, // Myanmar - 0, // Georgian - 0, // Hangul - 0x1681, // Ogham - 0x16a0, // Runic - 0, // Khmer - 0x7ca // N'Ko -}; -enum { SpecialCharCount = sizeof(specialChars) / sizeof(ushort) }; - -// this could become a list of all languages used for each writing -// system, instead of using the single most common language. -static const char *languageForWritingSystem[] = { - 0, // Any - "en", // Latin - "el", // Greek - "ru", // Cyrillic - "hy", // Armenian - "he", // Hebrew - "ar", // Arabic - "syr", // Syriac - "div", // Thaana - "hi", // Devanagari - "bn", // Bengali - "pa", // Gurmukhi - "gu", // Gujarati - "or", // Oriya - "ta", // Tamil - "te", // Telugu - "kn", // Kannada - "ml", // Malayalam - "si", // Sinhala - "th", // Thai - "lo", // Lao - "bo", // Tibetan - "my", // Myanmar - "ka", // Georgian - "km", // Khmer - "zh-cn", // SimplifiedChinese - "zh-tw", // TraditionalChinese - "ja", // Japanese - "ko", // Korean - "vi", // Vietnamese - 0, // Symbol - 0, // Ogham - 0, // Runic - 0 // N'Ko -}; -enum { LanguageCount = sizeof(languageForWritingSystem) / sizeof(const char *) }; - -// Unfortunately FontConfig doesn't know about some languages. We have to test these through the -// charset. The lists below contain the systems where we need to do this. -static const ushort sampleCharForWritingSystem[] = { - 0, // Any - 0, // Latin - 0, // Greek - 0, // Cyrillic - 0, // Armenian - 0, // Hebrew - 0, // Arabic - 0, // Syriac - 0, // Thaana - 0, // Devanagari - 0, // Bengali - 0, // Gurmukhi - 0, // Gujarati - 0, // Oriya - 0, // Tamil - 0xc15, // Telugu - 0xc95, // Kannada - 0xd15, // Malayalam - 0xd9a, // Sinhala - 0, // Thai - 0, // Lao - 0, // Tibetan - 0x1000, // Myanmar - 0, // Georgian - 0, // Khmer - 0, // SimplifiedChinese - 0, // TraditionalChinese - 0, // Japanese - 0, // Korean - 0, // Vietnamese - 0, // Symbol - 0x1681, // Ogham - 0x16a0, // Runic - 0x7ca // N'Ko -}; -enum { SampleCharCount = sizeof(sampleCharForWritingSystem) / sizeof(ushort) }; - -// Newer FontConfig let's us sort out fonts that contain certain glyphs, but no -// open type tables for is directly. Do this so we don't pick some strange -// pseudo unicode font -static const char *openType[] = { - 0, // Any - 0, // Latin - 0, // Greek - 0, // Cyrillic - 0, // Armenian - 0, // Hebrew - 0, // Arabic - "syrc", // Syriac - "thaa", // Thaana - "deva", // Devanagari - "beng", // Bengali - "guru", // Gurmukhi - "gurj", // Gujarati - "orya", // Oriya - "taml", // Tamil - "telu", // Telugu - "knda", // Kannada - "mlym", // Malayalam - "sinh", // Sinhala - 0, // Thai - 0, // Lao - "tibt", // Tibetan - "mymr", // Myanmar - 0, // Georgian - "khmr", // Khmer - 0, // SimplifiedChinese - 0, // TraditionalChinese - 0, // Japanese - 0, // Korean - 0, // Vietnamese - 0, // Symbol - 0, // Ogham - 0, // Runic - "nko " // N'Ko -}; - -static const char *getFcFamilyForStyleHint(const QFont::StyleHint style) -{ - const char *stylehint = 0; - switch (style) { - case QFont::SansSerif: - stylehint = "sans-serif"; - break; - case QFont::Serif: - stylehint = "serif"; - break; - case QFont::TypeWriter: - stylehint = "monospace"; - break; - default: - break; - } - return stylehint; -} - -void QFontconfigDatabase::populateFontDatabase() -{ - FcFontSet *fonts; - - QString familyName; - FcChar8 *value = 0; - int weight_value; - int slant_value; - int spacing_value; - FcChar8 *file_value; - int indexValue; - FcChar8 *foundry_value; - FcBool scalable; - FcBool antialias; - - { - FcObjectSet *os = FcObjectSetCreate(); - FcPattern *pattern = FcPatternCreate(); - const char *properties [] = { - FC_FAMILY, FC_WEIGHT, FC_SLANT, - FC_SPACING, FC_FILE, FC_INDEX, - FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, FC_WEIGHT, - FC_WIDTH, -#if FC_VERSION >= 20297 - FC_CAPABILITY, -#endif - (const char *)0 - }; - const char **p = properties; - while (*p) { - FcObjectSetAdd(os, *p); - ++p; - } - fonts = FcFontList(0, pattern, os); - FcObjectSetDestroy(os); - FcPatternDestroy(pattern); - } - - for (int i = 0; i < fonts->nfont; i++) { - if (FcPatternGetString(fonts->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch) - continue; - // capitalize(value); - familyName = QString::fromUtf8((const char *)value); - slant_value = FC_SLANT_ROMAN; - weight_value = FC_WEIGHT_MEDIUM; - spacing_value = FC_PROPORTIONAL; - file_value = 0; - indexValue = 0; - scalable = FcTrue; - - - if (FcPatternGetInteger (fonts->fonts[i], FC_SLANT, 0, &slant_value) != FcResultMatch) - slant_value = FC_SLANT_ROMAN; - if (FcPatternGetInteger (fonts->fonts[i], FC_WEIGHT, 0, &weight_value) != FcResultMatch) - weight_value = FC_WEIGHT_MEDIUM; - if (FcPatternGetInteger (fonts->fonts[i], FC_SPACING, 0, &spacing_value) != FcResultMatch) - spacing_value = FC_PROPORTIONAL; - if (FcPatternGetString (fonts->fonts[i], FC_FILE, 0, &file_value) != FcResultMatch) - file_value = 0; - if (FcPatternGetInteger (fonts->fonts[i], FC_INDEX, 0, &indexValue) != FcResultMatch) - indexValue = 0; - if (FcPatternGetBool(fonts->fonts[i], FC_SCALABLE, 0, &scalable) != FcResultMatch) - scalable = FcTrue; - if (FcPatternGetString(fonts->fonts[i], FC_FOUNDRY, 0, &foundry_value) != FcResultMatch) - foundry_value = 0; - if(FcPatternGetBool(fonts->fonts[i],FC_ANTIALIAS,0,&antialias) != FcResultMatch) - antialias = true; - - QSupportedWritingSystems writingSystems; - FcLangSet *langset = 0; - FcResult res = FcPatternGetLangSet(fonts->fonts[i], FC_LANG, 0, &langset); - if (res == FcResultMatch) { - for (int i = 1; i < LanguageCount; ++i) { - const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[i]; - if (lang) { - FcLangResult langRes = FcLangSetHasLang(langset, lang); - if (langRes != FcLangDifferentLang) - writingSystems.setSupported(QFontDatabase::WritingSystem(i)); - } - } - } else { - // we set Other to supported for symbol fonts. It makes no - // sense to merge these with other ones, as they are - // special in a way. - writingSystems.setSupported(QFontDatabase::Other); - } - - FcCharSet *cs = 0; - res = FcPatternGetCharSet(fonts->fonts[i], FC_CHARSET, 0, &cs); - if (res == FcResultMatch) { - // some languages are not supported by FontConfig, we rather check the - // charset to detect these - for (int i = 1; i < SampleCharCount; ++i) { - if (!sampleCharForWritingSystem[i]) - continue; - if (FcCharSetHasChar(cs, sampleCharForWritingSystem[i])) - writingSystems.setSupported(QFontDatabase::WritingSystem(i)); - } - } - -#if FC_VERSION >= 20297 - for (int j = 1; j < LanguageCount; ++j) { - if (writingSystems.supported(QFontDatabase::WritingSystem(j)) - && requiresOpenType(j) && openType[j]) { - FcChar8 *cap; - res = FcPatternGetString (fonts->fonts[i], FC_CAPABILITY, 0, &cap); - if (res != FcResultMatch || !strstr((const char *)cap, openType[j])) - writingSystems.setSupported(QFontDatabase::WritingSystem(j),false); - } - } -#endif - - FontFile *fontFile = new FontFile; - fontFile->fileName = QLatin1String((const char *)file_value); - fontFile->indexValue = indexValue; - - QFont::Style style = (slant_value == FC_SLANT_ITALIC) - ? QFont::StyleItalic - : ((slant_value == FC_SLANT_OBLIQUE) - ? QFont::StyleOblique - : QFont::StyleNormal); - QFont::Weight weight = QFont::Weight(getFCWeight(weight_value)); - - double pixel_size = 0; - if (!scalable) { - int width = 100; - FcPatternGetInteger (fonts->fonts[i], FC_WIDTH, 0, &width); - FcPatternGetDouble (fonts->fonts[i], FC_PIXEL_SIZE, 0, &pixel_size); - } - - QFont::Stretch stretch = QFont::Unstretched; - QPlatformFontDatabase::registerFont(familyName,QLatin1String((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,writingSystems,fontFile); -// qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size; - } - - FcFontSetDestroy (fonts); - - struct FcDefaultFont { - const char *qtname; - const char *rawname; - bool fixed; - }; - const FcDefaultFont defaults[] = { - { "Serif", "serif", false }, - { "Sans Serif", "sans-serif", false }, - { "Monospace", "monospace", true }, - { 0, 0, false } - }; - const FcDefaultFont *f = defaults; - // aliases only make sense for 'common', not for any of the specials - QSupportedWritingSystems ws; - ws.setSupported(QFontDatabase::Latin); - - - while (f->qtname) { - registerFont(f->qtname,QLatin1String(""),QFont::Normal,QFont::StyleNormal,QFont::Unstretched,true,true,0,ws,0); - registerFont(f->qtname,QLatin1String(""),QFont::Normal,QFont::StyleItalic,QFont::Unstretched,true,true,0,ws,0); - registerFont(f->qtname,QLatin1String(""),QFont::Normal,QFont::StyleOblique,QFont::Unstretched,true,true,0,ws,0); - ++f; - } - - //Lighthouse has very lazy population of the font db. We want it to be initialized when - //QApplication is constructed, so that the population procedure can do something like this to - //set the default font -// const FcDefaultFont *s = defaults; -// QFont font("Sans Serif"); -// font.setPointSize(9); -// QApplication::setFont(font); -} - -QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, QUnicodeTables::Script script, void *usrPtr) -{ - if (!usrPtr) - return 0; - QFontDef fontDef = f; - - QFontEngineFT *engine; - FontFile *fontfile = static_cast<FontFile *> (usrPtr); - QFontEngine::FaceId fid; - fid.filename = fontfile->fileName.toLocal8Bit(); - fid.index = fontfile->indexValue; - - //try and get the pattern - FcPattern *pattern = FcPatternCreate(); - - bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias); - QFontEngineFT::GlyphFormat format = antialias? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono; - - engine = new QFontEngineFT(fontDef); - - FcValue value; - value.type = FcTypeString; - QByteArray cs = fontDef.family.toUtf8(); - value.u.s = (const FcChar8 *)cs.data(); - FcPatternAdd(pattern,FC_FAMILY,value,true); - - - value.u.s = (const FcChar8 *)fid.filename.data(); - FcPatternAdd(pattern,FC_FILE,value,true); - - value.type = FcTypeInteger; - value.u.i = fid.index; - FcPatternAdd(pattern,FC_INDEX,value,true); - - QFontEngineFT::HintStyle default_hint_style; - - if (FcConfigSubstitute(0,pattern,FcMatchPattern)) { - - //hinting - int hint_style = 0; - if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hint_style) == FcResultNoMatch) - hint_style = QFontEngineFT::HintFull; - switch (hint_style) { - case FC_HINT_NONE: - default_hint_style = QFontEngineFT::HintNone; - break; - case FC_HINT_SLIGHT: - default_hint_style = QFontEngineFT::HintLight; - break; - case FC_HINT_MEDIUM: - default_hint_style = QFontEngineFT::HintMedium; - break; - default: - default_hint_style = QFontEngineFT::HintFull; - break; - } - } - - engine->setDefaultHintStyle(default_hint_style); - if (!engine->init(fid,antialias,format)) { - delete engine; - engine = 0; - return engine; - } - if (engine->invalid()) { - delete engine; - engine = 0; - } else if (scriptRequiresOpenType(script)) { - HB_Face hbFace = engine->harfbuzzFace(); - if (!hbFace || !hbFace->supported_scripts[script]) { - delete engine; - engine = 0; - } - } - - return engine; -} - -QStringList QFontconfigDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const -{ - QStringList fallbackFamilies; - FcPattern *pattern = FcPatternCreate(); - if (!pattern) - return fallbackFamilies; - - FcValue value; - value.type = FcTypeString; - QByteArray cs = family.toUtf8(); - value.u.s = (const FcChar8 *)cs.data(); - FcPatternAdd(pattern,FC_FAMILY,value,true); - - int slant_value = FC_SLANT_ROMAN; - if (style == QFont::StyleItalic) - slant_value = FC_SLANT_ITALIC; - else if (style == QFont::StyleOblique) - slant_value = FC_SLANT_OBLIQUE; - FcPatternAddInteger(pattern, FC_SLANT, slant_value); - - if (script != QUnicodeTables::Common && *specialLanguages[script] != '\0') { - Q_ASSERT(script < QUnicodeTables::ScriptCount); - FcLangSet *ls = FcLangSetCreate(); - FcLangSetAdd(ls, (const FcChar8*)specialLanguages[script]); - FcPatternAddLangSet(pattern, FC_LANG, ls); - FcLangSetDestroy(ls); - } - - const char *stylehint = getFcFamilyForStyleHint(styleHint); - if (stylehint) { - value.u.s = (const FcChar8 *)stylehint; - FcPatternAddWeak(pattern, FC_FAMILY, value, FcTrue); - } - - FcConfigSubstitute(0, pattern, FcMatchPattern); - FcConfigSubstitute(0, pattern, FcMatchFont); - - FcResult result = FcResultMatch; - FcFontSet *fontSet = FcFontSort(0,pattern,FcFalse,0,&result); - - if (fontSet && result == FcResultMatch) - { - for (int i = 0; i < fontSet->nfont; i++) { - FcChar8 *value = 0; - if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch) - continue; - // capitalize(value); - QString familyName = QString::fromUtf8((const char *)value); - if (!fallbackFamilies.contains(familyName,Qt::CaseInsensitive)) { - fallbackFamilies << familyName; - } - - } - } -// qDebug() << "fallbackFamilies for:" << family << fallbackFamilies; - - return fallbackFamilies; -} diff --git a/src/plugins/platforms/fontdatabases/genericunix/genericunix.pri b/src/plugins/platforms/fontdatabases/genericunix/genericunix.pri deleted file mode 100644 index 1153ab36b7..0000000000 --- a/src/plugins/platforms/fontdatabases/genericunix/genericunix.pri +++ /dev/null @@ -1,10 +0,0 @@ -contains(QT_CONFIG, fontconfig) { - include(../fontconfig/fontconfig.pri) - DEFINES += Q_FONTCONFIGDATABASE -} else { - include(../basicunix/basicunix.pri) -} - -INCLUDEPATH += $$PWD -HEADERS += \ - $$PWD/qgenericunixfontdatabase.h diff --git a/src/plugins/platforms/fontdatabases/genericunix/qgenericunixfontdatabase.h b/src/plugins/platforms/fontdatabases/genericunix/qgenericunixfontdatabase.h deleted file mode 100644 index 8bf542a215..0000000000 --- a/src/plugins/platforms/fontdatabases/genericunix/qgenericunixfontdatabase.h +++ /dev/null @@ -1,53 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGENERICUNIXFONTDATABASE_H -#define QGENERICUNIXFONTDATABASE_H - -#ifdef Q_FONTCONFIGDATABASE -#include "qfontconfigdatabase.h" -typedef QFontconfigDatabase QGenericUnixFontDatabase; -#else -#include "qbasicunixfontdatabase.h" -typedef QBasicUnixFontDatabase QGenericUnixFontDatabase; -#endif //Q_FONTCONFIGDATABASE - -#endif // QGENERICUNIXFONTDATABASE_H diff --git a/src/plugins/platforms/glxconvenience/glxconvenience.pri b/src/plugins/platforms/glxconvenience/glxconvenience.pri deleted file mode 100644 index b4d43a30b5..0000000000 --- a/src/plugins/platforms/glxconvenience/glxconvenience.pri +++ /dev/null @@ -1,15 +0,0 @@ -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/qglxconvenience.h - -SOURCES += \ - $$PWD/qglxconvenience.cpp - -CONFIG += xrender - -xrender { - LIBS += -lXrender -} else { - DEFINES += QT_NO_XRENDER -} diff --git a/src/plugins/platforms/glxconvenience/qglxconvenience.cpp b/src/plugins/platforms/glxconvenience/qglxconvenience.cpp deleted file mode 100644 index 34633d9692..0000000000 --- a/src/plugins/platforms/glxconvenience/qglxconvenience.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qglxconvenience.h" - -#include <QtCore/QVector> - -#ifndef QT_NO_XRENDER -#include <X11/extensions/Xrender.h> -#endif - -enum { - XFocusOut = FocusOut, - XFocusIn = FocusIn, - XKeyPress = KeyPress, - XKeyRelease = KeyRelease, - XNone = None, - XRevertToParent = RevertToParent, - XGrayScale = GrayScale, - XCursorShape = CursorShape -}; -#undef FocusOut -#undef FocusIn -#undef KeyPress -#undef KeyRelease -#undef None -#undef RevertToParent -#undef GrayScale -#undef CursorShape - -#ifdef FontChange -#undef FontChange -#endif - -QVector<int> qglx_buildSpec(const QPlatformWindowFormat &format, int drawableBit) -{ - QVector<int> spec(48); - int i = 0; - - spec[i++] = GLX_LEVEL; - spec[i++] = 0; - spec[i++] = GLX_DRAWABLE_TYPE; spec[i++] = drawableBit; - - if (format.rgba()) { - spec[i++] = GLX_RENDER_TYPE; spec[i++] = GLX_RGBA_BIT; - spec[i++] = GLX_RED_SIZE; spec[i++] = (format.redBufferSize() == -1) ? 1 : format.redBufferSize(); - spec[i++] = GLX_GREEN_SIZE; spec[i++] = (format.greenBufferSize() == -1) ? 1 : format.greenBufferSize(); - spec[i++] = GLX_BLUE_SIZE; spec[i++] = (format.blueBufferSize() == -1) ? 1 : format.blueBufferSize(); - if (format.alpha()) { - spec[i++] = GLX_ALPHA_SIZE; spec[i++] = (format.alphaBufferSize() == -1) ? 1 : format.alphaBufferSize(); - } - - if (format.accum()) { - spec[i++] = GLX_ACCUM_RED_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); - spec[i++] = GLX_ACCUM_GREEN_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); - spec[i++] = GLX_ACCUM_BLUE_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); - - if (format.alpha()) { - spec[i++] = GLX_ACCUM_ALPHA_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize(); - } - } - } else { - spec[i++] = GLX_RENDER_TYPE; spec[i++] = GLX_COLOR_INDEX_BIT; //I'm really not sure if this works.... - spec[i++] = GLX_BUFFER_SIZE; spec[i++] = 8; - } - - spec[i++] = GLX_DOUBLEBUFFER; spec[i++] = format.doubleBuffer() ? True : False; - spec[i++] = GLX_STEREO; spec[i++] = format.stereo() ? True : False; - - if (format.depth()) { - spec[i++] = GLX_DEPTH_SIZE; spec[i++] = (format.depthBufferSize() == -1) ? 1 : format.depthBufferSize(); - } - - if (format.stencil()) { - spec[i++] = GLX_STENCIL_SIZE; spec[i++] = (format.stencilBufferSize() == -1) ? 1 : format.stencilBufferSize(); - } - if (format.sampleBuffers()) { - spec[i++] = GLX_SAMPLE_BUFFERS_ARB; - spec[i++] = 1; - spec[i++] = GLX_SAMPLES_ARB; - spec[i++] = format.samples() == -1 ? 4 : format.samples(); - } - - spec[i++] = XNone; - return spec; -} - -GLXFBConfig qglx_findConfig(Display *display, int screen , const QPlatformWindowFormat &format, int drawableBit) -{ - bool reduced = true; - GLXFBConfig chosenConfig = 0; - QPlatformWindowFormat reducedFormat = format; - while (!chosenConfig && reduced) { - QVector<int> spec = qglx_buildSpec(reducedFormat, drawableBit); - int confcount = 0; - GLXFBConfig *configs; - configs = glXChooseFBConfig(display, screen,spec.constData(),&confcount); - if (confcount) - { - for (int i = 0; i < confcount; i++) { - chosenConfig = configs[i]; - // Make sure we try to get an ARGB visual if the format asked for an alpha: - if (reducedFormat.alpha()) { - int alphaSize; - glXGetFBConfigAttrib(display,configs[i],GLX_ALPHA_SIZE,&alphaSize); - if (alphaSize > 0) { - XVisualInfo *visual = glXGetVisualFromFBConfig(display, chosenConfig); -#if !defined(QT_NO_XRENDER) - XRenderPictFormat *pictFormat = XRenderFindVisualFormat(display, visual->visual); - if (pictFormat->direct.alphaMask > 0) - break; -#else - if (visual->depth == 32) - break; -#endif - } - } else { - break; // Just choose the first in the list if there's no alpha requested - } - } - - XFree(configs); - } - reducedFormat = qglx_reducePlatformWindowFormat(reducedFormat,&reduced); - } - - if (!chosenConfig) - qWarning("Warning: no suitable glx confiuration found"); - - return chosenConfig; -} - -XVisualInfo *qglx_findVisualInfo(Display *display, int screen, const QPlatformWindowFormat &format) -{ - GLXFBConfig config = qglx_findConfig(display,screen,format); - XVisualInfo *visualInfo = glXGetVisualFromFBConfig(display,config); - return visualInfo; -} - -QPlatformWindowFormat qglx_platformWindowFromGLXFBConfig(Display *display, GLXFBConfig config, GLXContext ctx) -{ - QPlatformWindowFormat format; - int redSize = 0; - int greenSize = 0; - int blueSize = 0; - int alphaSize = 0; - int depthSize = 0; - int stencilSize = 0; - int sampleBuffers = 0; - int sampleCount = 0; - int level = 0; - int rgba = 0; - int stereo = 0; - int accumSizeA = 0; - int accumSizeR = 0; - int accumSizeG = 0; - int accumSizeB = 0; - - XVisualInfo *vi = glXGetVisualFromFBConfig(display,config); - glXGetConfig(display,vi,GLX_RGBA,&rgba); - XFree(vi); - glXGetFBConfigAttrib(display, config, GLX_RED_SIZE, &redSize); - glXGetFBConfigAttrib(display, config, GLX_GREEN_SIZE, &greenSize); - glXGetFBConfigAttrib(display, config, GLX_BLUE_SIZE, &blueSize); - glXGetFBConfigAttrib(display, config, GLX_ALPHA_SIZE, &alphaSize); - glXGetFBConfigAttrib(display, config, GLX_DEPTH_SIZE, &depthSize); - glXGetFBConfigAttrib(display, config, GLX_STENCIL_SIZE, &stencilSize); - glXGetFBConfigAttrib(display, config, GLX_SAMPLES, &sampleBuffers); - glXGetFBConfigAttrib(display, config, GLX_LEVEL, &level); - glXGetFBConfigAttrib(display, config, GLX_STEREO, &stereo); - glXGetFBConfigAttrib(display, config, GLX_ACCUM_ALPHA_SIZE, &accumSizeA); - glXGetFBConfigAttrib(display, config, GLX_ACCUM_RED_SIZE, &accumSizeR); - glXGetFBConfigAttrib(display, config, GLX_ACCUM_GREEN_SIZE, &accumSizeG); - glXGetFBConfigAttrib(display, config, GLX_ACCUM_BLUE_SIZE, &accumSizeB); - - format.setRedBufferSize(redSize); - format.setGreenBufferSize(greenSize); - format.setBlueBufferSize(blueSize); - format.setAlphaBufferSize(alphaSize); - format.setDepthBufferSize(depthSize); - format.setStencilBufferSize(stencilSize); - format.setSampleBuffers(sampleBuffers); - if (format.sampleBuffers()) { - glXGetFBConfigAttrib(display, config, GLX_SAMPLES_ARB, &sampleCount); - format.setSamples(sampleCount); - } - - format.setDirectRendering(glXIsDirect(display, ctx)); - format.setRgba(rgba); - format.setStereo(stereo); - format.setAccumBufferSize(accumSizeB); - - return format; -} - -QPlatformWindowFormat qglx_reducePlatformWindowFormat(const QPlatformWindowFormat &format, bool *reduced) -{ - QPlatformWindowFormat retFormat = format; - *reduced = true; - - if (retFormat.sampleBuffers()) { - retFormat.setSampleBuffers(false); - } else if (retFormat.stereo()) { - retFormat.setStereo(false); - } else if (retFormat.accum()) { - retFormat.setAccum(false); - }else if (retFormat.stencil()) { - retFormat.setStencil(false); - }else if (retFormat.alpha()) { - retFormat.setAlpha(false); - }else if (retFormat.depth()) { - retFormat.setDepth(false); - }else if (retFormat.doubleBuffer()) { - retFormat.setDoubleBuffer(false); - }else{ - *reduced = false; - } - return retFormat; -} diff --git a/src/plugins/platforms/minimal/qminimalintegration.cpp b/src/plugins/platforms/minimal/qminimalintegration.cpp index b9ab528b50..23bade99b6 100644 --- a/src/plugins/platforms/minimal/qminimalintegration.cpp +++ b/src/plugins/platforms/minimal/qminimalintegration.cpp @@ -69,14 +69,14 @@ QPixmapData *QMinimalIntegration::createPixmapData(QPixmapData::PixelType type) return new QRasterPixmapData(type); } -QPlatformWindow *QMinimalIntegration::createPlatformWindow(QWidget *widget, WId winId) const +QPlatformWindow *QMinimalIntegration::createPlatformWindow(QWindow *window) const { - Q_UNUSED(winId); - return new QPlatformWindow(widget); + Q_UNUSED(window); + return new QPlatformWindow(window); } -QWindowSurface *QMinimalIntegration::createWindowSurface(QWidget *widget, WId winId) const +QWindowSurface *QMinimalIntegration::createWindowSurface(QWindow *window, WId winId) const { Q_UNUSED(winId); - return new QMinimalWindowSurface(widget); + return new QMinimalWindowSurface(window); } diff --git a/src/plugins/platforms/minimal/qminimalintegration.h b/src/plugins/platforms/minimal/qminimalintegration.h index d1fcc42c68..6ac45c2385 100644 --- a/src/plugins/platforms/minimal/qminimalintegration.h +++ b/src/plugins/platforms/minimal/qminimalintegration.h @@ -72,8 +72,8 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const; QPixmapData *createPixmapData(QPixmapData::PixelType type) const; - QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId) const; - QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const; + QPlatformWindow *createPlatformWindow(QWindow *window) const; + QWindowSurface *createWindowSurface(QWindow *window, WId winId) const; QList<QPlatformScreen *> screens() const { return mScreens; } diff --git a/src/plugins/platforms/minimal/qminimalwindowsurface.cpp b/src/plugins/platforms/minimal/qminimalwindowsurface.cpp index 91c68d1d2d..f28b34a000 100644 --- a/src/plugins/platforms/minimal/qminimalwindowsurface.cpp +++ b/src/plugins/platforms/minimal/qminimalwindowsurface.cpp @@ -42,11 +42,11 @@ #include "qminimalwindowsurface.h" #include <QtCore/qdebug.h> -#include <QtGui/private/qapplication_p.h> +#include <private/qguiapplication_p.h> QT_BEGIN_NAMESPACE -QMinimalWindowSurface::QMinimalWindowSurface(QWidget *window) +QMinimalWindowSurface::QMinimalWindowSurface(QWindow *window) : QWindowSurface(window) { //qDebug() << "QMinimalWindowSurface::QMinimalWindowSurface:" << (long)this; @@ -62,9 +62,9 @@ QPaintDevice *QMinimalWindowSurface::paintDevice() return &mImage; } -void QMinimalWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +void QMinimalWindowSurface::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) { - Q_UNUSED(widget); + Q_UNUSED(window); Q_UNUSED(region); Q_UNUSED(offset); @@ -78,7 +78,7 @@ void QMinimalWindowSurface::resize(const QSize &size) { //qDebug() << "QMinimalWindowSurface::setGeometry:" << (long)this << rect; QWindowSurface::resize(size); - QImage::Format format = QApplicationPrivate::platformIntegration()->screens().first()->format(); + QImage::Format format = QGuiApplicationPrivate::platformIntegration()->screens().first()->format(); if (mImage.size() != size) mImage = QImage(size, format); } diff --git a/src/plugins/platforms/minimal/qminimalwindowsurface.h b/src/plugins/platforms/minimal/qminimalwindowsurface.h index 2c6196a19a..943cdc43e1 100644 --- a/src/plugins/platforms/minimal/qminimalwindowsurface.h +++ b/src/plugins/platforms/minimal/qminimalwindowsurface.h @@ -45,17 +45,18 @@ #include <QtGui/private/qwindowsurface_p.h> #include <QtGui/QPlatformWindow> +#include <QtGui/QImage> QT_BEGIN_NAMESPACE class QMinimalWindowSurface : public QWindowSurface { public: - QMinimalWindowSurface(QWidget *window); + QMinimalWindowSurface(QWindow *window); ~QMinimalWindowSurface(); QPaintDevice *paintDevice(); - void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); void resize(const QSize &size); private: diff --git a/src/plugins/platforms/openkode/qopenkodewindow.cpp b/src/plugins/platforms/openkode/qopenkodewindow.cpp index c6fe6d0176..2215cd0a92 100644 --- a/src/plugins/platforms/openkode/qopenkodewindow.cpp +++ b/src/plugins/platforms/openkode/qopenkodewindow.cpp @@ -53,7 +53,7 @@ #include <EGL/egl.h> -#include <QtGui/qwidget.h> +#include <QtWidgets/qwidget.h> #include <QtGui/private/qwidget_p.h> #include <QtGui/private/qapplication_p.h> diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro index 492569796f..9d7ae296a9 100644 --- a/src/plugins/platforms/platforms.pro +++ b/src/plugins/platforms/platforms.pro @@ -9,3 +9,7 @@ contains(QT_CONFIG, wayland) { contains(QT_CONFIG, xcb) { SUBDIRS += xcb } + +mac { + SUBDIRS += cocoa +} diff --git a/src/plugins/platforms/uikit/uikit.pro b/src/plugins/platforms/uikit/uikit.pro index 45a48dc92a..5e3a0e6b7c 100644 --- a/src/plugins/platforms/uikit/uikit.pro +++ b/src/plugins/platforms/uikit/uikit.pro @@ -1,5 +1,5 @@ TARGET = quikit -load(qt_plugin) +load(qpa/plugin) QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms QT += opengl @@ -22,6 +22,6 @@ HEADERS = quikitsoftwareinputhandler.h #add libz for freetype. LIBS += -lz -#include(../fontdatabases/basicunix/basicunix.pri) +#load(qpa/fontdatabases/basicunix) target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target diff --git a/src/plugins/platforms/vnc/qvncserver.cpp b/src/plugins/platforms/vnc/qvncserver.cpp index 8b25e054d1..37412b6bd1 100644 --- a/src/plugins/platforms/vnc/qvncserver.cpp +++ b/src/plugins/platforms/vnc/qvncserver.cpp @@ -43,7 +43,7 @@ #include <QtCore/qtimer.h> #include <QtCore/qregexp.h> -#include <QtGui/qwidget.h> +#include <QtWidgets/qwidget.h> #include <QtGui/qpolygon.h> #include <QtGui/qpainter.h> diff --git a/src/plugins/platforms/wayland/gl_integration/qwaylandglintegration.h b/src/plugins/platforms/wayland/gl_integration/qwaylandglintegration.h index 4b50b4bd68..2960d64eea 100644 --- a/src/plugins/platforms/wayland/gl_integration/qwaylandglintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/qwaylandglintegration.h @@ -44,7 +44,10 @@ class QWaylandWindow; class QWaylandDisplay; -class QWidget; +class QWindow; + +class QPlatformGLContext; +class QGuiGLFormat; class QWaylandGLIntegration { @@ -54,7 +57,8 @@ public: virtual void initialize() = 0; - virtual QWaylandWindow *createEglWindow(QWidget *widget) = 0; + virtual QWaylandWindow *createEglWindow(QWindow *window) = 0; + virtual QPlatformGLContext *createPlatformGLContext(const QGuiGLFormat &glFormat, QPlatformGLContext *share) const = 0; static QWaylandGLIntegration *createGLIntegration(QWaylandDisplay *waylandDisplay); }; diff --git a/src/plugins/platforms/wayland/gl_integration/qwaylandglwindowsurface.cpp b/src/plugins/platforms/wayland/gl_integration/qwaylandglwindowsurface.cpp index a638fccf1e..1d6e79e94c 100644 --- a/src/plugins/platforms/wayland/gl_integration/qwaylandglwindowsurface.cpp +++ b/src/plugins/platforms/wayland/gl_integration/qwaylandglwindowsurface.cpp @@ -47,6 +47,7 @@ #include <QtOpenGL/QGLFramebufferObject> #include <QtOpenGL/QGLContext> +#include <QPlatformGLContext> #include <QtOpenGL/private/qglengineshadermanager_p.h> @@ -133,17 +134,18 @@ static void blitTexture(QGLContext *ctx, GLuint texture, const QSize &viewport, drawTexture(r, texture, texSize, sourceRect); } -QWaylandGLWindowSurface::QWaylandGLWindowSurface(QWidget *window) +QWaylandGLWindowSurface::QWaylandGLWindowSurface(QWindow *window) : QWindowSurface(window) - , mDisplay(QWaylandScreen::waylandScreenFromWidget(window)->display()) + , mDisplay(QWaylandScreen::waylandScreenFromWindow(window)->display()) , mPaintDevice(0) + , mContext(0) { - } QWaylandGLWindowSurface::~QWaylandGLWindowSurface() { delete mPaintDevice; + delete mContext; } QPaintDevice *QWaylandGLWindowSurface::paintDevice() @@ -151,32 +153,38 @@ QPaintDevice *QWaylandGLWindowSurface::paintDevice() return mPaintDevice; } +QGuiGLContext *QWaylandGLWindowSurface::context() const +{ + if (!mContext) + const_cast<QGuiGLContext *&>(mContext) = new QGuiGLContext(window()->glFormat()); + return mContext; +} + void QWaylandGLWindowSurface::beginPaint(const QRegion &) { - window()->platformWindow()->glContext()->makeCurrent(); - glClearColor(0,0,0,0xff); + context()->makeCurrent(window()->glSurface()); + glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); } -void QWaylandGLWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +void QWaylandGLWindowSurface::flush(QWindow *, const QRegion ®ion, const QPoint &offset) { Q_UNUSED(offset); Q_UNUSED(region); - QWaylandWindow *ww = (QWaylandWindow *) widget->platformWindow(); if (mPaintDevice->isBound()) mPaintDevice->release(); QRect rect(0,0,size().width(),size().height()); - QGLContext *ctx = QGLContext::fromPlatformGLContext(ww->glContext()); + QGLContext *ctx = QGLContext::fromGuiGLContext(context()); blitTexture(ctx,mPaintDevice->texture(),size(),mPaintDevice->size(),rect,rect); - ww->glContext()->swapBuffers(); + context()->swapBuffers(window()->glSurface()); } void QWaylandGLWindowSurface::resize(const QSize &size) { QWindowSurface::resize(size); - window()->platformWindow()->glContext()->makeCurrent(); + context()->makeCurrent(window()->glSurface()); delete mPaintDevice; mPaintDevice = new QGLFramebufferObject(size); } diff --git a/src/plugins/platforms/wayland/gl_integration/qwaylandglwindowsurface.h b/src/plugins/platforms/wayland/gl_integration/qwaylandglwindowsurface.h index 00da6976b8..3703869a60 100644 --- a/src/plugins/platforms/wayland/gl_integration/qwaylandglwindowsurface.h +++ b/src/plugins/platforms/wayland/gl_integration/qwaylandglwindowsurface.h @@ -51,19 +51,22 @@ class QGLFramebufferObject; class QWaylandGLWindowSurface : public QWindowSurface { public: - QWaylandGLWindowSurface(QWidget *window); + QWaylandGLWindowSurface(QWindow *window); ~QWaylandGLWindowSurface(); void beginPaint(const QRegion &); QPaintDevice *paintDevice(); - void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); void resize(const QSize &size); + QGuiGLContext *context() const; + private: QWaylandDisplay *mDisplay; QGLFramebufferObject *mPaintDevice; + QGuiGLContext *mContext; }; #endif // QWAYLANDDRMSURFACE_H diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.cpp b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.cpp index f02a10a05b..8769752d5f 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.cpp @@ -43,12 +43,14 @@ #include "../../../eglconvenience/qeglconvenience.h" +#include <QtCore/QDebug> +#include <QtGui/QWindowContext> + #include <QtOpenGL/QGLContext> #include <QtOpenGL/private/qglextensions_p.h> #include "qwaylandshmsurface.h" -#include <QtCore/QDebug> static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type) { @@ -77,7 +79,7 @@ QWaylandReadbackEglContext::QWaylandReadbackEglContext(QWaylandReadbackEglIntegr , mWindow(window) , mBuffer(0) , mPixmap(0) - , mConfig(q_configFromQPlatformWindowFormat(eglIntegration->eglDisplay(),window->widget()->platformWindowFormat(),true,EGL_PIXMAP_BIT)) + , mConfig(q_configFromQWindowFormat(eglIntegration->eglDisplay(),window->window()->requestedWindowFormat(),true,EGL_PIXMAP_BIT)) , mPixmapSurface(EGL_NO_SURFACE) { QVector<EGLint> eglContextAttrs; @@ -97,8 +99,6 @@ QWaylandReadbackEglContext::~QWaylandReadbackEglContext() void QWaylandReadbackEglContext::makeCurrent() { - QPlatformGLContext::makeCurrent(); - mWindow->waitForFrameSync(); eglMakeCurrent(mEglIntegration->eglDisplay(),mPixmapSurface,mPixmapSurface,mContext); @@ -114,7 +114,7 @@ void QWaylandReadbackEglContext::swapBuffers() { eglSwapBuffers(mEglIntegration->eglDisplay(),mPixmapSurface); - if (QPlatformGLContext::currentContext() != this) { + if (QWindowContext::currentContext()->handle() != this) { makeCurrent(); } @@ -143,9 +143,9 @@ void * QWaylandReadbackEglContext::getProcAddress(const QString &procName) return (void *) eglGetProcAddress(procName.toLatin1().data()); } -QPlatformWindowFormat QWaylandReadbackEglContext::platformWindowFormat() const +QWindowFormat QWaylandReadbackEglContext::windowFormat() const { - return qt_qPlatformWindowFormatFromConfig(mEglIntegration->eglDisplay(),mConfig); + return q_windowFormatFromConfig(mEglIntegration->eglDisplay(),mConfig); } void QWaylandReadbackEglContext::geometryChanged() diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.h b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.h index f9ab3783dd..f57ac46667 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglcontext.h @@ -43,7 +43,6 @@ #define QWAYLANDREADBACKEGLGLCONTEXT_H #include <QPlatformGLContext> -#include <QtGui/QWidget> #include "qwaylandreadbackeglintegration.h" #include "qwaylandreadbackeglwindow.h" @@ -61,7 +60,7 @@ public: void swapBuffers(); void* getProcAddress(const QString& procName); - virtual QPlatformWindowFormat platformWindowFormat() const; + virtual QWindowFormat windowFormat() const; void geometryChanged(); diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.cpp b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.cpp index 6bbac603cf..7fbe5cc725 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.cpp @@ -81,9 +81,14 @@ void QWaylandReadbackEglIntegration::initialize() } } -QWaylandWindow * QWaylandReadbackEglIntegration::createEglWindow(QWidget *widget) +QWaylandWindow * QWaylandReadbackEglIntegration::createEglWindow(QWindow *window) { - return new QWaylandReadbackEglWindow(widget,this); + return new QWaylandReadbackEglWindow(window, this); +} + +QPlatformGLContext *QWaylandReadbackEglWindow::createPlatformGLContext(const QGuiGLFormat &glFormat, QPlatformGLContext *share) const +{ + return new QWaylandReadbackEglContext(glFormat, share, this); } EGLDisplay QWaylandReadbackEglIntegration::eglDisplay() diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.h b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.h index ae1e8e5095..8945cdab38 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglintegration.h @@ -48,7 +48,8 @@ #include <QtCore/QDataStream> #include <QtCore/QMetaType> #include <QtCore/QVariant> -#include <QtGui/QWidget> +#include <QtCore/QEvent> +#include <QtGui/QCursor> #include <X11/Xlib.h> @@ -61,7 +62,8 @@ public: ~QWaylandReadbackEglIntegration(); void initialize(); - QWaylandWindow *createEglWindow(QWidget *widget); + QWaylandWindow *createEglWindow(QWindow *window); + QPlatformGLContext *createPlatformGLContext(const QGuiGLFormat &glFormat, QPlatformGLContext *share) const; QWaylandDisplay *waylandDisplay() const; Display *xDisplay() const; diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.cpp b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.cpp index 868e32e030..39ccafec5c 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.cpp @@ -43,7 +43,7 @@ #include "qwaylandreadbackeglcontext.h" -QWaylandReadbackEglWindow::QWaylandReadbackEglWindow(QWidget *window, QWaylandReadbackEglIntegration *eglIntegration) +QWaylandReadbackEglWindow::QWaylandReadbackEglWindow(QWindow *window, QWaylandReadbackEglIntegration *eglIntegration) : QWaylandShmWindow(window) , mEglIntegration(eglIntegration) , mContext(0) diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.h b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.h index 1433483923..63ab7a55ae 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/qwaylandreadbackeglwindow.h @@ -50,7 +50,7 @@ class QWaylandReadbackEglContext; class QWaylandReadbackEglWindow : public QWaylandShmWindow { public: - QWaylandReadbackEglWindow(QWidget *window, QWaylandReadbackEglIntegration *eglIntegration); + QWaylandReadbackEglWindow(QWindow *window, QWaylandReadbackEglIntegration *eglIntegration); WindowType windowType() const; diff --git a/src/plugins/platforms/wayland/gl_integration/readback_egl/readback_egl.pri b/src/plugins/platforms/wayland/gl_integration/readback_egl/readback_egl.pri index 0d8e01b6bb..3325fe8ec9 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_egl/readback_egl.pri +++ b/src/plugins/platforms/wayland/gl_integration/readback_egl/readback_egl.pri @@ -1,14 +1,12 @@ - LIBS += -lX11 -lXext -lEGL +load(qpa/egl/convenience) HEADERS += \ $$PWD/qwaylandreadbackeglintegration.h \ $$PWD/qwaylandreadbackeglcontext.h \ $$PWD/qwaylandreadbackeglwindow.h \ - $$PWD/../../../eglconvenience/qeglconvenience.h SOURCES += \ $$PWD/qwaylandreadbackeglintegration.cpp \ $$PWD/qwaylandreadbackeglwindow.cpp \ $$PWD/qwaylandreadbackeglcontext.cpp \ - $$PWD/../../../eglconvenience/qeglconvenience.cpp diff --git a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.cpp b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.cpp index 857c1db6e3..54b7d322f8 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.cpp @@ -44,8 +44,19 @@ #include "qwaylandshmsurface.h" #include "qwaylandreadbackglxwindow.h" +#include <QtGui/QGuiGLContext> #include <QtCore/QDebug> +QWaylandReadbackGlxSurface::QWaylandReadbackGlxSurface(QWaylandReadbackGlxWindow *window) + : m_window(window) +{ +} + +GLXPixmap QWaylandReadbackGlxSurface::glxPixmap() const +{ + return m_window->glxPixmap(); +} + static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type) { const int width = img.width(); @@ -68,96 +79,66 @@ static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type) } } -QWaylandReadbackGlxContext::QWaylandReadbackGlxContext(QWaylandReadbackGlxIntegration *glxIntegration, QWaylandReadbackGlxWindow *window) - : QPlatformGLContext() - , mGlxIntegration(glxIntegration) - , mWindow(window) - , mBuffer(0) - , mPixmap(0) - , mConfig(qglx_findConfig(glxIntegration->xDisplay(),glxIntegration->screen(),window->widget()->platformWindowFormat(),GLX_PIXMAP_BIT)) - , mGlxPixmap(0) +QWaylandReadbackGlxContext::QWaylandReadbackGlxContext(const QGuiGLFormat &format, + QPlatformGLContext *share, Display *display, int screen) + : m_display(display) { - XVisualInfo *visualInfo = glXGetVisualFromFBConfig(glxIntegration->xDisplay(),mConfig); - mContext = glXCreateContext(glxIntegration->xDisplay(),visualInfo,0,TRUE); + GLXFBConfig config = qglx_findConfig(display, screen, format, GLX_PIXMAP_BIT); + + GLXContext shareContext = share ? static_cast<QWaylandReadbackGlxContext *>(share)->m_context : 0; - geometryChanged(); + XVisualInfo *visualInfo = glXGetVisualFromFBConfig(display, config); + m_context = glXCreateContext(display, visualInfo, shareContext, TRUE); + m_format = qglx_guiGLFormatFromGLXFBConfig(display, config, m_context); } -void QWaylandReadbackGlxContext::makeCurrent() +QGuiGLFormat QWaylandReadbackGlxContext::format() const { - QPlatformGLContext::makeCurrent(); + return m_format; +} + +bool QWaylandReadbackGlxContext::makeCurrent(const QPlatformGLSurface &surface) +{ + GLXPixmap glxPixmap = static_cast<const QWaylandReadbackGlxSurface &>(surface).glxPixmap(); - glXMakeCurrent(mGlxIntegration->xDisplay(),mGlxPixmap,mContext); + return glXMakeCurrent(m_display, glxPixmap, m_context); } void QWaylandReadbackGlxContext::doneCurrent() { - QPlatformGLContext::doneCurrent(); + glXMakeCurrent(m_display, 0, 0); } -void QWaylandReadbackGlxContext::swapBuffers() +void QWaylandReadbackGlxContext::swapBuffers(const QPlatformGLSurface &surface) { - if (QPlatformGLContext::currentContext() != this) { - makeCurrent(); - } + // #### makeCurrent() directly on the platform context doesn't update QGuiGLContext::currentContext() + if (QGuiGLContext::currentContext()->handle() != this) + makeCurrent(surface, surface); - QSize size = mWindow->geometry().size(); + const QWaylandReadbackGlxSurface &s = + static_cast<const QWaylandReadbackGlxSurface &>(surface); - QImage img(size,QImage::Format_ARGB32); + QSize size = s.window()->geometry().size(); + + QImage img(size, QImage::Format_ARGB32); const uchar *constBits = img.bits(); void *pixels = const_cast<uchar *>(constBits); - glReadPixels(0,0, size.width(), size.height(), GL_RGBA,GL_UNSIGNED_BYTE, pixels); + glReadPixels(0, 0, size.width(), size.height(), GL_RGBA,GL_UNSIGNED_BYTE, pixels); img = img.mirrored(); - qgl_byteSwapImage(img,GL_UNSIGNED_INT_8_8_8_8_REV); + qgl_byteSwapImage(img, GL_UNSIGNED_INT_8_8_8_8_REV); constBits = img.bits(); - const uchar *constDstBits = mBuffer->image()->bits(); + const uchar *constDstBits = s.window()->buffer(); uchar *dstBits = const_cast<uchar *>(constDstBits); - memcpy(dstBits,constBits,(img.width()*4) * img.height()); - - - mWindow->damage(QRegion(QRect(QPoint(0,0),size))); - mWindow->waitForFrameSync(); + memcpy(dstBits, constBits, (img.width() * 4) * img.height()); + s.window()->damage(QRect(QPoint(), size)); + s.window()->waitForFrameSync(); } -void * QWaylandReadbackGlxContext::getProcAddress(const QString &procName) +void (*QWaylandReadbackGlxContext::getProcAddress(const QByteArray &procName)) () { - return (void *) glXGetProcAddress(reinterpret_cast<GLubyte *>(procName.toLatin1().data())); -} - -QPlatformWindowFormat QWaylandReadbackGlxContext::platformWindowFormat() const -{ - return qglx_platformWindowFromGLXFBConfig(mGlxIntegration->xDisplay(),mConfig,mContext); -} - -void QWaylandReadbackGlxContext::geometryChanged() -{ - QSize size(mWindow->geometry().size()); - if (size.isEmpty()) { - //QGLWidget wants a context for a window without geometry - size = QSize(1,1); - } - - mWindow->waitForFrameSync(); - - delete mBuffer; - //XFreePixmap deletes the glxPixmap as well - if (mPixmap) { - XFreePixmap(mGlxIntegration->xDisplay(),mPixmap); - } - - mBuffer = new QWaylandShmBuffer(mGlxIntegration->waylandDisplay(),size,QImage::Format_ARGB32); - mWindow->attach(mBuffer); - int depth = XDefaultDepth(mGlxIntegration->xDisplay(),mGlxIntegration->screen()); - mPixmap = XCreatePixmap(mGlxIntegration->xDisplay(),mGlxIntegration->rootWindow(),size.width(),size.height(),depth); - XSync(mGlxIntegration->xDisplay(),False); - - mGlxPixmap = glXCreatePixmap(mGlxIntegration->xDisplay(),mConfig,mPixmap,0); - - if (!mGlxPixmap) { - qDebug() << "Could not make egl surface out of pixmap :("; - } + return glXGetProcAddress(reinterpret_cast<const GLubyte *>(procName.constData())); } diff --git a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.h b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.h index 07e0f620de..27a7287b07 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxcontext.h @@ -43,6 +43,7 @@ #define QWAYLANDREADBACKGLXCONTEXT_H #include <QPlatformGLContext> +#include <QGuiGLFormat> #include "qwaylandreadbackglxintegration.h" @@ -51,29 +52,37 @@ class QWaylandReadbackGlxWindow; class QWaylandShmBuffer; +class QWaylandReadbackGlxSurface : public QPlatformGLSurface +{ +public: + QWaylandReadbackGlxSurface(QWaylandReadbackGlxWindow *window); + + QWaylandReadbackGlxWindow *window() const { return m_window; } + GLXPixmap glxPixmap() const; + +private: + QWaylandReadbackGlxWindow *m_window; +}; + class QWaylandReadbackGlxContext : public QPlatformGLContext { public: - QWaylandReadbackGlxContext(QWaylandReadbackGlxIntegration *glxIntegration, QWaylandReadbackGlxWindow *window); + QWaylandReadbackGlxContext(const QGuiGLFormat &format, QPlatformGLContext *share, Display *display, int screen); - void makeCurrent(); - void doneCurrent(); - void swapBuffers(); - void* getProcAddress(const QString& procName); + QGuiGLFormat format() const; - QPlatformWindowFormat platformWindowFormat() const; + void swapBuffers(const QPlatformGLSurface &surface); - void geometryChanged(); + bool makeCurrent(const QPlatformGLSurface &surface); + void doneCurrent(); + + void (*getProcAddress(const QByteArray &procName)) (); private: - QWaylandReadbackGlxIntegration *mGlxIntegration; - QWaylandReadbackGlxWindow *mWindow; - QWaylandShmBuffer *mBuffer; - - Pixmap mPixmap; - GLXFBConfig mConfig; - GLXContext mContext; - GLXPixmap mGlxPixmap; + GLXContext m_context; + + Display *m_display; + QGuiGLFormat m_format; }; #endif // QWAYLANDREADBACKGLXCONTEXT_H diff --git a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.cpp b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.cpp index 37a14a9f4c..6fb2a178c8 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.cpp @@ -66,9 +66,14 @@ void QWaylandReadbackGlxIntegration::initialize() { } -QWaylandWindow * QWaylandReadbackGlxIntegration::createEglWindow(QWidget *widget) +QWaylandWindow * QWaylandReadbackGlxIntegration::createEglWindow(QWindow *window) { - return new QWaylandReadbackGlxWindow(widget,this); + return new QWaylandReadbackGlxWindow(window,this); +} + +QPlatformGLContext *QWaylandReadbackGlxIntegration::createPlatformGLContext(const QGuiGLFormat &glFormat, QPlatformGLContext *share) const +{ + return new QWaylandReadbackGlxContext(glFormat, share, mDisplay, mScreen); } QWaylandGLIntegration * QWaylandGLIntegration::createGLIntegration(QWaylandDisplay *waylandDisplay) diff --git a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.h b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.h index d267d8dffe..0b3d0cc2cc 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxintegration.h @@ -48,7 +48,7 @@ #include <QtCore/QDataStream> #include <QtCore/QMetaType> #include <QtCore/QVariant> -#include <QtGui/QWidget> +#include <QtGui/QWindow> #include <X11/Xlib.h> @@ -60,7 +60,8 @@ public: void initialize(); - QWaylandWindow *createEglWindow(QWidget *widget); + QWaylandWindow *createEglWindow(QWindow *window); + QPlatformGLContext *createPlatformGLContext(const QGuiGLFormat &glFormat, QPlatformGLContext *share) const; QWaylandDisplay *waylandDisplay() const; diff --git a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxwindow.cpp b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxwindow.cpp index 98198dfa06..f878bef0c4 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxwindow.cpp +++ b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxwindow.cpp @@ -39,12 +39,19 @@ ** ****************************************************************************/ +#include <QtDebug> + #include "qwaylandreadbackglxwindow.h" -QWaylandReadbackGlxWindow::QWaylandReadbackGlxWindow(QWidget *window, QWaylandReadbackGlxIntegration *glxIntegration) +#include "qwaylandshmsurface.h" + +QWaylandReadbackGlxWindow::QWaylandReadbackGlxWindow(QWindow *window, QWaylandReadbackGlxIntegration *glxIntegration) : QWaylandShmWindow(window) - , mGlxIntegration(glxIntegration) - , mContext(0) + , m_glxIntegration(glxIntegration) + , m_buffer(0) + , m_pixmap(0) + , m_config(qglx_findConfig(glxIntegration->xDisplay(), glxIntegration->screen(), window->glFormat())) + , m_glxPixmap(0) { } @@ -54,20 +61,51 @@ QWaylandWindow::WindowType QWaylandReadbackGlxWindow::windowType() const return QWaylandWindow::Egl; } -QPlatformGLContext * QWaylandReadbackGlxWindow::glContext() const +void QWaylandReadbackGlxWindow::setGeometry(const QRect &rect) { - if (!mContext) { - QWaylandReadbackGlxWindow *that = const_cast<QWaylandReadbackGlxWindow *>(this); - that->mContext = new QWaylandReadbackGlxContext(mGlxIntegration,that); + QWaylandShmWindow::setGeometry(rect); + + if (m_pixmap) { + delete mBuffer; + //XFreePixmap deletes the glxPixmap as well + XFreePixmap(m_glxIntegration->xDisplay(), m_pixmap); + m_pixmap = 0; } - return mContext; } -void QWaylandReadbackGlxWindow::setGeometry(const QRect &rect) +GLXPixmap QWaylandReadbackGlxWindow::glxPixmap() const { - QWaylandShmWindow::setGeometry(rect); + if (!m_pixmap) + const_cast<QWaylandReadbackGlxWindow *>(this)->createSurface(); - if (mContext) { - mContext->geometryChanged(); + return m_glxPixmap; +} + +uchar *QWaylandReadbackGlxWindow::buffer() +{ + return m_buffer->image()->bits(); +} + +void QWaylandReadbackGlxWindow::createSurface() +{ + QSize size(geometry().size()); + if (size.isEmpty()) { + //QGLWidget wants a context for a window without geometry + size = QSize(1,1); } + + waitForFrameSync(); + + m_buffer = new QWaylandShmBuffer(m_glxIntegration->waylandDisplay(), size, QImage::Format_ARGB32); + attach(m_buffer); + + int depth = XDefaultDepth(m_glxIntegration->xDisplay(), m_glxIntegration->screen()); + m_pixmap = XCreatePixmap(m_glxIntegration->xDisplay(), m_glxIntegration->rootWindow(), size.width(), size.height(), depth); + XSync(m_glxIntegration->xDisplay(), False); + + m_glxPixmap = glXCreatePixmap(m_glxIntegration->xDisplay(), m_config, m_pixmap,0); + + if (!m_glxPixmap) + qDebug() << "Could not make glx surface out of pixmap :("; } + diff --git a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxwindow.h b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxwindow.h index d478961d53..60b22a4408 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxwindow.h +++ b/src/plugins/platforms/wayland/gl_integration/readback_glx/qwaylandreadbackglxwindow.h @@ -49,17 +49,26 @@ class QWaylandReadbackGlxWindow : public QWaylandShmWindow { public: - QWaylandReadbackGlxWindow(QWidget *window, QWaylandReadbackGlxIntegration *glxIntegration); + QWaylandReadbackGlxWindow(QWindow *window, QWaylandReadbackGlxIntegration *glxIntegration); WindowType windowType() const; - QPlatformGLContext *glContext() const; + QPlatformGLSurface *createGLSurface() const; void setGeometry(const QRect &rect); + Pixmap glxPixmap() const; + + uchar *buffer(); + private: - QWaylandReadbackGlxIntegration *mGlxIntegration; - QWaylandReadbackGlxContext *mContext; + void createSurface(); + + QWaylandReadbackGlxIntegration *m_glxIntegration; + QWaylandShmBuffer *m_buffer; + Pixmap m_pixmap; + GLXFBConfig m_config; + GLXPixmap m_glxPixmap; }; #endif // QWAYLANDREADBACKGLXWINDOW_H diff --git a/src/plugins/platforms/wayland/gl_integration/readback_glx/readback_glx.pri b/src/plugins/platforms/wayland/gl_integration/readback_glx/readback_glx.pri index f8ea005937..dc84d1c9e9 100644 --- a/src/plugins/platforms/wayland/gl_integration/readback_glx/readback_glx.pri +++ b/src/plugins/platforms/wayland/gl_integration/readback_glx/readback_glx.pri @@ -1,4 +1,4 @@ -include (../../../glxconvenience/glxconvenience.pri) +load(qpa/glx/convenience) HEADERS += \ $$PWD/qwaylandreadbackglxintegration.h \ $$PWD/qwaylandreadbackglxwindow.h \ diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.cpp b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.cpp index d4deb01022..d5c2f62e44 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.cpp +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.cpp @@ -73,7 +73,7 @@ void QWaylandEglIntegration::initialize() } } -QWaylandWindow *QWaylandEglIntegration::createEglWindow(QWidget *window) +QWaylandWindow *QWaylandEglIntegration::createEglWindow(QWindow *window) { return new QWaylandEglWindow(window); } diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.h b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.h index ea8b0f725c..bc20b2cdb3 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglintegration.h @@ -47,7 +47,7 @@ #include "qwaylandeglinclude.h" class QWaylandWindow; -class QWidget; +class QWindow; class QWaylandEglIntegration : public QWaylandGLIntegration { @@ -57,7 +57,7 @@ public: void initialize(); - QWaylandWindow *createEglWindow(QWidget *window); + QWaylandWindow *createEglWindow(QWindow *window); EGLDisplay eglDisplay() const; struct wl_egl_display *nativeDisplay() const; diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglwindow.cpp b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglwindow.cpp index cd8b5b3524..4a085ae0bd 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglwindow.cpp +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglwindow.cpp @@ -44,7 +44,9 @@ #include "qwaylandscreen.h" #include "qwaylandglcontext.h" -QWaylandEglWindow::QWaylandEglWindow(QWidget *window) +#include <QtGui/QWindow> + +QWaylandEglWindow::QWaylandEglWindow(QWindow *window) : QWaylandWindow(window) , mGLContext(0) , mWaylandEglWindow(0) @@ -83,7 +85,7 @@ QPlatformGLContext * QWaylandEglWindow::glContext() const { if (!mGLContext) { QWaylandEglWindow *that = const_cast<QWaylandEglWindow *>(this); - that->mGLContext = new QWaylandGLContext(mEglIntegration->eglDisplay(),widget()->platformWindowFormat()); + that->mGLContext = new QWaylandGLContext(mEglIntegration->eglDisplay(),this->window()->requestedWindowFormat()); EGLNativeWindowType window(reinterpret_cast<EGLNativeWindowType>(mWaylandEglWindow)); EGLSurface surface = eglCreateWindowSurface(mEglIntegration->eglDisplay(),mGLContext->eglConfig(),window,NULL); @@ -98,7 +100,7 @@ void QWaylandEglWindow::newSurfaceCreated() if (mWaylandEglWindow) { wl_egl_window_destroy(mWaylandEglWindow); } - wl_visual *visual = QWaylandScreen::waylandScreenFromWidget(widget())->visual(); + wl_visual *visual = QWaylandScreen::waylandScreenFromWindow(window())->visual(); QSize size = geometry().size(); if (!size.isValid()) size = QSize(0,0); diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglwindow.h b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglwindow.h index 6d2038824a..343c50729b 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglwindow.h +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandeglwindow.h @@ -51,7 +51,7 @@ class QWaylandGLContext; class QWaylandEglWindow : public QWaylandWindow { public: - QWaylandEglWindow(QWidget *window); + QWaylandEglWindow(QWindow *window); ~QWaylandEglWindow(); WindowType windowType() const; void setGeometry(const QRect &rect); diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp index 72ad5a8b6a..0cff704ab1 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp @@ -47,22 +47,17 @@ #include "../../../eglconvenience/qeglconvenience.h" #include <QtGui/QPlatformGLContext> -#include <QtGui/QPlatformWindowFormat> +#include <QtGui/QWindowFormat> #include <QtCore/QMutex> -QWaylandGLContext::QWaylandGLContext(EGLDisplay eglDisplay, const QPlatformWindowFormat &format) +QWaylandGLContext::QWaylandGLContext(EGLDisplay eglDisplay, const QWindowFormat &format) : QPlatformGLContext() , mEglDisplay(eglDisplay) , mSurface(EGL_NO_SURFACE) - , mConfig(q_configFromQPlatformWindowFormat(mEglDisplay,format,true)) - , mFormat(qt_qPlatformWindowFormatFromConfig(mEglDisplay,mConfig)) + , mConfig(q_configFromQWindowFormat(mEglDisplay,format,true)) + , mFormat(q_windowFormatFromConfig(mEglDisplay,mConfig)) { - QPlatformGLContext *sharePlatformContext = 0; - sharePlatformContext = format.sharedGLContext(); - mFormat.setSharedContext(sharePlatformContext); EGLContext shareEGLContext = EGL_NO_CONTEXT; - if (sharePlatformContext) - shareEGLContext = static_cast<const QWaylandGLContext*>(sharePlatformContext)->mContext; eglBindAPI(EGL_OPENGL_ES_API); @@ -90,7 +85,6 @@ QWaylandGLContext::~QWaylandGLContext() void QWaylandGLContext::makeCurrent() { - QPlatformGLContext::makeCurrent(); if (mSurface == EGL_NO_SURFACE) { qWarning("makeCurrent with EGL_NO_SURFACE"); } diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.h b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.h index 2c6feb498c..47070f54b1 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.h +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.h @@ -53,14 +53,14 @@ class QWaylandGLWindowSurface; class QWaylandGLContext : public QPlatformGLContext { public: - QWaylandGLContext(EGLDisplay eglDisplay, const QPlatformWindowFormat &format); + QWaylandGLContext(EGLDisplay eglDisplay, const QWindowFormat &format); ~QWaylandGLContext(); void makeCurrent(); void doneCurrent(); void swapBuffers(); void* getProcAddress(const QString&); - QPlatformWindowFormat platformWindowFormat() const { return mFormat; } + QWindowFormat windowFormat() const { return mFormat; } void setEglSurface(EGLSurface surface); EGLConfig eglConfig() const; @@ -70,7 +70,7 @@ private: EGLContext mContext; EGLSurface mSurface; EGLConfig mConfig; - QPlatformWindowFormat mFormat; + QWindowFormat mFormat; QWaylandGLContext(); diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/wayland_egl.pri b/src/plugins/platforms/wayland/gl_integration/wayland_egl/wayland_egl.pri index cd0701150f..6f4edb08a6 100644 --- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/wayland_egl.pri +++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/wayland_egl.pri @@ -1,4 +1,4 @@ -include (../../../eglconvenience/eglconvenience.pri) +load(qpa/egl/convenience) LIBS += -lwayland-egl -lEGL INCLUDEPATH += $$PWD diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.cpp index 72de02a868..c5db44da4b 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.cpp @@ -42,128 +42,37 @@ #include "qwaylandxcompositeeglcontext.h" #include "qwaylandxcompositeeglwindow.h" -#include "qwaylandxcompositebuffer.h" -#include "wayland-xcomposite-client-protocol.h" #include <QtCore/QDebug> +#include <QtGui/QRegion> -#include "qeglconvenience.h" -#include "qxlibeglintegration.h" +#include "QtPlatformSupport/private/qeglconvenience_p.h" -#include <X11/extensions/Xcomposite.h> - -QWaylandXCompositeEGLContext::QWaylandXCompositeEGLContext(QWaylandXCompositeEGLIntegration *glxIntegration, QWaylandXCompositeEGLWindow *window) - : QPlatformGLContext() - , mEglIntegration(glxIntegration) - , mWindow(window) - , mBuffer(0) - , mXWindow(0) - , mConfig(q_configFromQPlatformWindowFormat(glxIntegration->eglDisplay(),window->widget()->platformWindowFormat(),true,EGL_WINDOW_BIT)) - , mWaitingForSync(false) -{ - QVector<EGLint> eglContextAttrs; - eglContextAttrs.append(EGL_CONTEXT_CLIENT_VERSION); eglContextAttrs.append(2); - eglContextAttrs.append(EGL_NONE); - - mContext = eglCreateContext(glxIntegration->eglDisplay(),mConfig,EGL_NO_CONTEXT,eglContextAttrs.constData()); - if (mContext == EGL_NO_CONTEXT) { - qFatal("failed to find context"); - } - - geometryChanged(); -} - -void QWaylandXCompositeEGLContext::makeCurrent() -{ - QPlatformGLContext::makeCurrent(); - - eglMakeCurrent(mEglIntegration->eglDisplay(),mEglWindowSurface,mEglWindowSurface,mContext); -} - -void QWaylandXCompositeEGLContext::doneCurrent() -{ - QPlatformGLContext::doneCurrent(); - eglMakeCurrent(mEglIntegration->eglDisplay(),EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT); -} - -void QWaylandXCompositeEGLContext::swapBuffers() -{ - QSize size = mWindow->geometry().size(); - - eglSwapBuffers(mEglIntegration->eglDisplay(),mEglWindowSurface); - mWindow->damage(QRegion(QRect(QPoint(0,0),size))); - mWindow->waitForFrameSync(); -} - -void * QWaylandXCompositeEGLContext::getProcAddress(const QString &procName) +QWaylandXCompositeEGLSurface::QWaylandXCompositeEGLSurface(QWaylandXCompositeEGLWindow *window) + : QEGLSurface(window->eglSurface(), window->window()->glFormat()) + , m_window(window) { - return (void *)eglGetProcAddress(qPrintable(procName)); } -QPlatformWindowFormat QWaylandXCompositeEGLContext::platformWindowFormat() const +EGLSurface QWaylandXCompositeEGLSurface::eglSurface() const { - return qt_qPlatformWindowFormatFromConfig(mEglIntegration->eglDisplay(),mConfig); + return m_window->eglSurface(); } -void QWaylandXCompositeEGLContext::sync_function(void *data) +QWaylandXCompositeEGLContext::QWaylandXCompositeEGLContext(const QGuiGLFormat &format, QPlatformGLContext *share, EGLDisplay display) + : QEGLPlatformContext(format, share, display) { - QWaylandXCompositeEGLContext *that = static_cast<QWaylandXCompositeEGLContext *>(data); - that->mWaitingForSync = false; } -void QWaylandXCompositeEGLContext::geometryChanged() +void QWaylandXCompositeEGLContext::swapBuffers(const QPlatformGLSurface &surface) { - QSize size(mWindow->geometry().size()); - if (size.isEmpty()) { - //QGLWidget wants a context for a window without geometry - size = QSize(1,1); - } - - delete mBuffer; - //XFreePixmap deletes the glxPixmap as well - if (mXWindow) { - XDestroyWindow(mEglIntegration->xDisplay(),mXWindow); - } - - VisualID visualId = QXlibEglIntegration::getCompatibleVisualId(mEglIntegration->xDisplay(),mEglIntegration->eglDisplay(),mConfig); - - XVisualInfo visualInfoTemplate; - memset(&visualInfoTemplate, 0, sizeof(XVisualInfo)); - visualInfoTemplate.visualid = visualId; - - int matchingCount = 0; - XVisualInfo *visualInfo = XGetVisualInfo(mEglIntegration->xDisplay(), VisualIDMask, &visualInfoTemplate, &matchingCount); - - Colormap cmap = XCreateColormap(mEglIntegration->xDisplay(),mEglIntegration->rootWindow(),visualInfo->visual,AllocNone); - - XSetWindowAttributes a; - a.colormap = cmap; - mXWindow = XCreateWindow(mEglIntegration->xDisplay(), mEglIntegration->rootWindow(),0, 0, size.width(), size.height(), - 0, visualInfo->depth, InputOutput, visualInfo->visual, - CWColormap, &a); - - XCompositeRedirectWindow(mEglIntegration->xDisplay(), mXWindow, CompositeRedirectManual); - XMapWindow(mEglIntegration->xDisplay(), mXWindow); + QEGLPlatformContext::swapBuffers(surface); - mEglWindowSurface = eglCreateWindowSurface(mEglIntegration->eglDisplay(),mConfig,mXWindow,0); - if (mEglWindowSurface == EGL_NO_SURFACE) { - qFatal("Could not make eglsurface"); - } + const QWaylandXCompositeEGLSurface &s = + static_cast<const QWaylandXCompositeEGLSurface &>(surface); - XSync(mEglIntegration->xDisplay(),False); - mBuffer = new QWaylandXCompositeBuffer(mEglIntegration->waylandXComposite(), - (uint32_t)mXWindow, - size, - mEglIntegration->waylandDisplay()->argbVisual()); - mWindow->attach(mBuffer); - wl_display_sync_callback(mEglIntegration->waylandDisplay()->wl_display(), - QWaylandXCompositeEGLContext::sync_function, - this); + QSize size = s.window()->geometry().size(); - mWaitingForSync = true; - wl_display_sync(mEglIntegration->waylandDisplay()->wl_display(),0); - mEglIntegration->waylandDisplay()->flushRequests(); - while (mWaitingForSync) { - mEglIntegration->waylandDisplay()->readEvents(); - } + s.window()->damage(QRect(QPoint(), size)); + s.window()->waitForFrameSync(); } diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.h b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.h index 9d9dd53e0b..bd7039f284 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.h +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglcontext.h @@ -44,39 +44,29 @@ #include <QtGui/QPlatformGLContext> -#include <QtCore/QWaitCondition> - -#include "qwaylandbuffer.h" #include "qwaylandxcompositeeglintegration.h" +#include "qeglplatformcontext.h" + class QWaylandXCompositeEGLWindow; -class QWaylandXCompositeEGLContext : public QPlatformGLContext +class QWaylandXCompositeEGLSurface : public QEGLSurface { public: - QWaylandXCompositeEGLContext(QWaylandXCompositeEGLIntegration *glxIntegration, QWaylandXCompositeEGLWindow *window); - - void makeCurrent(); - void doneCurrent(); - void swapBuffers(); - void* getProcAddress(const QString& procName); - - QPlatformWindowFormat platformWindowFormat() const; - - void geometryChanged(); + QWaylandXCompositeEGLSurface(QWaylandXCompositeEGLWindow *window); + EGLSurface eglSurface() const; + QWaylandXCompositeEGLWindow *window() const { return m_window; } private: - QWaylandXCompositeEGLIntegration *mEglIntegration; - QWaylandXCompositeEGLWindow *mWindow; - QWaylandBuffer *mBuffer; + QWaylandXCompositeEGLWindow *m_window; +}; - Window mXWindow; - EGLConfig mConfig; - EGLContext mContext; - EGLSurface mEglWindowSurface; +class QWaylandXCompositeEGLContext : public QEGLPlatformContext +{ +public: + QWaylandXCompositeEGLContext(const QGuiGLFormat &format, QPlatformGLContext *share, EGLDisplay display); - static void sync_function(void *data); - bool mWaitingForSync; + void swapBuffers(const QPlatformGLSurface &surface); }; #endif // QWAYLANDXCOMPOSITEEGLCONTEXT_H diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.cpp index 53199e87b8..90d5bea770 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.cpp @@ -70,9 +70,14 @@ void QWaylandXCompositeEGLIntegration::initialize() { } -QWaylandWindow * QWaylandXCompositeEGLIntegration::createEglWindow(QWidget *widget) +QWaylandWindow * QWaylandXCompositeEGLIntegration::createEglWindow(QWindow *window) { - return new QWaylandXCompositeEGLWindow(widget,this); + return new QWaylandXCompositeEGLWindow(window,this); +} + +QPlatformGLContext *QWaylandXCompositeEGLIntegration::createPlatformGLContext(const QGuiGLFormat &glFormat, QPlatformGLContext *share) const +{ + return new QWaylandXCompositeEGLContext(glFormat, share, eglDisplay()); } Display * QWaylandXCompositeEGLIntegration::xDisplay() const diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.h b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.h index 1e8055944f..ac302ef89f 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglintegration.h @@ -49,7 +49,9 @@ #include <QtCore/QDataStream> #include <QtCore/QMetaType> #include <QtCore/QVariant> -#include <QtGui/QWidget> +#include <QtGui/QWindow> + +#include <QPlatformGLContext> #include <QWaitCondition> @@ -66,7 +68,8 @@ public: void initialize(); - QWaylandWindow *createEglWindow(QWidget *widget); + QWaylandWindow *createEglWindow(QWindow *window); + QPlatformGLContext *createPlatformGLContext(const QGuiGLFormat &glFormat, QPlatformGLContext *share) const; QWaylandDisplay *waylandDisplay() const; struct wl_xcomposite *waylandXComposite() const; diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglwindow.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglwindow.cpp index 3daf5f6196..5c6717eb0c 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglwindow.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglwindow.cpp @@ -40,15 +40,27 @@ ****************************************************************************/ #include "qwaylandxcompositeeglwindow.h" +#include "qwaylandxcompositebuffer.h" + +#include "qeglconvenience.h" + +#include "wayland-xcomposite-client-protocol.h" +#include "qxlibeglintegration.h" + +#include <X11/extensions/Xcomposite.h> #include <QtCore/QDebug> -QWaylandXCompositeEGLWindow::QWaylandXCompositeEGLWindow(QWidget *window, QWaylandXCompositeEGLIntegration *glxIntegration) +QWaylandXCompositeEGLWindow::QWaylandXCompositeEGLWindow(QWindow *window, QWaylandXCompositeEGLIntegration *glxIntegration) : QWaylandWindow(window) - , mGlxIntegration(glxIntegration) - , mContext(0) + , m_glxIntegration(glxIntegration) + , m_context(0) + , m_buffer(0) + , m_xWindow(0) + , m_config(q_configFromGLFormat(glxIntegration->eglDisplay(), window->glFormat(), true)) + , m_surface(0) + , m_waitingForSync(false) { - } QWaylandWindow::WindowType QWaylandXCompositeEGLWindow::windowType() const @@ -57,21 +69,86 @@ QWaylandWindow::WindowType QWaylandXCompositeEGLWindow::windowType() const return QWaylandWindow::Egl; } -QPlatformGLContext * QWaylandXCompositeEGLWindow::glContext() const +QPlatformGLSurface *QWaylandXCompositeEGLWindow::createGLSurface() const { - if (!mContext) { - qDebug() << "creating glcontext;"; - QWaylandXCompositeEGLWindow *that = const_cast<QWaylandXCompositeEGLWindow *>(this); - that->mContext = new QWaylandXCompositeEGLContext(mGlxIntegration,that); - } - return mContext; + return new QWaylandXCompositeEGLSurface(const_cast<QWaylandXCompositeEGLWindow *>(this)); } void QWaylandXCompositeEGLWindow::setGeometry(const QRect &rect) { QWaylandWindow::setGeometry(rect); - if (mContext) { - mContext->geometryChanged(); + if (m_surface) { + eglDestroySurface(m_glxIntegration->eglDisplay(), m_surface); + m_surface = 0; + } +} + +EGLSurface QWaylandXCompositeEGLWindow::eglSurface() const +{ + if (!m_surface) + const_cast<QWaylandXCompositeEGLWindow *>(this)->createEglSurface(); + return m_surface; +} + +void QWaylandXCompositeEGLWindow::createEglSurface() +{ + QSize size(geometry().size()); + if (size.isEmpty()) { + // QGLWidget wants a context for a window without geometry + size = QSize(1,1); + } + + delete m_buffer; + //XFreePixmap deletes the glxPixmap as well + if (m_xWindow) { + XDestroyWindow(m_glxIntegration->xDisplay(), m_xWindow); } + + VisualID visualId = QXlibEglIntegration::getCompatibleVisualId(m_glxIntegration->xDisplay(), m_glxIntegration->eglDisplay(), m_config); + + XVisualInfo visualInfoTemplate; + memset(&visualInfoTemplate, 0, sizeof(XVisualInfo)); + visualInfoTemplate.visualid = visualId; + + int matchingCount = 0; + XVisualInfo *visualInfo = XGetVisualInfo(m_glxIntegration->xDisplay(), VisualIDMask, &visualInfoTemplate, &matchingCount); + + Colormap cmap = XCreateColormap(m_glxIntegration->xDisplay(),m_glxIntegration->rootWindow(),visualInfo->visual,AllocNone); + + XSetWindowAttributes a; + a.colormap = cmap; + m_xWindow = XCreateWindow(m_glxIntegration->xDisplay(), m_glxIntegration->rootWindow(),0, 0, size.width(), size.height(), + 0, visualInfo->depth, InputOutput, visualInfo->visual, + CWColormap, &a); + + XCompositeRedirectWindow(m_glxIntegration->xDisplay(), m_xWindow, CompositeRedirectManual); + XMapWindow(m_glxIntegration->xDisplay(), m_xWindow); + + m_surface = eglCreateWindowSurface(m_glxIntegration->eglDisplay(), m_config, m_xWindow,0); + if (m_surface == EGL_NO_SURFACE) { + qFatal("Could not make eglsurface"); + } + + XSync(m_glxIntegration->xDisplay(),False); + mBuffer = new QWaylandXCompositeBuffer(m_glxIntegration->waylandXComposite(), + (uint32_t)m_xWindow, + size, + m_glxIntegration->waylandDisplay()->argbVisual()); + attach(m_buffer); + wl_display_sync_callback(m_glxIntegration->waylandDisplay()->wl_display(), + QWaylandXCompositeEGLWindow::sync_function, + this); + + m_waitingForSync = true; + wl_display_sync(m_glxIntegration->waylandDisplay()->wl_display(),0); + m_glxIntegration->waylandDisplay()->flushRequests(); + while (m_waitingForSync) + m_glxIntegration->waylandDisplay()->readEvents(); +} + +void QWaylandXCompositeEGLWindow::sync_function(void *data) +{ + QWaylandXCompositeEGLWindow *that = static_cast<QWaylandXCompositeEGLWindow *>(data); + that->m_waitingForSync = false; } diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglwindow.h b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglwindow.h index 707801905d..16188ca3e0 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglwindow.h +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/qwaylandxcompositeeglwindow.h @@ -43,23 +43,37 @@ #define QWAYLANDXCOMPOSITEEGLWINDOW_H #include "qwaylandwindow.h" +#include "qwaylandbuffer.h" + #include "qwaylandxcompositeeglintegration.h" #include "qwaylandxcompositeeglcontext.h" class QWaylandXCompositeEGLWindow : public QWaylandWindow { public: - QWaylandXCompositeEGLWindow(QWidget *window, QWaylandXCompositeEGLIntegration *glxIntegration); + QWaylandXCompositeEGLWindow(QWindow *window, QWaylandXCompositeEGLIntegration *glxIntegration); WindowType windowType() const; - QPlatformGLContext *glContext() const; + QPlatformGLSurface *createGLSurface() const; void setGeometry(const QRect &rect); + EGLSurface eglSurface() const; + private: - QWaylandXCompositeEGLIntegration *mGlxIntegration; - QWaylandXCompositeEGLContext *mContext; + void createEglSurface(); + + QWaylandXCompositeEGLIntegration *m_glxIntegration; + QWaylandXCompositeEGLContext *m_context; + QWaylandBuffer *m_buffer; + + Window m_xWindow; + EGLConfig m_config; + EGLSurface m_surface; + + bool m_waitingForSync; + static void sync_function(void *data); }; #endif // QWAYLANDXCOMPOSITEEGLWINDOW_H diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/xcomposite_egl.pri b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/xcomposite_egl.pri index c3533f9ce3..a61391b2d1 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/xcomposite_egl.pri +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_egl/xcomposite_egl.pri @@ -1,6 +1,7 @@ include (../xcomposite_share/xcomposite_share.pri) -include (../../../eglconvenience/eglconvenience.pri) -include (../../../eglconvenience/xlibeglintegration.pri) +load(qpa/egl/convenience) +load(qpa/egl/context) +load(qpa/egl/xlibintegration) LIBS += -lXcomposite -lEGL diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp index dff6ffab66..5d4cf7a567 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp @@ -39,114 +39,67 @@ ** ****************************************************************************/ +#include <QtCore/QDebug> + #include "qwaylandxcompositeglxcontext.h" #include "qwaylandxcompositeglxwindow.h" -#include "qwaylandxcompositebuffer.h" - -#include "wayland-xcomposite-client-protocol.h" -#include <QtCore/QDebug> -#include <X11/extensions/Xcomposite.h> +#include <QRegion> -QWaylandXCompositeGLXContext::QWaylandXCompositeGLXContext(QWaylandXCompositeGLXIntegration *glxIntegration, QWaylandXCompositeGLXWindow *window) - : QPlatformGLContext() - , mGlxIntegration(glxIntegration) - , mWindow(window) - , mBuffer(0) - , mXWindow(0) - , mConfig(qglx_findConfig(glxIntegration->xDisplay(),glxIntegration->screen(),window->widget()->platformWindowFormat())) - , mWaitingForSyncCallback(false) +QWaylandXCompositeGLXSurface::QWaylandXCompositeGLXSurface(QWaylandXCompositeGLXWindow *window) + : m_window(window) { - XVisualInfo *visualInfo = glXGetVisualFromFBConfig(glxIntegration->xDisplay(),mConfig); - mContext = glXCreateContext(glxIntegration->xDisplay(),visualInfo,0,TRUE); - - geometryChanged(); } -void QWaylandXCompositeGLXContext::makeCurrent() +Window QWaylandXCompositeGLXSurface::xWindow() const { - QPlatformGLContext::makeCurrent(); - glXMakeCurrent(mGlxIntegration->xDisplay(),mXWindow,mContext); + return m_window->xWindow(); } -void QWaylandXCompositeGLXContext::doneCurrent() +QWaylandXCompositeGLXContext::QWaylandXCompositeGLXContext(const QGuiGLFormat &format, QPlatformGLContext *share, Display *display, int screen) + : m_display(display) { - glXMakeCurrent(mGlxIntegration->xDisplay(),0,0); - QPlatformGLContext::doneCurrent(); + GLXContext shareContext = share ? static_cast<QWaylandXCompositeGLXContext *>(share)->m_context : 0; + + GLXFBConfig config = qglx_findConfig(display, screen, format); + XVisualInfo *visualInfo = glXGetVisualFromFBConfig(display, config); + m_context = glXCreateContext(display, visualInfo, shareContext, true); + m_format = qglx_guiGLFormatFromGLXFBConfig(display, config, m_context); } -void QWaylandXCompositeGLXContext::swapBuffers() +bool QWaylandXCompositeGLXContext::makeCurrent(const QPlatformGLSurface &surface) { - QSize size = mWindow->geometry().size(); + Window xWindow = static_cast<const QWaylandXCompositeGLXSurface &>(surface).xWindow(); - glXSwapBuffers(mGlxIntegration->xDisplay(),mXWindow); - mWindow->damage(QRegion(QRect(QPoint(0,0),size))); - mWindow->waitForFrameSync(); + return glXMakeCurrent(m_display, xWindow, m_context); } -void * QWaylandXCompositeGLXContext::getProcAddress(const QString &procName) +void QWaylandXCompositeGLXContext::doneCurrent() { - return (void *) glXGetProcAddress(reinterpret_cast<GLubyte *>(procName.toLatin1().data())); + glXMakeCurrent(m_display, 0, 0); } -QPlatformWindowFormat QWaylandXCompositeGLXContext::platformWindowFormat() const +void QWaylandXCompositeGLXContext::swapBuffers(const QPlatformGLSurface &surface) { - return qglx_platformWindowFromGLXFBConfig(mGlxIntegration->xDisplay(),mConfig,mContext); -} + const QWaylandXCompositeGLXSurface &s = + static_cast<const QWaylandXCompositeGLXSurface &>(surface); -void QWaylandXCompositeGLXContext::sync_function(void *data) -{ - QWaylandXCompositeGLXContext *that = static_cast<QWaylandXCompositeGLXContext *>(data); - that->mWaitingForSyncCallback = false; + QSize size = s.window()->geometry().size(); + + glXSwapBuffers(m_display, s.xWindow()); + + s.window()->damage(QRect(QPoint(), size)); + s.window()->waitForFrameSync(); } -void QWaylandXCompositeGLXContext::waitForSync() +void (*QWaylandXCompositeGLXContext::getProcAddress(const QByteArray &procName)) () { - wl_display_sync_callback(mGlxIntegration->waylandDisplay()->wl_display(), - QWaylandXCompositeGLXContext::sync_function, - this); - mWaitingForSyncCallback = true; - wl_display_sync(mGlxIntegration->waylandDisplay()->wl_display(),0); - mGlxIntegration->waylandDisplay()->flushRequests(); - while (mWaitingForSyncCallback) { - mGlxIntegration->waylandDisplay()->readEvents(); - } + return glXGetProcAddress(reinterpret_cast<const GLubyte *>(procName.constData())); } -void QWaylandXCompositeGLXContext::geometryChanged() +QGuiGLFormat QWaylandXCompositeGLXContext::format() const { - QSize size(mWindow->geometry().size()); - if (size.isEmpty()) { - //QGLWidget wants a context for a window without geometry - size = QSize(1,1); - } - - delete mBuffer; - //XFreePixmap deletes the glxPixmap as well - if (mXWindow) { - XDestroyWindow(mGlxIntegration->xDisplay(),mXWindow); - } - - XVisualInfo *visualInfo = glXGetVisualFromFBConfig(mGlxIntegration->xDisplay(),mConfig); - Colormap cmap = XCreateColormap(mGlxIntegration->xDisplay(),mGlxIntegration->rootWindow(),visualInfo->visual,AllocNone); - - XSetWindowAttributes a; - a.background_pixel = WhitePixel(mGlxIntegration->xDisplay(), mGlxIntegration->screen()); - a.border_pixel = BlackPixel(mGlxIntegration->xDisplay(), mGlxIntegration->screen()); - a.colormap = cmap; - mXWindow = XCreateWindow(mGlxIntegration->xDisplay(), mGlxIntegration->rootWindow(),0, 0, size.width(), size.height(), - 0, visualInfo->depth, InputOutput, visualInfo->visual, - CWBackPixel|CWBorderPixel|CWColormap, &a); - - XCompositeRedirectWindow(mGlxIntegration->xDisplay(), mXWindow, CompositeRedirectManual); - XMapWindow(mGlxIntegration->xDisplay(), mXWindow); - - XSync(mGlxIntegration->xDisplay(),False); - mBuffer = new QWaylandXCompositeBuffer(mGlxIntegration->waylandXComposite(), - (uint32_t)mXWindow, - size, - mGlxIntegration->waylandDisplay()->argbVisual()); - mWindow->attach(mBuffer); - waitForSync(); + return m_format; } + diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.h b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.h index b6ee2bbc23..e0de801a5e 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.h +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.h @@ -44,42 +44,44 @@ #include <QtGui/QPlatformGLContext> -#include <QtCore/QWaitCondition> - -#include "qwaylandbuffer.h" #include "qwaylandxcompositeglxintegration.h" - #include "qglxconvenience.h" class QWaylandXCompositeGLXWindow; class QWaylandShmBuffer; +class QWaylandXCompositeGLXSurface : public QPlatformGLSurface +{ +public: + QWaylandXCompositeGLXSurface(QWaylandXCompositeGLXWindow *window); + + QWaylandXCompositeGLXWindow *window() const { return m_window; } + Window xWindow() const; + +private: + QWaylandXCompositeGLXWindow *m_window; +}; + + class QWaylandXCompositeGLXContext : public QPlatformGLContext { public: - QWaylandXCompositeGLXContext(QWaylandXCompositeGLXIntegration *glxIntegration, QWaylandXCompositeGLXWindow *window); + QWaylandXCompositeGLXContext(const QGuiGLFormat &format, QPlatformGLContext *share, Display *display, int screen); - void makeCurrent(); - void doneCurrent(); - void swapBuffers(); - void* getProcAddress(const QString& procName); + QGuiGLFormat format() const; - QPlatformWindowFormat platformWindowFormat() const; + void swapBuffers(const QPlatformGLSurface &surface); - void geometryChanged(); + bool makeCurrent(const QPlatformGLSurface &surface); + void doneCurrent(); -private: - QWaylandXCompositeGLXIntegration *mGlxIntegration; - QWaylandXCompositeGLXWindow *mWindow; - QWaylandBuffer *mBuffer; + void (*getProcAddress(const QByteArray &procName)) (); - Window mXWindow; - GLXFBConfig mConfig; - GLXContext mContext; +private: + GLXContext m_context; - static void sync_function(void *data); - void waitForSync(); - bool mWaitingForSyncCallback; + Display *m_display; + QGuiGLFormat m_format; }; #endif // QWAYLANDXCOMPOSITEGLXCONTEXT_H diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.cpp index e8dbea48c6..a80a595768 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.cpp @@ -70,9 +70,14 @@ void QWaylandXCompositeGLXIntegration::initialize() { } -QWaylandWindow * QWaylandXCompositeGLXIntegration::createEglWindow(QWidget *widget) +QWaylandWindow * QWaylandXCompositeGLXIntegration::createEglWindow(QWindow *window) { - return new QWaylandXCompositeGLXWindow(widget,this); + return new QWaylandXCompositeGLXWindow(window, this); +} + +QPlatformGLContext *QWaylandXCompositeGLXIntegration::createPlatformGLContext(const QGuiGLFormat &glFormat, QPlatformGLContext *share) const +{ + return new QWaylandXCompositeGLXContext(glFormat, share, mDisplay, mScreen); } Display * QWaylandXCompositeGLXIntegration::xDisplay() const diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.h b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.h index 17f2f6d4e4..c347b110c6 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.h +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxintegration.h @@ -49,7 +49,7 @@ #include <QtCore/QDataStream> #include <QtCore/QMetaType> #include <QtCore/QVariant> -#include <QtGui/QWidget> +#include <QtGui/QWindow> #include <X11/Xlib.h> @@ -63,7 +63,8 @@ public: void initialize(); - QWaylandWindow *createEglWindow(QWidget *widget); + QWaylandWindow *createEglWindow(QWindow *window); + QPlatformGLContext *createPlatformGLContext(const QGuiGLFormat &glFormat, QPlatformGLContext *share) const; QWaylandDisplay *waylandDisplay() const; struct wl_xcomposite *waylandXComposite() const; diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxwindow.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxwindow.cpp index cd7ae1964c..41a14e3f66 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxwindow.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxwindow.cpp @@ -40,15 +40,24 @@ ****************************************************************************/ #include "qwaylandxcompositeglxwindow.h" +#include "qwaylandxcompositebuffer.h" #include <QtCore/QDebug> -QWaylandXCompositeGLXWindow::QWaylandXCompositeGLXWindow(QWidget *window, QWaylandXCompositeGLXIntegration *glxIntegration) +#include "wayland-xcomposite-client-protocol.h" +#include <QtGui/QRegion> + +#include <X11/extensions/Xcomposite.h> + + +QWaylandXCompositeGLXWindow::QWaylandXCompositeGLXWindow(QWindow *window, QWaylandXCompositeGLXIntegration *glxIntegration) : QWaylandWindow(window) - , mGlxIntegration(glxIntegration) - , mContext(0) + , m_glxIntegration(glxIntegration) + , m_xWindow(0) + , m_config(qglx_findConfig(glxIntegration->xDisplay(), glxIntegration->screen(), window->glFormat())) + , m_buffer(0) + , m_waitingForSync(false) { - } QWaylandWindow::WindowType QWaylandXCompositeGLXWindow::windowType() const @@ -57,21 +66,79 @@ QWaylandWindow::WindowType QWaylandXCompositeGLXWindow::windowType() const return QWaylandWindow::Egl; } -QPlatformGLContext * QWaylandXCompositeGLXWindow::glContext() const +QPlatformGLSurface *QWaylandXCompositeGLXWindow::createGLSurface() const { - if (!mContext) { - qDebug() << "creating glcontext;"; - QWaylandXCompositeGLXWindow *that = const_cast<QWaylandXCompositeGLXWindow *>(this); - that->mContext = new QWaylandXCompositeGLXContext(mGlxIntegration,that); - } - return mContext; + return new QWaylandXCompositeGLXSurface(const_cast<QWaylandXCompositeGLXWindow *>(this)); } void QWaylandXCompositeGLXWindow::setGeometry(const QRect &rect) { QWaylandWindow::setGeometry(rect); - if (mContext) { - mContext->geometryChanged(); + if (m_xWindow) { + delete m_buffer; + + XDestroyWindow(m_glxIntegration->xDisplay(), m_xWindow); + m_xWindow = 0; + } +} + +Window QWaylandXCompositeGLXWindow::xWindow() const +{ + if (!m_xWindow) + const_cast<QWaylandXCompositeGLXWindow *>(this)->createSurface(); + + return m_xWindow; +} + +void QWaylandXCompositeGLXWindow::waitForSync() +{ + wl_display_sync_callback(m_glxIntegration->waylandDisplay()->wl_display(), + QWaylandXCompositeGLXWindow::sync_function, + this); + m_waitingForSync= true; + wl_display_sync(m_glxIntegration->waylandDisplay()->wl_display(), 0); + m_glxIntegration->waylandDisplay()->flushRequests(); + while (m_waitingForSync) + m_glxIntegration->waylandDisplay()->readEvents(); +} + + +void QWaylandXCompositeGLXWindow::createSurface() +{ + QSize size(geometry().size()); + if (size.isEmpty()) { + //QGLWidget wants a context for a window without geometry + size = QSize(1,1); } + + XVisualInfo *visualInfo = glXGetVisualFromFBConfig(m_glxIntegration->xDisplay(), m_config); + Colormap cmap = XCreateColormap(m_glxIntegration->xDisplay(), m_glxIntegration->rootWindow(), + visualInfo->visual, AllocNone); + + XSetWindowAttributes a; + a.background_pixel = WhitePixel(m_glxIntegration->xDisplay(), m_glxIntegration->screen()); + a.border_pixel = BlackPixel(m_glxIntegration->xDisplay(), m_glxIntegration->screen()); + a.colormap = cmap; + m_xWindow = XCreateWindow(m_glxIntegration->xDisplay(), m_glxIntegration->rootWindow(),0, 0, size.width(), size.height(), + 0, visualInfo->depth, InputOutput, visualInfo->visual, + CWBackPixel|CWBorderPixel|CWColormap, &a); + + XCompositeRedirectWindow(m_glxIntegration->xDisplay(), m_xWindow, CompositeRedirectManual); + XMapWindow(m_glxIntegration->xDisplay(), m_xWindow); + + XSync(m_glxIntegration->xDisplay(), False); + m_buffer = new QWaylandXCompositeBuffer(m_glxIntegration->waylandXComposite(), + (uint32_t)m_xWindow, + size, + m_glxIntegration->waylandDisplay()->argbVisual()); + attach(m_buffer); + waitForSync(); +} + +void QWaylandXCompositeGLXWindow::sync_function(void *data) +{ + QWaylandXCompositeGLXWindow *that = static_cast<QWaylandXCompositeGLXWindow *>(data); + that->m_waitingForSync = false; } + diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxwindow.h b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxwindow.h index 8808f2d482..7a19c7175a 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxwindow.h +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxwindow.h @@ -46,20 +46,36 @@ #include "qwaylandxcompositeglxintegration.h" #include "qwaylandxcompositeglxcontext.h" +#include <QtCore/QWaitCondition> + +#include "qwaylandbuffer.h" + class QWaylandXCompositeGLXWindow : public QWaylandWindow { public: - QWaylandXCompositeGLXWindow(QWidget *window, QWaylandXCompositeGLXIntegration *glxIntegration); + QWaylandXCompositeGLXWindow(QWindow *window, QWaylandXCompositeGLXIntegration *glxIntegration); WindowType windowType() const; - QPlatformGLContext *glContext() const; + QPlatformGLSurface *createGLSurface() const; void setGeometry(const QRect &rect); + Window xWindow() const; + private: - QWaylandXCompositeGLXIntegration *mGlxIntegration; - QWaylandXCompositeGLXContext *mContext; + void createSurface(); + + QWaylandXCompositeGLXIntegration *m_glxIntegration; + + Window m_xWindow; + GLXFBConfig m_config; + + QWaylandBuffer *m_buffer; + + void waitForSync(); + bool m_waitingForSync; + static void sync_function(void *data); }; #endif // QWAYLANDXCOMPOSITEGLXWINDOW_H diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/xcomposite_glx.pri b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/xcomposite_glx.pri index 43295e91e7..9aae32c41b 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/xcomposite_glx.pri +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/xcomposite_glx.pri @@ -1,5 +1,5 @@ include (../xcomposite_share/xcomposite_share.pri) -include (../../../glxconvenience/glxconvenience.pri) +load(qpa/glx/convenience) LIBS += -lXcomposite SOURCES += \ diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_share/qwaylandxcompositebuffer.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_share/qwaylandxcompositebuffer.cpp index 7d309ef877..f4bacc3c1f 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_share/qwaylandxcompositebuffer.cpp +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_share/qwaylandxcompositebuffer.cpp @@ -42,6 +42,7 @@ #include "qwaylandxcompositebuffer.h" #include "wayland-client.h" +#include "wayland-xcomposite-client-protocol.h" QWaylandXCompositeBuffer::QWaylandXCompositeBuffer(wl_xcomposite *xcomposite, uint32_t window, const QSize &size, wl_visual *visual) :mSize(size) diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_share/qwaylandxcompositebuffer.h b/src/plugins/platforms/wayland/gl_integration/xcomposite_share/qwaylandxcompositebuffer.h index cbd40ad381..02176d7850 100644 --- a/src/plugins/platforms/wayland/gl_integration/xcomposite_share/qwaylandxcompositebuffer.h +++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_share/qwaylandxcompositebuffer.h @@ -43,8 +43,10 @@ #define QWAYLANDXCOMPOSITEBUFFER_H #include "qwaylandbuffer.h" +#include <stdint.h> -#include "wayland-xcomposite-client-protocol.h" +struct wl_xcomposite; +struct wl_visual; class QWaylandXCompositeBuffer : public QWaylandBuffer { diff --git a/src/plugins/platforms/wayland/qwaylandclipboard.cpp b/src/plugins/platforms/wayland/qwaylandclipboard.cpp index b7f6ae535b..feaa660bc6 100644 --- a/src/plugins/platforms/wayland/qwaylandclipboard.cpp +++ b/src/plugins/platforms/wayland/qwaylandclipboard.cpp @@ -43,7 +43,7 @@ #include "qwaylanddisplay.h" #include "qwaylandinputdevice.h" #include <QtGui/QPlatformNativeInterface> -#include <QtGui/QApplication> +#include <QtGui/QGuiApplication> #include <QtCore/QMimeData> #include <QtCore/QStringList> #include <QtCore/QFile> diff --git a/src/plugins/platforms/wayland/qwaylandcursor.cpp b/src/plugins/platforms/wayland/qwaylandcursor.cpp index 87b846cefb..d69d618591 100644 --- a/src/plugins/platforms/wayland/qwaylandcursor.cpp +++ b/src/plugins/platforms/wayland/qwaylandcursor.cpp @@ -108,11 +108,11 @@ QWaylandCursor::QWaylandCursor(QWaylandScreen *screen) { } -void QWaylandCursor::changeCursor(QCursor *cursor, QWidget *widget) +void QWaylandCursor::changeCursor(QCursor *cursor, QWindow *window) { const struct pointer_image *p; - if (widget == NULL) + if (window == NULL) return; p = NULL; diff --git a/src/plugins/platforms/wayland/qwaylandcursor.h b/src/plugins/platforms/wayland/qwaylandcursor.h index 236bfc56ee..4409eea828 100644 --- a/src/plugins/platforms/wayland/qwaylandcursor.h +++ b/src/plugins/platforms/wayland/qwaylandcursor.h @@ -52,7 +52,7 @@ class QWaylandCursor : QPlatformCursor { public: QWaylandCursor(QWaylandScreen *screen); - void changeCursor(QCursor *cursor, QWidget *widget); + void changeCursor(QCursor *cursor, QWindow *window); QWaylandShmBuffer *mBuffer; QWaylandDisplay *mDisplay; }; diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp index 83516e9b4e..f1c9ccc18f 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp +++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp @@ -56,8 +56,7 @@ #endif #include <QtCore/QAbstractEventDispatcher> -#include <QtGui/QApplication> -#include <QtGui/private/qapplication_p.h> +#include <QtGui/private/qguiapplication_p.h> #include <unistd.h> #include <fcntl.h> @@ -290,7 +289,7 @@ void QWaylandDisplay::displayHandleGlobal(uint32_t id, new QWaylandInputDevice(mDisplay, id); mInputDevices.append(inputDevice); } else if (interface == "wl_selection_offer") { - QPlatformIntegration *plat = QApplicationPrivate::platformIntegration(); + QPlatformIntegration *plat = QGuiApplicationPrivate::platformIntegration(); QWaylandClipboard *clipboard = static_cast<QWaylandClipboard *>(plat->clipboard()); clipboard->createSelectionOffer(id); } diff --git a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp index d1da57d81d..7f3737613f 100644 --- a/src/plugins/platforms/wayland/qwaylandinputdevice.cpp +++ b/src/plugins/platforms/wayland/qwaylandinputdevice.cpp @@ -110,7 +110,7 @@ void QWaylandInputDevice::inputHandleMotion(void *data, inputDevice->mSurfacePos = QPoint(surface_x, surface_y); inputDevice->mGlobalPos = QPoint(x, y); inputDevice->mTime = time; - QWindowSystemInterface::handleMouseEvent(window->widget(), + QWindowSystemInterface::handleMouseEvent(window->window(), time, inputDevice->mSurfacePos, inputDevice->mGlobalPos, @@ -152,7 +152,7 @@ void QWaylandInputDevice::inputHandleButton(void *data, inputDevice->mButtons &= ~qt_button; inputDevice->mTime = time; - QWindowSystemInterface::handleMouseEvent(window->widget(), + QWindowSystemInterface::handleMouseEvent(window->window(), time, inputDevice->mSurfacePos, inputDevice->mGlobalPos, @@ -269,7 +269,7 @@ void QWaylandInputDevice::inputHandleKey(void *data, sym = translateKey(sym, s, sizeof s); if (window) { - QWindowSystemInterface::handleKeyEvent(window->widget(), + QWindowSystemInterface::handleKeyEvent(window->window(), time, type, sym, inputDevice->mModifiers, QString::fromLatin1(s)); @@ -292,13 +292,13 @@ void QWaylandInputDevice::inputHandlePointerFocus(void *data, if (inputDevice->mPointerFocus) { window = inputDevice->mPointerFocus; - QWindowSystemInterface::handleLeaveEvent(window->widget()); + QWindowSystemInterface::handleLeaveEvent(window->window()); inputDevice->mPointerFocus = NULL; } if (surface) { window = (QWaylandWindow *) wl_surface_get_user_data(surface); - QWindowSystemInterface::handleEnterEvent(window->widget()); + QWindowSystemInterface::handleEnterEvent(window->window()); inputDevice->mPointerFocus = window; } @@ -330,7 +330,7 @@ void QWaylandInputDevice::inputHandleKeyboardFocus(void *data, if (surface) { window = (QWaylandWindow *) wl_surface_get_user_data(surface); inputDevice->mKeyboardFocus = window; - QWindowSystemInterface::handleWindowActivated(window->widget()); + QWindowSystemInterface::handleWindowActivated(window->window()); } else { inputDevice->mKeyboardFocus = NULL; QWindowSystemInterface::handleWindowActivated(0); diff --git a/src/plugins/platforms/wayland/qwaylandintegration.cpp b/src/plugins/platforms/wayland/qwaylandintegration.cpp index 8257bca557..4c2eaa631c 100644 --- a/src/plugins/platforms/wayland/qwaylandintegration.cpp +++ b/src/plugins/platforms/wayland/qwaylandintegration.cpp @@ -47,11 +47,11 @@ #include "qwaylandnativeinterface.h" #include "qwaylandclipboard.h" -#include "qgenericunixfontdatabase.h" +#include "QtPlatformSupport/private/qgenericunixfontdatabase_p.h" #include <QtGui/QWindowSystemInterface> #include <QtGui/QPlatformCursor> -#include <QtGui/QPlatformWindowFormat> +#include <QtGui/QGuiGLFormat> #include <QtGui/private/qpixmap_raster_p.h> #ifdef QT_WAYLAND_GL_SUPPORT @@ -98,27 +98,33 @@ QPixmapData *QWaylandIntegration::createPixmapData(QPixmapData::PixelType type) return new QRasterPixmapData(type); } -QPlatformWindow *QWaylandIntegration::createPlatformWindow(QWidget *widget, WId winId) const +QPlatformWindow *QWaylandIntegration::createPlatformWindow(QWindow *window) const { - Q_UNUSED(winId); #ifdef QT_WAYLAND_GL_SUPPORT - bool useOpenGL = mUseOpenGL || (widget->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL); + bool useOpenGL = mUseOpenGL || window->surfaceType() == QWindow::OpenGLSurface; if (useOpenGL) - return mDisplay->eglIntegration()->createEglWindow(widget); + return mDisplay->eglIntegration()->createEglWindow(window); #endif - return new QWaylandShmWindow(widget); + return new QWaylandShmWindow(window); } -QWindowSurface *QWaylandIntegration::createWindowSurface(QWidget *widget, WId winId) const +QPlatformGLContext *QWaylandIntegration::createPlatformGLContext(const QGuiGLFormat &glFormat, QPlatformGLContext *share) const +{ +#ifdef QT_WAYLAND_GL_SUPPORT + return mDisplay->eglIntegration()->createPlatformGLContext(glFormat, share); +#endif + return 0; +} + +QWindowSurface *QWaylandIntegration::createWindowSurface(QWindow *window, WId winId) const { - Q_UNUSED(winId); Q_UNUSED(winId); #ifdef QT_WAYLAND_GL_SUPPORT - bool useOpenGL = mUseOpenGL || (widget->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL); + bool useOpenGL = mUseOpenGL || window->surfaceType() == QWindow::OpenGLSurface; if (useOpenGL) - return new QWaylandGLWindowSurface(widget); + return new QWaylandGLWindowSurface(window); #endif - return new QWaylandShmWindowSurface(widget); + return new QWaylandShmWindowSurface(window); } QPlatformFontDatabase *QWaylandIntegration::fontDatabase() const diff --git a/src/plugins/platforms/wayland/qwaylandintegration.h b/src/plugins/platforms/wayland/qwaylandintegration.h index c7dc89d928..2e05faf677 100644 --- a/src/plugins/platforms/wayland/qwaylandintegration.h +++ b/src/plugins/platforms/wayland/qwaylandintegration.h @@ -56,8 +56,9 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const; QPixmapData *createPixmapData(QPixmapData::PixelType type) const; - QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId) const; - QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const; + QPlatformWindow *createPlatformWindow(QWindow *window) const; + QPlatformGLContext *createPlatformGLContext(const QGuiGLFormat &glFormat, QPlatformGLContext *share) const; + QWindowSurface *createWindowSurface(QWindow *window, WId winId) const; QList<QPlatformScreen *> screens() const; diff --git a/src/plugins/platforms/wayland/qwaylandnativeinterface.cpp b/src/plugins/platforms/wayland/qwaylandnativeinterface.cpp index 43be74a6ea..f6028f69b2 100644 --- a/src/plugins/platforms/wayland/qwaylandnativeinterface.cpp +++ b/src/plugins/platforms/wayland/qwaylandnativeinterface.cpp @@ -43,30 +43,30 @@ #include "qwaylanddisplay.h" #include "qwaylandwindow.h" -#include <QtGui/private/qapplication_p.h> +#include <QtGui/private/qguiapplication_p.h> -void *QWaylandNativeInterface::nativeResourceForWidget(const QByteArray &resourceString, QWidget *widget) +void *QWaylandNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) { QByteArray lowerCaseResource = resourceString.toLower(); if (lowerCaseResource == "display") - return qPlatformScreenForWidget(widget)->display()->wl_display(); + return qPlatformScreenForWindow(window)->display()->wl_display(); if (lowerCaseResource == "surface") { - return ((QWaylandWindow *) widget->platformWindow())->wl_surface(); + return ((QWaylandWindow *) window->handle())->wl_surface(); } return NULL; } -QWaylandScreen * QWaylandNativeInterface::qPlatformScreenForWidget(QWidget *widget) +QWaylandScreen * QWaylandNativeInterface::qPlatformScreenForWindow(QWindow *window) { QWaylandScreen *screen; - if (widget) { - screen = static_cast<QWaylandScreen *>(QPlatformScreen::platformScreenForWidget(widget)); + if (window) { + screen = static_cast<QWaylandScreen *>(QPlatformScreen::platformScreenForWindow(window)); } else { - screen = static_cast<QWaylandScreen *>(QApplicationPrivate::platformIntegration()->screens()[0]); + screen = static_cast<QWaylandScreen *>(QGuiApplicationPrivate::platformIntegration()->screens()[0]); } return screen; } diff --git a/src/plugins/platforms/wayland/qwaylandnativeinterface.h b/src/plugins/platforms/wayland/qwaylandnativeinterface.h index d33a41b00b..f1d4fe9402 100644 --- a/src/plugins/platforms/wayland/qwaylandnativeinterface.h +++ b/src/plugins/platforms/wayland/qwaylandnativeinterface.h @@ -49,11 +49,11 @@ class QWaylandNativeInterface : public QPlatformNativeInterface { public: - void *nativeResourceForWidget(const QByteArray &resourceString, - QWidget *widget); + void *nativeResourceForWindow(const QByteArray &resourceString, + QWindow *window); private: - static QWaylandScreen *qPlatformScreenForWidget(QWidget *widget); + static QWaylandScreen *qPlatformScreenForWindow(QWindow *window); }; diff --git a/src/plugins/platforms/wayland/qwaylandscreen.cpp b/src/plugins/platforms/wayland/qwaylandscreen.cpp index be6dcb2e88..3a63e78207 100644 --- a/src/plugins/platforms/wayland/qwaylandscreen.cpp +++ b/src/plugins/platforms/wayland/qwaylandscreen.cpp @@ -81,9 +81,9 @@ QImage::Format QWaylandScreen::format() const return mFormat; } -QWaylandScreen * QWaylandScreen::waylandScreenFromWidget(QWidget *widget) +QWaylandScreen * QWaylandScreen::waylandScreenFromWindow(QWindow *window) { - QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWidget(widget); + QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWindow(window); return static_cast<QWaylandScreen *>(platformScreen); } diff --git a/src/plugins/platforms/wayland/qwaylandscreen.h b/src/plugins/platforms/wayland/qwaylandscreen.h index f2b3bcefbc..9bf4f6574a 100644 --- a/src/plugins/platforms/wayland/qwaylandscreen.h +++ b/src/plugins/platforms/wayland/qwaylandscreen.h @@ -62,7 +62,7 @@ public: wl_visual *visual() const; - static QWaylandScreen *waylandScreenFromWidget(QWidget *widget); + static QWaylandScreen *waylandScreenFromWindow(QWindow *window); private: QWaylandDisplay *mWaylandDisplay; diff --git a/src/plugins/platforms/wayland/qwaylandshmsurface.cpp b/src/plugins/platforms/wayland/qwaylandshmsurface.cpp index efc56bb5d4..520633811c 100644 --- a/src/plugins/platforms/wayland/qwaylandshmsurface.cpp +++ b/src/plugins/platforms/wayland/qwaylandshmsurface.cpp @@ -41,7 +41,6 @@ #include "qwaylandshmsurface.h" #include <QtCore/qdebug.h> -#include <QtGui/private/qapplication_p.h> #include "qwaylanddisplay.h" #include "qwaylandshmwindow.h" @@ -91,10 +90,10 @@ QWaylandShmBuffer::~QWaylandShmBuffer(void) wl_buffer_destroy(mBuffer); } -QWaylandShmWindowSurface::QWaylandShmWindowSurface(QWidget *window) +QWaylandShmWindowSurface::QWaylandShmWindowSurface(QWindow *window) : QWindowSurface(window) , mBuffer(0) - , mDisplay(QWaylandScreen::waylandScreenFromWidget(window)->display()) + , mDisplay(QWaylandScreen::waylandScreenFromWindow(window)->display()) { } @@ -109,27 +108,27 @@ QPaintDevice *QWaylandShmWindowSurface::paintDevice() void QWaylandShmWindowSurface::beginPaint(const QRegion &) { - QWaylandShmWindow *waylandWindow = static_cast<QWaylandShmWindow *>(window()->platformWindow()); + QWaylandShmWindow *waylandWindow = static_cast<QWaylandShmWindow *>(window()->handle()); Q_ASSERT(waylandWindow->windowType() == QWaylandWindow::Shm); waylandWindow->waitForFrameSync(); } -void QWaylandShmWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +void QWaylandShmWindowSurface::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) { - Q_UNUSED(widget); + Q_UNUSED(window); Q_UNUSED(offset); - QWaylandShmWindow *waylandWindow = static_cast<QWaylandShmWindow *>(window()->platformWindow()); + QWaylandShmWindow *waylandWindow = static_cast<QWaylandShmWindow *>(window->handle()); Q_ASSERT(waylandWindow->windowType() == QWaylandWindow::Shm); waylandWindow->damage(region); } void QWaylandShmWindowSurface::resize(const QSize &size) { - QWaylandShmWindow *waylandWindow = static_cast<QWaylandShmWindow *>(window()->platformWindow()); + QWaylandShmWindow *waylandWindow = static_cast<QWaylandShmWindow *>(window()->handle()); Q_ASSERT(waylandWindow->windowType() == QWaylandWindow::Shm); QWindowSurface::resize(size); - QImage::Format format = QPlatformScreen::platformScreenForWidget(window())->format(); + QImage::Format format = QPlatformScreen::platformScreenForWindow(window())->format(); if (mBuffer != NULL && mBuffer->size() == size) return; diff --git a/src/plugins/platforms/wayland/qwaylandshmsurface.h b/src/plugins/platforms/wayland/qwaylandshmsurface.h index f3db8b86e5..1045709d7c 100644 --- a/src/plugins/platforms/wayland/qwaylandshmsurface.h +++ b/src/plugins/platforms/wayland/qwaylandshmsurface.h @@ -44,7 +44,7 @@ #include "qwaylandbuffer.h" #include <QtGui/private/qwindowsurface_p.h> - +#include <QtGui/QImage> #include <QtGui/QPlatformWindow> QT_BEGIN_NAMESPACE @@ -65,11 +65,11 @@ private: class QWaylandShmWindowSurface : public QWindowSurface { public: - QWaylandShmWindowSurface(QWidget *window); + QWaylandShmWindowSurface(QWindow *window); ~QWaylandShmWindowSurface(); QPaintDevice *paintDevice(); - void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); void resize(const QSize &size); void beginPaint(const QRegion &); diff --git a/src/plugins/platforms/wayland/qwaylandshmwindow.cpp b/src/plugins/platforms/wayland/qwaylandshmwindow.cpp index a6b7050f7a..bd1e61fa4c 100644 --- a/src/plugins/platforms/wayland/qwaylandshmwindow.cpp +++ b/src/plugins/platforms/wayland/qwaylandshmwindow.cpp @@ -47,8 +47,8 @@ #include <QtCore/QDebug> -QWaylandShmWindow::QWaylandShmWindow(QWidget *widget) - : QWaylandWindow(widget) +QWaylandShmWindow::QWaylandShmWindow(QWindow *window) + : QWaylandWindow(window) { newSurfaceCreated(); } @@ -63,9 +63,9 @@ QWaylandWindow::WindowType QWaylandShmWindow::windowType() const return QWaylandWindow::Shm; } -QPlatformGLContext * QWaylandShmWindow::glContext() const +QPlatformGLSurface * QWaylandShmWindow::glSurface() const { - qWarning("Trying to retrieve a glContext from a Raster window surface!"); + qWarning("Raster window does not have a GL drawable"); return 0; } diff --git a/src/plugins/platforms/wayland/qwaylandshmwindow.h b/src/plugins/platforms/wayland/qwaylandshmwindow.h index 8033703391..db26c5c928 100644 --- a/src/plugins/platforms/wayland/qwaylandshmwindow.h +++ b/src/plugins/platforms/wayland/qwaylandshmwindow.h @@ -48,11 +48,11 @@ class QWaylandShmWindow : public QWaylandWindow { public: - QWaylandShmWindow(QWidget *widget); + QWaylandShmWindow(QWindow *window); ~QWaylandShmWindow(); WindowType windowType() const; - QPlatformGLContext *glContext() const; + QPlatformGLSurface *glSurface() const; }; #endif // QWAYLANDSHMWINDOW_H diff --git a/src/plugins/platforms/wayland/qwaylandwindow.cpp b/src/plugins/platforms/wayland/qwaylandwindow.cpp index eda8c94516..53f74e3ddf 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow.cpp +++ b/src/plugins/platforms/wayland/qwaylandwindow.cpp @@ -46,19 +46,20 @@ #include "qwaylandinputdevice.h" #include "qwaylandscreen.h" +#include <QtGui/QWindow> + #ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT #include "windowmanager_integration/qwaylandwindowmanagerintegration.h" #endif #include <QCoreApplication> -#include <QtGui/QWidget> #include <QtGui/QWindowSystemInterface> #include <QDebug> -QWaylandWindow::QWaylandWindow(QWidget *window) +QWaylandWindow::QWaylandWindow(QWindow *window) : QPlatformWindow(window) - , mDisplay(QWaylandScreen::waylandScreenFromWidget(window)->display()) + , mDisplay(QWaylandScreen::waylandScreenFromWindow(window)->display()) , mBuffer(0) , mWaitingForFrameSync(false) { @@ -119,7 +120,7 @@ void QWaylandWindow::configure(uint32_t time, uint32_t edges, setGeometry(geometry); - QWindowSystemInterface::handleGeometryChange(widget(), geometry); + QWindowSystemInterface::handleGeometryChange(window(), geometry); } void QWaylandWindow::attach(QWaylandBuffer *buffer) diff --git a/src/plugins/platforms/wayland/qwaylandwindow.h b/src/plugins/platforms/wayland/qwaylandwindow.h index b8eae96e5e..ca9f4b14d3 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow.h +++ b/src/plugins/platforms/wayland/qwaylandwindow.h @@ -59,7 +59,7 @@ public: Egl }; - QWaylandWindow(QWidget *window); + QWaylandWindow(QWindow *window); ~QWaylandWindow(); virtual WindowType windowType() const = 0; diff --git a/src/plugins/platforms/wayland/wayland.pro b/src/plugins/platforms/wayland/wayland.pro index 857a2918ce..6a6ffdffc0 100644 --- a/src/plugins/platforms/wayland/wayland.pro +++ b/src/plugins/platforms/wayland/wayland.pro @@ -1,14 +1,14 @@ TARGET = qwayland load(qt_plugin) -QT+=gui-private core-private opengl-private +CONFIG += qpa/genericunixfontdatabase DESTDIR = $$QT.gui.plugins/platforms DEFINES += Q_PLATFORM_WAYLAND DEFINES += $$QMAKE_DEFINES_WAYLAND -QT += core-private gui-private opengl-private +QT += core-private gui-private opengl-private platformsupport-private SOURCES = main.cpp \ qwaylandintegration.cpp \ @@ -37,13 +37,6 @@ INCLUDEPATH += $$QMAKE_INCDIR_WAYLAND LIBS += $$QMAKE_LIBS_WAYLAND QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_WAYLAND -INCLUDEPATH += $$PWD - -include ($$PWD/gl_integration/gl_integration.pri) -include ($$PWD/windowmanager_integration/windowmanager_integration.pri) - -include (../fontdatabases/genericunix/genericunix.pri) - target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target diff --git a/src/plugins/platforms/xcb/README b/src/plugins/platforms/xcb/README index 17a86e6d08..0e6e0c6b59 100644 --- a/src/plugins/platforms/xcb/README +++ b/src/plugins/platforms/xcb/README @@ -1,3 +1,3 @@ Required packages: -libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm1 libxcb-icccm1-dev libxcb-sync0 libxcb-sync0-dev +libxcb1 libxcb1-dev libx11-xcb1 libx11-xcb-dev libxcb-keysyms1 libxcb-keysyms1-dev libxcb-image0 libxcb-image0-dev libxcb-shm0 libxcb-shm0-dev libxcb-icccm1 libxcb-icccm1-dev libxcb-sync0 libxcb-sync0-dev libxcb-render-util0 libxcb-render-util0-dev diff --git a/src/plugins/platforms/xcb/qdri2context.cpp b/src/plugins/platforms/xcb/qdri2context.cpp index 8bcdacb92b..8eef1b6111 100644 --- a/src/plugins/platforms/xcb/qdri2context.cpp +++ b/src/plugins/platforms/xcb/qdri2context.cpp @@ -45,7 +45,7 @@ #include "qxcbconnection.h" #include <QtCore/QDebug> -#include <QtGui/QWidget> +#include <QtWidgets/QWidget> #include <xcb/dri2.h> #include <xcb/xfixes.h> @@ -146,7 +146,6 @@ QDri2Context::~QDri2Context() void QDri2Context::makeCurrent() { - QPlatformGLContext::makeCurrent(); Q_D(QDri2Context); eglMakeCurrent(EGL_DISPLAY_FROM_XCB(d->qXcbWindow),EGL_NO_SURFACE,EGL_NO_SURFACE,d->eglContext); @@ -156,7 +155,6 @@ void QDri2Context::makeCurrent() void QDri2Context::doneCurrent() { - QPlatformGLContext::doneCurrent(); Q_D(QDri2Context); eglMakeCurrent(EGL_DISPLAY_FROM_XCB(d->qXcbWindow),EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT); } diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp index 8e04cbcb71..a47de88141 100644 --- a/src/plugins/platforms/xcb/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/qglxintegration.cpp @@ -50,70 +50,70 @@ #include <X11/Xutil.h> #include <GL/glx.h> +#include <QtGui/QGuiGLContext> + #include "qglxintegration.h" -#include "qglxconvenience.h" +#include <QtPlatformSupport/private/qglxconvenience_p.h> #if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) #include <dlfcn.h> #endif -QGLXContext::QGLXContext(Window window, QXcbScreen *screen, const QPlatformWindowFormat &format) +QGLXSurface::QGLXSurface(GLXDrawable drawable, const QGuiGLFormat &format) + : QPlatformGLSurface(format) + , glxDrawable(drawable) +{ +} + +QGLXContext::QGLXContext(QXcbScreen *screen, const QGuiGLFormat &format, QPlatformGLContext *share) : QPlatformGLContext() , m_screen(screen) - , m_drawable((Drawable)window) , m_context(0) { Q_XCB_NOOP(m_screen->connection()); - const QPlatformGLContext *sharePlatformContext; - sharePlatformContext = format.sharedGLContext(); GLXContext shareGlxContext = 0; - if (sharePlatformContext) - shareGlxContext = static_cast<const QGLXContext*>(sharePlatformContext)->glxContext(); + if (share) + shareGlxContext = static_cast<const QGLXContext*>(share)->glxContext(); GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(screen),screen->screenNumber(),format); m_context = glXCreateNewContext(DISPLAY_FROM_XCB(screen), config, GLX_RGBA_TYPE, shareGlxContext, TRUE); - m_windowFormat = qglx_platformWindowFromGLXFBConfig(DISPLAY_FROM_XCB(screen), config, m_context); + m_format = qglx_guiGLFormatFromGLXFBConfig(DISPLAY_FROM_XCB(screen), config, m_context); Q_XCB_NOOP(m_screen->connection()); } -QGLXContext::QGLXContext(QXcbScreen *screen, Drawable drawable, GLXContext context) - : QPlatformGLContext(), m_screen(screen), m_drawable(drawable), m_context(context) -{ - -} - QGLXContext::~QGLXContext() { Q_XCB_NOOP(m_screen->connection()); - if (m_context) - glXDestroyContext(DISPLAY_FROM_XCB(m_screen), m_context); + glXDestroyContext(DISPLAY_FROM_XCB(m_screen), m_context); Q_XCB_NOOP(m_screen->connection()); } -void QGLXContext::makeCurrent() +bool QGLXContext::makeCurrent(const QPlatformGLSurface &surface) { Q_XCB_NOOP(m_screen->connection()); - QPlatformGLContext::makeCurrent(); - glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), m_drawable, m_context); + + GLXDrawable glxSurface = static_cast<const QGLXSurface &>(surface).glxDrawable; + + bool result = glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), glxSurface, m_context); + Q_XCB_NOOP(m_screen->connection()); + return result; } void QGLXContext::doneCurrent() { - Q_XCB_NOOP(m_screen->connection()); - QPlatformGLContext::doneCurrent(); glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), 0, 0); - Q_XCB_NOOP(m_screen->connection()); } -void QGLXContext::swapBuffers() +void QGLXContext::swapBuffers(const QPlatformGLSurface &drawable) { Q_XCB_NOOP(m_screen->connection()); - glXSwapBuffers(DISPLAY_FROM_XCB(m_screen), m_drawable); + GLXDrawable glxDrawable = static_cast<const QGLXSurface &>(drawable).glxDrawable; + glXSwapBuffers(DISPLAY_FROM_XCB(m_screen), glxDrawable); Q_XCB_NOOP(m_screen->connection()); } -void* QGLXContext::getProcAddress(const QString& procName) +void (*QGLXContext::getProcAddress(const QByteArray &procName)) () { Q_XCB_NOOP(m_screen->connection()); typedef void *(*qt_glXGetProcAddressARB)(const GLubyte *); @@ -144,10 +144,10 @@ void* QGLXContext::getProcAddress(const QString& procName) } if (!glXGetProcAddressARB) return 0; - return glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName.toLatin1().data())); + return (void (*)())glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName.constData())); } -QPlatformWindowFormat QGLXContext::platformWindowFormat() const +QGuiGLFormat QGLXContext::format() const { - return m_windowFormat; + return m_format; } diff --git a/src/plugins/platforms/xcb/qglxintegration.h b/src/plugins/platforms/xcb/qglxintegration.h index 84de7b7143..ae95e23b81 100644 --- a/src/plugins/platforms/xcb/qglxintegration.h +++ b/src/plugins/platforms/xcb/qglxintegration.h @@ -45,34 +45,38 @@ #include "qxcbwindow.h" #include <QtGui/QPlatformGLContext> -#include <QtGui/QPlatformWindowFormat> +#include <QtGui/QGuiGLFormat> #include <QtCore/QMutex> #include <GL/glx.h> +class QGLXSurface : public QPlatformGLSurface +{ +public: + QGLXSurface(GLXDrawable drawable, const QGuiGLFormat &format); + GLXDrawable glxDrawable; +}; + class QGLXContext : public QPlatformGLContext { public: - QGLXContext(Window window, QXcbScreen *xd, const QPlatformWindowFormat &format); + QGLXContext(QXcbScreen *xd, const QGuiGLFormat &format, QPlatformGLContext *share); ~QGLXContext(); - virtual void makeCurrent(); - virtual void doneCurrent(); - virtual void swapBuffers(); - virtual void* getProcAddress(const QString& procName); + bool makeCurrent(const QPlatformGLSurface &surface); + void doneCurrent(); + void swapBuffers(const QPlatformGLSurface &surface); + void (*getProcAddress(const QByteArray &procName)) (); - GLXContext glxContext() const { return m_context; } + QGuiGLFormat format() const; - QPlatformWindowFormat platformWindowFormat() const; + GLXContext glxContext() const { return m_context; } private: QXcbScreen *m_screen; - Drawable m_drawable; GLXContext m_context; - QPlatformWindowFormat m_windowFormat; - - QGLXContext (QXcbScreen *screen, Drawable drawable, GLXContext context); + QGuiGLFormat m_format; }; #endif diff --git a/src/plugins/platforms/xcb/qxcbclipboard.cpp b/src/plugins/platforms/xcb/qxcbclipboard.cpp new file mode 100644 index 0000000000..e25192fcd7 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbclipboard.cpp @@ -0,0 +1,767 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxcbclipboard.h" + +#include "qxcbconnection.h" +#include "qxcbscreen.h" +#include "qxcbmime.h" + +#include <private/qguiapplication_p.h> +#include <QElapsedTimer> + +#include <QtCore/QDebug> + +#include <xcb/xcb_icccm.h> + +class QXcbClipboardMime : public QXcbMime +{ + Q_OBJECT +public: + QXcbClipboardMime(QClipboard::Mode mode, QXcbClipboard *clipboard) + : QXcbMime() + , m_clipboard(clipboard) + { + switch (mode) { + case QClipboard::Selection: + modeAtom = XCB_ATOM_PRIMARY; + break; + + case QClipboard::Clipboard: + modeAtom = m_clipboard->atom(QXcbAtom::CLIPBOARD); + break; + + default: + qWarning("QTestLiteMime: Internal error: Unsupported clipboard mode"); + break; + } + } + +protected: + QStringList formats_sys() const + { + if (empty()) + return QStringList(); + + if (!formatList.count()) { + QXcbClipboardMime *that = const_cast<QXcbClipboardMime *>(this); + // get the list of targets from the current clipboard owner - we do this + // once so that multiple calls to this function don't require multiple + // server round trips... + that->format_atoms = m_clipboard->getDataInFormat(modeAtom, m_clipboard->atom(QXcbAtom::TARGETS)); + + if (format_atoms.size() > 0) { + xcb_atom_t *targets = (xcb_atom_t *) format_atoms.data(); + int size = format_atoms.size() / sizeof(xcb_atom_t); + + for (int i = 0; i < size; ++i) { + if (targets[i] == 0) + continue; + + QString format = mimeAtomToString(m_clipboard->connection(), targets[i]); + if (!formatList.contains(format)) + that->formatList.append(format); + } + } + } + + return formatList; + } + + bool hasFormat_sys(const QString &format) const + { + QStringList list = formats(); + return list.contains(format); + } + + QVariant retrieveData_sys(const QString &fmt, QVariant::Type requestedType) const + { + if (fmt.isEmpty() || empty()) + return QByteArray(); + + (void)formats(); // trigger update of format list + + QList<xcb_atom_t> atoms; + xcb_atom_t *targets = (xcb_atom_t *) format_atoms.data(); + int size = format_atoms.size() / sizeof(xcb_atom_t); + for (int i = 0; i < size; ++i) + atoms.append(targets[i]); + + QByteArray encoding; + xcb_atom_t fmtatom = mimeAtomForFormat(m_clipboard->connection(), fmt, requestedType, atoms, &encoding); + + if (fmtatom == 0) + return QVariant(); + + return mimeConvertToFormat(m_clipboard->connection(), fmtatom, m_clipboard->getDataInFormat(modeAtom, fmtatom), fmt, requestedType, encoding); + } +private: + bool empty() const + { + return m_clipboard->getSelectionOwner(modeAtom) == XCB_NONE; + } + + + xcb_atom_t modeAtom; + QXcbClipboard *m_clipboard; + QStringList formatList; + QByteArray format_atoms; +}; + +const int QXcbClipboard::clipboard_timeout = 5000; + +QXcbClipboard::QXcbClipboard(QXcbConnection *c) + : QXcbObject(c), QPlatformClipboard() + , m_xClipboard(0) + , m_clientClipboard(0) + , m_xSelection(0) + , m_clientSelection(0) + , m_requestor(XCB_NONE) + , m_owner(XCB_NONE) +{ + m_screen = connection()->screens().at(connection()->primaryScreen()); +} + +xcb_window_t QXcbClipboard::getSelectionOwner(xcb_atom_t atom) const +{ + xcb_connection_t *c = xcb_connection(); + xcb_get_selection_owner_cookie_t cookie = xcb_get_selection_owner(c, atom); + xcb_get_selection_owner_reply_t *reply; + reply = xcb_get_selection_owner_reply(c, cookie, 0); + xcb_window_t win = reply->owner; + free(reply); + return win; +} + +QMimeData * QXcbClipboard::mimeData(QClipboard::Mode mode) +{ + if (mode == QClipboard::Clipboard) { + if (!m_xClipboard) { + m_xClipboard = new QXcbClipboardMime(mode, this); + } + xcb_window_t clipboardOwner = getSelectionOwner(atom(QXcbAtom::CLIPBOARD)); + if (clipboardOwner == owner()) { + return m_clientClipboard; + } else { + return m_xClipboard; + } + } else if (mode == QClipboard::Selection) { + if (!m_xSelection) { + m_xSelection = new QXcbClipboardMime(mode, this); + } + xcb_window_t clipboardOwner = getSelectionOwner(XCB_ATOM_PRIMARY); + if (clipboardOwner == owner()) { + return m_clientSelection; + } else { + return m_xSelection; + } + } + return 0; +} + +void QXcbClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode) +{ + xcb_atom_t modeAtom; + QMimeData **d; + switch (mode) { + case QClipboard::Selection: + modeAtom = XCB_ATOM_PRIMARY; + d = &m_clientSelection; + break; + + case QClipboard::Clipboard: + modeAtom = atom(QXcbAtom::CLIPBOARD); + d = &m_clientClipboard; + break; + + default: + qWarning("QClipboard::setMimeData: unsupported mode '%d'", mode); + return; + } + + xcb_window_t newOwner; + + if (! data) { // no data, clear clipboard contents + newOwner = XCB_NONE; + } else { + newOwner = owner(); + + *d = data; + } + + xcb_set_selection_owner(xcb_connection(), newOwner, modeAtom, connection()->time()); + + if (getSelectionOwner(modeAtom) != newOwner) { + qWarning("QClipboard::setData: Cannot set X11 selection owner"); + } + +} + +bool QXcbClipboard::supportsMode(QClipboard::Mode mode) const +{ + if (mode == QClipboard::Clipboard || mode == QClipboard::Selection) + return true; + return false; +} + +xcb_window_t QXcbClipboard::requestor() const +{ + if (!m_requestor) { + const int x = 0, y = 0, w = 3, h = 3; + QXcbClipboard *that = const_cast<QXcbClipboard *>(this); + + xcb_window_t window = xcb_generate_id(xcb_connection()); + Q_XCB_CALL(xcb_create_window(xcb_connection(), + XCB_COPY_FROM_PARENT, // depth -- same as root + window, // window id + m_screen->screen()->root, // parent window id + x, y, w, h, + 0, // border width + XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class + m_screen->screen()->root_visual, // visual + 0, // value mask + 0)); // value list + + uint32_t mask = XCB_EVENT_MASK_PROPERTY_CHANGE; + xcb_change_window_attributes(xcb_connection(), window, XCB_CW_EVENT_MASK, &mask); + + that->setRequestor(window); + } + return m_requestor; +} + +void QXcbClipboard::setRequestor(xcb_window_t window) +{ + if (m_requestor != XCB_NONE) { + xcb_destroy_window(xcb_connection(), m_requestor); + } + m_requestor = window; +} + +xcb_window_t QXcbClipboard::owner() const +{ + if (!m_owner) { + int x = 0, y = 0, w = 3, h = 3; + QXcbClipboard *that = const_cast<QXcbClipboard *>(this); + + xcb_window_t window = xcb_generate_id(xcb_connection()); + Q_XCB_CALL(xcb_create_window(xcb_connection(), + XCB_COPY_FROM_PARENT, // depth -- same as root + window, // window id + m_screen->screen()->root, // parent window id + x, y, w, h, + 0, // border width + XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class + m_screen->screen()->root_visual, // visual + 0, // value mask + 0)); // value list + + that->setOwner(window); + } + return m_owner; +} + +void QXcbClipboard::setOwner(xcb_window_t window) +{ + if (m_owner != XCB_NONE){ + xcb_destroy_window(xcb_connection(), m_owner); + } + m_owner = window; +} + +xcb_atom_t QXcbClipboard::sendTargetsSelection(QMimeData *d, xcb_window_t window, xcb_atom_t property) +{ + QVector<xcb_atom_t> types; + QStringList formats = QInternalMimeData::formatsHelper(d); + for (int i = 0; i < formats.size(); ++i) { + QList<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), formats.at(i)); + for (int j = 0; j < atoms.size(); ++j) { + if (!types.contains(atoms.at(j))) + types.append(atoms.at(j)); + } + } + types.append(atom(QXcbAtom::TARGETS)); + types.append(atom(QXcbAtom::MULTIPLE)); + types.append(atom(QXcbAtom::TIMESTAMP)); + types.append(atom(QXcbAtom::SAVE_TARGETS)); + + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property, XCB_ATOM_ATOM, + 32, types.size(), (const void *)types.constData()); + return property; +} + +xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_window_t window, xcb_atom_t property) +{ + xcb_atom_t atomFormat = target; + int dataFormat = 0; + QByteArray data; + + QString fmt = QXcbMime::mimeAtomToString(connection(), target); + if (fmt.isEmpty()) { // Not a MIME type we have +// qDebug() << "QClipboard: send_selection(): converting to type" << connection()->atomName(target) << "is not supported"; + return XCB_NONE; + } +// qDebug() << "QClipboard: send_selection(): converting to type" << fmt; + + if (QXcbMime::mimeDataForAtom(connection(), target, d, &data, &atomFormat, &dataFormat)) { + + // don't allow INCR transfers when using MULTIPLE or to + // Motif clients (since Motif doesn't support INCR) + static xcb_atom_t motif_clip_temporary = atom(QXcbAtom::CLIP_TEMPORARY); + bool allow_incr = property != motif_clip_temporary; + + // X_ChangeProperty protocol request is 24 bytes + const int increment = (xcb_get_maximum_request_length(xcb_connection()) * 4) - 24; + if (data.size() > increment && allow_incr) { + long bytes = data.size(); + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property, + atom(QXcbAtom::INCR), 32, 1, (const void *)&bytes); + +// (void)new QClipboardINCRTransaction(window, property, atomFormat, dataFormat, data, increment); + qWarning() << "not implemented INCR just YET!"; + return property; + } + + // make sure we can perform the XChangeProperty in a single request + if (data.size() > increment) + return XCB_NONE; // ### perhaps use several XChangeProperty calls w/ PropModeAppend? + int dataSize = data.size() / (dataFormat / 8); + // use a single request to transfer data + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property, atomFormat, + dataFormat, dataSize, (const void *)data.constData()); + } + return property; +} + +void QXcbClipboard::handleSelectionRequest(xcb_selection_request_event_t *req) +{ + if (requestor() && req->requestor == requestor()) { + qDebug() << "This should be caught before"; + return; + } + + xcb_selection_notify_event_t event; + event.response_type = XCB_SELECTION_NOTIFY; + event.requestor = req->requestor; + event.selection = req->selection; + event.target = req->target; + event.property = XCB_NONE; + event.time = req->time; + + QMimeData *d; + if (req->selection == XCB_ATOM_PRIMARY) { + d = m_clientSelection; + } else if (req->selection == atom(QXcbAtom::CLIPBOARD)) { + d = m_clientClipboard; + } else { + qWarning() << "QClipboard: Unknown selection" << connection()->atomName(req->selection); + xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event); + return; + } + + if (!d) { + qWarning("QClipboard: Cannot transfer data, no data available"); + xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event); + return; + } + + xcb_atom_t xa_targets = atom(QXcbAtom::TARGETS); + xcb_atom_t xa_multiple = atom(QXcbAtom::MULTIPLE); + xcb_atom_t xa_timestamp = atom(QXcbAtom::TIMESTAMP); + + struct AtomPair { xcb_atom_t target; xcb_atom_t property; } *multi = 0; + xcb_atom_t multi_type = XCB_NONE; + int multi_format = 0; + int nmulti = 0; + int imulti = -1; + bool multi_writeback = false; + + if (req->target == xa_multiple) { + QByteArray multi_data; + if (req->property == XCB_NONE + || !clipboardReadProperty(req->requestor, req->property, false, &multi_data, + 0, &multi_type, &multi_format) + || multi_format != 32) { + // MULTIPLE property not formatted correctly + xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event); + return; + } + nmulti = multi_data.size()/sizeof(*multi); + multi = new AtomPair[nmulti]; + memcpy(multi,multi_data.data(),multi_data.size()); + imulti = 0; + } + + for (; imulti < nmulti; ++imulti) { + xcb_atom_t target; + xcb_atom_t property; + + if (multi) { + target = multi[imulti].target; + property = multi[imulti].property; + } else { + target = req->target; + property = req->property; + if (property == XCB_NONE) // obsolete client + property = target; + } + + xcb_atom_t ret = XCB_NONE; + if (target == XCB_NONE || property == XCB_NONE) { + ; + } else if (target == xa_timestamp) { +// if (d->timestamp != CurrentTime) { +// XChangeProperty(DISPLAY_FROM_XCB(connection()), req->requestor, property, QXcbAtom::XA_INTEGER, 32, +// PropModeReplace, CurrentTime, 1); +// ret = property; +// } else { +// qWarning("QClipboard: Invalid data timestamp"); +// } + } else if (target == xa_targets) { + ret = sendTargetsSelection(d, req->requestor, property); + } else { + ret = sendSelection(d, target, req->requestor, property); + } + + if (nmulti > 0) { + if (ret == XCB_NONE) { + multi[imulti].property = XCB_NONE; + multi_writeback = true; + } + } else { + event.property = ret; + break; + } + } + + if (nmulti > 0) { + if (multi_writeback) { + // according to ICCCM 2.6.2 says to put None back + // into the original property on the requestor window + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, req->requestor, req->property, + multi_type, 32, nmulti*2, (const void *)multi); + } + + delete [] multi; + event.property = req->property; + } + + // send selection notify to requestor + xcb_send_event(xcb_connection(), false, req->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)&event); +} + +static inline int maxSelectionIncr(xcb_connection_t *c) +{ + int l = xcb_get_maximum_request_length(c); + return (l > 65536 ? 65536*4 : l*4) - 100; +} + +bool QXcbClipboard::clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format) const +{ + int maxsize = maxSelectionIncr(xcb_connection()); + ulong bytes_left; // bytes_after + xcb_atom_t dummy_type; + int dummy_format; + + if (!type) // allow null args + type = &dummy_type; + if (!format) + format = &dummy_format; + + // Don't read anything, just get the size of the property data + xcb_get_property_cookie_t cookie = Q_XCB_CALL(xcb_get_property(xcb_connection(), false, win, property, XCB_GET_PROPERTY_TYPE_ANY, 0, 0)); + xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, 0); + if (!reply || reply->type == XCB_NONE) { + buffer->resize(0); + return false; + } + *type = reply->type; + *format = reply->format; + bytes_left = reply->bytes_after; + free(reply); + + int offset = 0, buffer_offset = 0, format_inc = 1, proplen = bytes_left; + + switch (*format) { + case 8: + default: + format_inc = sizeof(char) / 1; + break; + + case 16: + format_inc = sizeof(short) / 2; + proplen *= sizeof(short) / 2; + break; + + case 32: + format_inc = sizeof(long) / 4; + proplen *= sizeof(long) / 4; + break; + } + + int newSize = proplen; + buffer->resize(newSize); + + bool ok = (buffer->size() == newSize); + + if (ok && newSize) { + // could allocate buffer + + while (bytes_left) { + // more to read... + + xcb_get_property_cookie_t cookie = Q_XCB_CALL(xcb_get_property(xcb_connection(), false, win, property, XCB_GET_PROPERTY_TYPE_ANY, offset, maxsize/4)); + reply = xcb_get_property_reply(xcb_connection(), cookie, 0); + if (!reply || reply->type == XCB_NONE) { + free(reply); + break; + } + *type = reply->type; + *format = reply->format; + bytes_left = reply->bytes_after; + char *data = (char *)xcb_get_property_value(reply); + int length = xcb_get_property_value_length(reply); + + offset += length / (32 / *format); + length *= format_inc * (*format) / 8; + + // Here we check if we get a buffer overflow and tries to + // recover -- this shouldn't normally happen, but it doesn't + // hurt to be defensive + if ((int)(buffer_offset + length) > buffer->size()) { + length = buffer->size() - buffer_offset; + + // escape loop + bytes_left = 0; + } + + memcpy(buffer->data() + buffer_offset, data, length); + buffer_offset += length; + + free(reply); + } + } + + + // correct size, not 0-term. + if (size) + *size = buffer_offset; + + if (deleteProperty) + xcb_delete_property(xcb_connection(), win, property); + + connection()->flush(); + + return ok; +} + + +namespace +{ + class Notify { + public: + Notify(xcb_window_t win, int t) + : window(win), type(t) {} + xcb_window_t window; + int type; + bool check(xcb_generic_event_t *event) const { + if (!event) + return false; + int t = event->response_type & 0x7f; + if (t != type) + return false; + if (t == XCB_PROPERTY_NOTIFY) { + xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event; + if (pn->window == window) + return true; + } else if (t == XCB_SELECTION_NOTIFY) { + xcb_selection_notify_event_t *sn = (xcb_selection_notify_event_t *)event; + if (sn->requestor == window) + return true; + } + return false; + } + }; + class ClipboardEvent { + public: + ClipboardEvent(QXcbConnection *c) + { clipboard = c->internAtom("CLIPBOARD"); } + xcb_atom_t clipboard; + bool check(xcb_generic_event_t *e) const { + if (!e) + return false; + int type = e->response_type & 0x7f; + if (type == XCB_SELECTION_REQUEST) { + xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)e; + return sr->selection == XCB_ATOM_PRIMARY || sr->selection == clipboard; + } else if (type == XCB_SELECTION_CLEAR) { + xcb_selection_clear_event_t *sc = (xcb_selection_clear_event_t *)e; + return sc->selection == XCB_ATOM_PRIMARY || sc->selection == clipboard; + } + return false; + } + }; +} + +xcb_generic_event_t *QXcbClipboard::waitForClipboardEvent(xcb_window_t win, int type, int timeout) +{ + QElapsedTimer timer; + timer.start(); + do { + Notify notify(win, type); + xcb_generic_event_t *e = connection()->checkEvent(notify); + if (e) + return e; + + // process other clipboard events, since someone is probably requesting data from us + ClipboardEvent clipboard(connection()); + e = connection()->checkEvent(clipboard); + if (e) { + connection()->handleXcbEvent(e); + free(e); + } + + connection()->flush(); + + // sleep 50 ms, so we don't use up CPU cycles all the time. + struct timeval usleep_tv; + usleep_tv.tv_sec = 0; + usleep_tv.tv_usec = 50000; + select(0, 0, 0, 0, &usleep_tv); + } while (timer.elapsed() < timeout); + + return 0; +} + +QByteArray QXcbClipboard::clipboardReadIncrementalProperty(xcb_window_t win, xcb_atom_t property, int nbytes, bool nullterm) +{ + QByteArray buf; + QByteArray tmp_buf; + bool alloc_error = false; + int length; + int offset = 0; + + if (nbytes > 0) { + // Reserve buffer + zero-terminator (for text data) + // We want to complete the INCR transfer even if we cannot + // allocate more memory + buf.resize(nbytes+1); + alloc_error = buf.size() != nbytes+1; + } + + for (;;) { + connection()->flush(); + xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_PROPERTY_NOTIFY, clipboard_timeout); + if (!ge) + break; + + xcb_property_notify_event_t *event = (xcb_property_notify_event_t *)ge; + if (event->atom != property || event->state != XCB_PROPERTY_NEW_VALUE) + continue; + if (clipboardReadProperty(win, property, true, &tmp_buf, &length, 0, 0)) { + if (length == 0) { // no more data, we're done + if (nullterm) { + buf.resize(offset+1); + buf[offset] = '\0'; + } else { + buf.resize(offset); + } + return buf; + } else if (!alloc_error) { + if (offset+length > (int)buf.size()) { + buf.resize(offset+length+65535); + if (buf.size() != offset+length+65535) { + alloc_error = true; + length = buf.size() - offset; + } + } + memcpy(buf.data()+offset, tmp_buf.constData(), length); + tmp_buf.resize(0); + offset += length; + } + } else { + break; + } + + free(ge); + } + + // timed out ... create a new requestor window, otherwise the requestor + // could consider next request to be still part of this timed out request + setRequestor(0); + + return QByteArray(); +} + +QByteArray QXcbClipboard::getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtAtom) +{ + return getSelection(modeAtom, fmtAtom, atom(QXcbAtom::_QT_SELECTION)); +} + +QByteArray QXcbClipboard::getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property) +{ + QByteArray buf; + xcb_window_t win = requestor(); + + xcb_delete_property(xcb_connection(), win, property); + xcb_convert_selection(xcb_connection(), win, selection, target, property, connection()->time()); + + connection()->sync(); + + xcb_generic_event_t *ge = waitForClipboardEvent(win, XCB_SELECTION_NOTIFY, clipboard_timeout); + bool no_selection = !ge || ((xcb_selection_notify_event_t *)ge)->property == XCB_NONE; + free(ge); + + if (no_selection) + return buf; + + xcb_atom_t type; + if (clipboardReadProperty(win, property, true, &buf, 0, &type, 0)) { + if (type == atom(QXcbAtom::INCR)) { + int nbytes = buf.size() >= 4 ? *((int*)buf.data()) : 0; + buf = clipboardReadIncrementalProperty(win, property, nbytes, false); + } + } + + return buf; +} + +#include "qxcbclipboard.moc" diff --git a/src/plugins/platforms/xcb/qxcbclipboard.h b/src/plugins/platforms/xcb/qxcbclipboard.h new file mode 100644 index 0000000000..ff2d44144e --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbclipboard.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXCBCLIPBOARD_H +#define QXCBCLIPBOARD_H + +#include <QPlatformClipboard> +#include <qxcbobject.h> +#include <xcb/xcb.h> + +class QXcbConnection; +class QXcbScreen; + +class QXcbClipboard : public QXcbObject, public QPlatformClipboard +{ +public: + QXcbClipboard(QXcbConnection *connection); + + QMimeData *mimeData(QClipboard::Mode mode); + void setMimeData(QMimeData *data, QClipboard::Mode mode); + + bool supportsMode(QClipboard::Mode mode) const; + + QXcbScreen *screen() const { return m_screen; } + + xcb_window_t requestor() const; + void setRequestor(xcb_window_t window); + + xcb_window_t owner() const; + + void handleSelectionRequest(xcb_selection_request_event_t *event); + + bool clipboardReadProperty(xcb_window_t win, xcb_atom_t property, bool deleteProperty, QByteArray *buffer, int *size, xcb_atom_t *type, int *format) const; + QByteArray clipboardReadIncrementalProperty(xcb_window_t win, xcb_atom_t property, int nbytes, bool nullterm); + + QByteArray getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtatom); + + xcb_window_t getSelectionOwner(xcb_atom_t atom) const; + QByteArray getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property); + +private: + void setOwner(xcb_window_t window); + + xcb_generic_event_t *waitForClipboardEvent(xcb_window_t win, int type, int timeout); + + xcb_atom_t sendTargetsSelection(QMimeData *d, xcb_window_t window, xcb_atom_t property); + xcb_atom_t sendSelection(QMimeData *d, xcb_atom_t target, xcb_window_t window, xcb_atom_t property); + + QXcbScreen *m_screen; + + QMimeData *m_xClipboard; + QMimeData *m_clientClipboard; + + QMimeData *m_xSelection; + QMimeData *m_clientSelection; + + xcb_window_t m_requestor; + xcb_window_t m_owner; + + static const int clipboard_timeout; + +}; + +#endif // QXCBCLIPBOARD_H diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 80a1624380..0af71fa830 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -43,29 +43,36 @@ #include "qxcbkeyboard.h" #include "qxcbscreen.h" #include "qxcbwindow.h" +#include "qxcbclipboard.h" +#include "qxcbdrag.h" +#include "qxcbwmsupport.h" #include <QtAlgorithms> #include <QSocketNotifier> -#include <QtGui/private/qapplication_p.h> +#include <QtGui/private/qguiapplication_p.h> #include <QAbstractEventDispatcher> #include <QtCore/QDebug> #include <stdio.h> #include <errno.h> +#include <xcb/xfixes.h> #ifdef XCB_USE_XLIB #include <X11/Xlib.h> #include <X11/Xlib-xcb.h> #endif +#ifdef XCB_USE_RENDER +#include <xcb/render.h> +#endif + #ifdef XCB_USE_EGL //dont pull in eglext prototypes #include <EGL/egl.h> #endif #ifdef XCB_USE_DRI2 #include <xcb/dri2.h> -#include <xcb/xfixes.h> extern "C" { #include <xf86drm.h> } @@ -84,11 +91,11 @@ QXcbConnection::QXcbConnection(const char *displayName) , m_has_support_for_dri2(false) #endif { - int primaryScreen = 0; + m_primaryScreen = 0; #ifdef XCB_USE_XLIB Display *dpy = XOpenDisplay(m_displayName.constData()); - primaryScreen = DefaultScreen(dpy); + m_primaryScreen = DefaultScreen(dpy); m_connection = XGetXCBConnection(dpy); XSetEventQueueOwner(dpy, XCBOwnsEventQueue); m_xlib_display = dpy; @@ -107,6 +114,8 @@ QXcbConnection::QXcbConnection(const char *displayName) initializeAllAtoms(); + m_time = XCB_CURRENT_TIME; + xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup); int screenNumber = 0; @@ -115,7 +124,13 @@ QXcbConnection::QXcbConnection(const char *displayName) xcb_screen_next(&it); } + m_wmSupport = new QXcbWMSupport(this); m_keyboard = new QXcbKeyboard(this); + m_clipboard = new QXcbClipboard(this); + m_drag = new QXcbDrag(this); + + initializeXFixes(); + initializeXRender(); #ifdef XCB_USE_DRI2 initializeDri2(); @@ -126,6 +141,7 @@ QXcbConnection::QXcbConnection(const char *displayName) QAbstractEventDispatcher *dispatcher = QAbstractEventDispatcher::instance(qApp->thread()); connect(dispatcher, SIGNAL(aboutToBlock()), this, SLOT(processXcbEvents())); + connect(dispatcher, SIGNAL(awake()), this, SLOT(processXcbEvents())); sync(); } @@ -141,24 +157,29 @@ QXcbConnection::~QXcbConnection() #endif delete m_keyboard; + delete m_clipboard; } -QXcbWindow *platformWindowFromId(xcb_window_t id) +void QXcbConnection::addWindow(xcb_window_t id, QXcbWindow *window) { - QWidget *widget = QWidget::find(id); - if (widget) - return static_cast<QXcbWindow *>(widget->platformWindow()); - return 0; + m_mapper.insert(id, window); +} + +void QXcbConnection::removeWindow(xcb_window_t id) +{ + m_mapper.remove(id); } -#define HANDLE_PLATFORM_WINDOW_EVENT(event_t, window, handler) \ +QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id) +{ + return m_mapper.value(id, 0); +} + +#define HANDLE_PLATFORM_WINDOW_EVENT(event_t, windowMember, handler) \ { \ event_t *e = (event_t *)event; \ - if (QXcbWindow *platformWindow = platformWindowFromId(e->window)) { \ - QObjectPrivate *d = QObjectPrivate::get(platformWindow->widget()); \ - if (!d->wasDeleted) \ - platformWindow->handler(e); \ - } \ + if (QXcbWindow *platformWindow = platformWindowFromId(e->windowMember)) \ + platformWindow->handler(e); \ } \ break; @@ -166,7 +187,7 @@ break; { \ event_t *e = (event_t *)event; \ if (QXcbWindow *platformWindow = platformWindowFromId(e->event)) \ - m_keyboard->handler(platformWindow->widget(), e); \ + m_keyboard->handler(platformWindow, e); \ } \ break; @@ -409,69 +430,167 @@ void QXcbConnection::handleXcbError(xcb_generic_error_t *error) #endif } +void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) +{ +#ifdef Q_XCB_DEBUG + { + int i = 0; + for (; i < m_callLog.size(); ++i) + if (m_callLog.at(i).sequence >= event->sequence) + break; + m_callLog.remove(0, i); + } +#endif + bool handled = true; + + uint response_type = event->response_type & ~0x80; + + switch (response_type) { + case XCB_EXPOSE: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent); + case XCB_BUTTON_PRESS: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent); + case XCB_BUTTON_RELEASE: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent); + case XCB_MOTION_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent); + case XCB_CONFIGURE_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent); + case XCB_MAP_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_map_notify_event_t, event, handleMapNotifyEvent); + case XCB_UNMAP_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_unmap_notify_event_t, event, handleUnmapNotifyEvent); + case XCB_CLIENT_MESSAGE: + handleClientMessageEvent((xcb_client_message_event_t *)event); + case XCB_ENTER_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent); + case XCB_LEAVE_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent); + case XCB_FOCUS_IN: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent); + case XCB_FOCUS_OUT: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent); + case XCB_KEY_PRESS: + HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent); + case XCB_KEY_RELEASE: + HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent); + case XCB_MAPPING_NOTIFY: + m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event); + break; + case XCB_SELECTION_REQUEST: + { + xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)event; + if (sr->selection == atom(QXcbAtom::XdndSelection)) + m_drag->handleSelectionRequest(sr); + else + m_clipboard->handleSelectionRequest(sr); + break; + } + case XCB_SELECTION_CLEAR: + setTime(((xcb_selection_clear_event_t *)event)->time); + qDebug() << "XCB_SELECTION_CLEAR"; + handled = false; + break; + case XCB_SELECTION_NOTIFY: + qDebug() << "XCB_SELECTION_NOTIFY"; + handled = false; + break; + case XCB_PROPERTY_NOTIFY: + setTime(((xcb_property_notify_event_t *)event)->time); +// qDebug() << "XCB_PROPERTY_NOTIFY"; + handled = false; + break; + default: + handled = false; + break; + } + if (handled) + printXcbEvent("Handled XCB event", event); + else + printXcbEvent("Unhandled XCB event", event); +} + +void QXcbConnection::addPeekFunc(PeekFunc f) +{ + m_peekFuncs.append(f); +} + void QXcbConnection::processXcbEvents() { - while (xcb_generic_event_t *event = xcb_poll_for_event(xcb_connection())) { - bool handled = true; + while (xcb_generic_event_t *event = xcb_poll_for_event(xcb_connection())) + eventqueue.append(event); + + for(int i = 0; i < eventqueue.size(); ++i) { + xcb_generic_event_t *event = eventqueue.at(i); + if (!event) + continue; + eventqueue[i] = 0; uint response_type = event->response_type & ~0x80; if (!response_type) { handleXcbError((xcb_generic_error_t *)event); - continue; + } else { + QVector<PeekFunc>::iterator it = m_peekFuncs.begin(); + while (it != m_peekFuncs.end()) { + // These callbacks return true if the event is what they were + // waiting for, remove them from the list in that case. + if ((*it)(event)) + it = m_peekFuncs.erase(it); + else + ++it; + } + handleXcbEvent(event); } -#ifdef Q_XCB_DEBUG - { - int i = 0; - for (; i < m_callLog.size(); ++i) - if (m_callLog.at(i).sequence >= event->sequence) - break; - m_callLog.remove(0, i); - } -#endif - - switch (response_type) { - case XCB_EXPOSE: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent); - case XCB_BUTTON_PRESS: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent); - case XCB_BUTTON_RELEASE: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent); - case XCB_MOTION_NOTIFY: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent); - case XCB_CONFIGURE_NOTIFY: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent); - case XCB_CLIENT_MESSAGE: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_client_message_event_t, window, handleClientMessageEvent); - case XCB_ENTER_NOTIFY: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent); - case XCB_LEAVE_NOTIFY: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent); - case XCB_FOCUS_IN: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent); - case XCB_FOCUS_OUT: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent); - case XCB_KEY_PRESS: - HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent); - case XCB_KEY_RELEASE: - HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent); - case XCB_MAPPING_NOTIFY: - m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event); - break; - default: - handled = false; - break; - } - if (handled) - printXcbEvent("Handled XCB event", event); - else - printXcbEvent("Unhandled XCB event", event); + free(event); } + eventqueue.clear(); + + // Indicate with a null event that the event the callbacks are waiting for + // is not in the queue currently. + Q_FOREACH (PeekFunc f, m_peekFuncs) + f(0); + m_peekFuncs.clear(); + xcb_flush(xcb_connection()); } +void QXcbConnection::handleClientMessageEvent(const xcb_client_message_event_t *event) +{ + if (event->format != 32) + return; + + if (event->type == atom(QXcbAtom::XdndStatus)) { + drag()->handleStatus(event, false); + } else if (event->type == atom(QXcbAtom::XdndFinished)) { + drag()->handleFinished(event, false); + } + + QXcbWindow *window = platformWindowFromId(event->window); + if (!window) + return; + + window->handleClientMessageEvent(event); +} + + +xcb_generic_event_t *QXcbConnection::checkEvent(int type) +{ + while (xcb_generic_event_t *event = xcb_poll_for_event(xcb_connection())) + eventqueue.append(event); + + for (int i = 0; i < eventqueue.size(); ++i) { + xcb_generic_event_t *event = eventqueue.at(i); + if (event->response_type == type) { + eventqueue[i] = 0; + return event; + } + } + return 0; +} + static const char * xcb_atomnames = { // window-manager <-> client protocols "WM_PROTOCOLS\0" @@ -579,7 +698,6 @@ static const char * xcb_atomnames = { "_NET_ACTIVE_WINDOW\0" // Property formats - "COMPOUND_TEXT\0" "TEXT\0" "UTF8_STRING\0" @@ -659,8 +777,57 @@ void QXcbConnection::initializeAllAtoms() { for (i = 0; i < QXcbAtom::NAtoms; ++i) cookies[i] = xcb_intern_atom(xcb_connection(), false, strlen(names[i]), names[i]); - for (i = 0; i < QXcbAtom::NAtoms; ++i) - m_allAtoms[i] = xcb_intern_atom_reply(xcb_connection(), cookies[i], 0)->atom; + for (i = 0; i < QXcbAtom::NAtoms; ++i) { + xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcb_connection(), cookies[i], 0); + m_allAtoms[i] = reply->atom; + free(reply); + } +} + +xcb_atom_t QXcbConnection::internAtom(const char *name) +{ + if (!name || *name == 0) + return XCB_NONE; + + xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xcb_connection(), false, strlen(name), name); + xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcb_connection(), cookie, 0); + int atom = reply->atom; + free(reply); + return atom; +} + +QByteArray QXcbConnection::atomName(xcb_atom_t atom) +{ + if (!atom) + return QByteArray(); + + xcb_generic_error_t *error = 0; + xcb_get_atom_name_cookie_t cookie = Q_XCB_CALL(xcb_get_atom_name(xcb_connection(), atom)); + xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(xcb_connection(), cookie, &error); + if (error) { + qWarning() << "QXcbConnection::atomName: bad Atom" << atom; + } + if (reply) { + QByteArray result(xcb_get_atom_name_name(reply), xcb_get_atom_name_name_length(reply)); + free(reply); + return result; + } + 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() @@ -670,6 +837,39 @@ void QXcbConnection::sync() free(xcb_get_input_focus_reply(xcb_connection(), cookie, 0)); } +void QXcbConnection::initializeXFixes() +{ + xcb_generic_error_t *error = 0; + xcb_prefetch_extension_data (m_connection, &xcb_xfixes_id); + xcb_xfixes_query_version_cookie_t xfixes_query_cookie = xcb_xfixes_query_version(m_connection, + XCB_XFIXES_MAJOR_VERSION, + XCB_XFIXES_MINOR_VERSION); + xcb_xfixes_query_version_reply_t *xfixes_query = xcb_xfixes_query_version_reply (m_connection, + xfixes_query_cookie, &error); + if (!xfixes_query || error || xfixes_query->major_version < 2) { + qWarning("Failed to initialize XFixes"); + free(error); + } + free(xfixes_query); +} + +void QXcbConnection::initializeXRender() +{ +#ifdef XCB_USE_RENDER + xcb_generic_error_t *error = 0; + xcb_render_query_version_cookie_t xrender_query_cookie = xcb_render_query_version(m_connection, + XCB_RENDER_MAJOR_VERSION, + XCB_RENDER_MINOR_VERSION); + xcb_render_query_version_reply_t *xrender_query = xcb_render_query_version_reply(m_connection, + xrender_query_cookie, &error); + if (!xrender_query || error || (xrender_query->major_version == 0 && xrender_query->minor_version < 5)) { + qWarning("Failed to initialize XRender"); + free(error); + } + free(xrender_query); +#endif +} + #if defined(XCB_USE_EGL) bool QXcbConnection::hasEgl() const { @@ -740,26 +940,12 @@ bool QXcbConnection::hasSupportForDri2() const if (!m_dri2_support_probed) { xcb_generic_error_t *error = 0; - xcb_prefetch_extension_data (m_connection, &xcb_xfixes_id); xcb_prefetch_extension_data (m_connection, &xcb_dri2_id); - xcb_xfixes_query_version_cookie_t xfixes_query_cookie = xcb_xfixes_query_version(m_connection, - XCB_XFIXES_MAJOR_VERSION, - XCB_XFIXES_MINOR_VERSION); - xcb_dri2_query_version_cookie_t dri2_query_cookie = xcb_dri2_query_version (m_connection, XCB_DRI2_MAJOR_VERSION, XCB_DRI2_MINOR_VERSION); - xcb_xfixes_query_version_reply_t *xfixes_query = xcb_xfixes_query_version_reply (m_connection, - xfixes_query_cookie, &error); - if (!xfixes_query || error || xfixes_query->major_version < 2) { - delete error; - delete xfixes_query; - return false; - } - delete xfixes_query; - xcb_dri2_query_version_reply_t *dri2_query = xcb_dri2_query_version_reply (m_connection, dri2_query_cookie, &error); if (!dri2_query || error) { diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 01bc719546..9413b682c3 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -44,6 +44,7 @@ #include <xcb/xcb.h> +#include <QHash> #include <QList> #include <QObject> #include <QVector> @@ -51,6 +52,13 @@ #define Q_XCB_DEBUG class QXcbScreen; +class QXcbWindow; +class QXcbDrag; +class QXcbKeyboard; +class QXcbClipboard; +class QXcbWMSupport; + +typedef QHash<xcb_window_t, QXcbWindow *> WindowMapper; namespace QXcbAtom { enum Atom { @@ -160,7 +168,6 @@ namespace QXcbAtom { _NET_ACTIVE_WINDOW, // Property formats - COMPOUND_TEXT, TEXT, UTF8_STRING, @@ -215,8 +222,6 @@ namespace QXcbAtom { }; } -class QXcbKeyboard; - class QXcbConnection : public QObject { Q_OBJECT @@ -226,17 +231,26 @@ public: QXcbConnection *connection() const { return const_cast<QXcbConnection *>(this); } - QList<QXcbScreen *> screens() const { return m_screens; } + const QList<QXcbScreen *> &screens() const { return m_screens; } int primaryScreen() const { return m_primaryScreen; } xcb_atom_t atom(QXcbAtom::Atom atom); + xcb_atom_t internAtom(const char *name); + QByteArray atomName(xcb_atom_t atom); 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; } + QXcbClipboard *clipboard() const { return m_clipboard; } + QXcbDrag *drag() const { return m_drag; } + + QXcbWMSupport *wmSupport() const { return m_wmSupport; } + #ifdef XCB_USE_XLIB void *xlib_display() const { return m_xlib_display; } #endif @@ -253,7 +267,24 @@ public: #endif void sync(); + void flush() { xcb_flush(m_connection); } + void handleXcbError(xcb_generic_error_t *error); + void handleXcbEvent(xcb_generic_event_t *event); + + void addWindow(xcb_window_t id, QXcbWindow *window); + void removeWindow(xcb_window_t id); + QXcbWindow *platformWindowFromId(xcb_window_t id); + + xcb_generic_event_t *checkEvent(int type); + template<typename T> + inline xcb_generic_event_t *checkEvent(const T &checker); + + typedef bool (*PeekFunc)(xcb_generic_event_t *); + void addPeekFunc(PeekFunc f); + + inline xcb_timestamp_t time() const { return m_time; } + inline void setTime(xcb_timestamp_t t) { if (t > m_time) m_time = t; } private slots: void processXcbEvents(); @@ -261,9 +292,12 @@ private slots: private: void initializeAllAtoms(); void sendConnectionEvent(QXcbAtom::Atom atom, uint id = 0); + void initializeXFixes(); + void initializeXRender(); #ifdef XCB_USE_DRI2 void initializeDri2(); #endif + void handleClientMessageEvent(const xcb_client_message_event_t *event); xcb_connection_t *m_connection; const xcb_setup_t *m_setup; @@ -273,9 +307,14 @@ private: xcb_atom_t m_allAtoms[QXcbAtom::NAtoms]; + xcb_timestamp_t m_time; + QByteArray m_displayName; QXcbKeyboard *m_keyboard; + QXcbClipboard *m_clipboard; + QXcbDrag *m_drag; + QXcbWMSupport *m_wmSupport; #if defined(XCB_USE_XLIB) void *m_xlib_display; @@ -303,10 +342,32 @@ private: template <typename cookie_t> friend cookie_t q_xcb_call_template(const cookie_t &cookie, QXcbConnection *connection, const char *file, int line); #endif + QVector<xcb_generic_event_t *> eventqueue; + + WindowMapper m_mapper; + + QVector<PeekFunc> m_peekFuncs; }; #define DISPLAY_FROM_XCB(object) ((Display *)(object->connection()->xlib_display())) +template<typename T> +xcb_generic_event_t *QXcbConnection::checkEvent(const T &checker) +{ + while (xcb_generic_event_t *event = xcb_poll_for_event(xcb_connection())) + eventqueue.append(event); + + for (int i = 0; i < eventqueue.size(); ++i) { + xcb_generic_event_t *event = eventqueue.at(i); + if (checker.check(event)) { + eventqueue[i] = 0; + return event; + } + } + return 0; +} + + #ifdef Q_XCB_DEBUG template <typename cookie_t> cookie_t q_xcb_call_template(const cookie_t &cookie, QXcbConnection *connection, const char *file, int line) diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp new file mode 100644 index 0000000000..f6856d5694 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -0,0 +1,546 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxcbcursor.h" +#include "qxcbconnection.h" +#include "qxcbwindow.h" +#include "qxcbimage.h" +#include <QtCore/QLibrary> +#include <QtGui/QWindow> +#include <QtGui/QBitmap> +#include <QtGui/private/qguiapplication_p.h> +#include <X11/cursorfont.h> +#include <xcb/xfixes.h> +#include <xcb/xcb_image.h> + +QT_BEGIN_NAMESPACE + +typedef int (*PtrXcursorLibraryLoadCursor)(void *, const char *); +static PtrXcursorLibraryLoadCursor ptrXcursorLibraryLoadCursor = 0; +static xcb_font_t cursorFont = 0; +static int cursorCount = 0; + +static uint8_t cur_blank_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +static const uint8_t cur_ver_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f, + 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xf0, 0x0f, + 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00 }; +static const uint8_t mcur_ver_bits[] = { + 0x00, 0x00, 0x80, 0x03, 0xc0, 0x07, 0xe0, 0x0f, 0xf0, 0x1f, 0xf8, 0x3f, + 0xfc, 0x7f, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xfc, 0x7f, 0xf8, 0x3f, + 0xf0, 0x1f, 0xe0, 0x0f, 0xc0, 0x07, 0x80, 0x03 }; +static const uint8_t cur_hor_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x08, 0x30, 0x18, + 0x38, 0x38, 0xfc, 0x7f, 0xfc, 0x7f, 0x38, 0x38, 0x30, 0x18, 0x20, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t mcur_hor_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x60, 0x0c, 0x70, 0x1c, 0x78, 0x3c, + 0xfc, 0x7f, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfc, 0x7f, 0x78, 0x3c, + 0x70, 0x1c, 0x60, 0x0c, 0x40, 0x04, 0x00, 0x00 }; +static const uint8_t cur_bdiag_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3c, 0x00, 0x3e, + 0x00, 0x37, 0x88, 0x23, 0xd8, 0x01, 0xf8, 0x00, 0x78, 0x00, 0xf8, 0x00, + 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t mcur_bdiag_bits[] = { + 0x00, 0x00, 0xc0, 0x7f, 0x80, 0x7f, 0x00, 0x7f, 0x00, 0x7e, 0x04, 0x7f, + 0x8c, 0x7f, 0xdc, 0x77, 0xfc, 0x63, 0xfc, 0x41, 0xfc, 0x00, 0xfc, 0x01, + 0xfc, 0x03, 0xfc, 0x07, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t cur_fdiag_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x01, 0xf8, 0x00, 0x78, 0x00, + 0xf8, 0x00, 0xd8, 0x01, 0x88, 0x23, 0x00, 0x37, 0x00, 0x3e, 0x00, 0x3c, + 0x00, 0x3e, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t mcur_fdiag_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x07, 0xfc, 0x03, 0xfc, 0x01, 0xfc, 0x00, + 0xfc, 0x41, 0xfc, 0x63, 0xdc, 0x77, 0x8c, 0x7f, 0x04, 0x7f, 0x00, 0x7e, + 0x00, 0x7f, 0x80, 0x7f, 0xc0, 0x7f, 0x00, 0x00 }; +static const uint8_t *cursor_bits16[] = { + cur_ver_bits, mcur_ver_bits, cur_hor_bits, mcur_hor_bits, + cur_bdiag_bits, mcur_bdiag_bits, cur_fdiag_bits, mcur_fdiag_bits, + 0, 0, cur_blank_bits, cur_blank_bits }; + +static const uint8_t vsplit_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, + 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t vsplitm_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x07, 0x00, + 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, + 0x00, 0xc0, 0x01, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00, + 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00, + 0x80, 0xff, 0xff, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00, + 0x00, 0xc0, 0x01, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, + 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t hsplit_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, + 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, + 0x00, 0x41, 0x82, 0x00, 0x80, 0x41, 0x82, 0x01, 0xc0, 0x7f, 0xfe, 0x03, + 0x80, 0x41, 0x82, 0x01, 0x00, 0x41, 0x82, 0x00, 0x00, 0x40, 0x02, 0x00, + 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, + 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t hsplitm_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, + 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe3, 0xc7, 0x00, + 0x80, 0xe3, 0xc7, 0x01, 0xc0, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x07, + 0xc0, 0xff, 0xff, 0x03, 0x80, 0xe3, 0xc7, 0x01, 0x00, 0xe3, 0xc7, 0x00, + 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, + 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static const uint8_t whatsthis_bits[] = { + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0xf0, 0x07, 0x00, + 0x09, 0x18, 0x0e, 0x00, 0x11, 0x1c, 0x0e, 0x00, 0x21, 0x1c, 0x0e, 0x00, + 0x41, 0x1c, 0x0e, 0x00, 0x81, 0x1c, 0x0e, 0x00, 0x01, 0x01, 0x07, 0x00, + 0x01, 0x82, 0x03, 0x00, 0xc1, 0xc7, 0x01, 0x00, 0x49, 0xc0, 0x01, 0x00, + 0x95, 0xc0, 0x01, 0x00, 0x93, 0xc0, 0x01, 0x00, 0x21, 0x01, 0x00, 0x00, + 0x20, 0xc1, 0x01, 0x00, 0x40, 0xc2, 0x01, 0x00, 0x40, 0x02, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +static const uint8_t whatsthism_bits[] = { + 0x01, 0x00, 0x00, 0x00, 0x03, 0xf0, 0x07, 0x00, 0x07, 0xf8, 0x0f, 0x00, + 0x0f, 0xfc, 0x1f, 0x00, 0x1f, 0x3e, 0x1f, 0x00, 0x3f, 0x3e, 0x1f, 0x00, + 0x7f, 0x3e, 0x1f, 0x00, 0xff, 0x3e, 0x1f, 0x00, 0xff, 0x9d, 0x0f, 0x00, + 0xff, 0xc3, 0x07, 0x00, 0xff, 0xe7, 0x03, 0x00, 0x7f, 0xe0, 0x03, 0x00, + 0xf7, 0xe0, 0x03, 0x00, 0xf3, 0xe0, 0x03, 0x00, 0xe1, 0xe1, 0x03, 0x00, + 0xe0, 0xe1, 0x03, 0x00, 0xc0, 0xe3, 0x03, 0x00, 0xc0, 0xe3, 0x03, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +static const uint8_t busy_bits[] = { + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x41, 0xe0, 0xff, 0x00, 0x81, 0x20, 0x80, 0x00, 0x01, 0xe1, 0xff, 0x00, + 0x01, 0x42, 0x40, 0x00, 0xc1, 0x47, 0x40, 0x00, 0x49, 0x40, 0x55, 0x00, + 0x95, 0x80, 0x2a, 0x00, 0x93, 0x00, 0x15, 0x00, 0x21, 0x01, 0x0a, 0x00, + 0x20, 0x01, 0x11, 0x00, 0x40, 0x82, 0x20, 0x00, 0x40, 0x42, 0x44, 0x00, + 0x80, 0x41, 0x4a, 0x00, 0x00, 0x40, 0x55, 0x00, 0x00, 0xe0, 0xff, 0x00, + 0x00, 0x20, 0x80, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static const uint8_t busym_bits[] = { + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, + 0x7f, 0xe0, 0xff, 0x00, 0xff, 0xe0, 0xff, 0x00, 0xff, 0xe1, 0xff, 0x00, + 0xff, 0xc3, 0x7f, 0x00, 0xff, 0xc7, 0x7f, 0x00, 0x7f, 0xc0, 0x7f, 0x00, + 0xf7, 0x80, 0x3f, 0x00, 0xf3, 0x00, 0x1f, 0x00, 0xe1, 0x01, 0x0e, 0x00, + 0xe0, 0x01, 0x1f, 0x00, 0xc0, 0x83, 0x3f, 0x00, 0xc0, 0xc3, 0x7f, 0x00, + 0x80, 0xc1, 0x7f, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0xff, 0x00, + 0x00, 0xe0, 0xff, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +static const uint8_t * const cursor_bits32[] = { + vsplit_bits, vsplitm_bits, hsplit_bits, hsplitm_bits, + 0, 0, 0, 0, whatsthis_bits, whatsthism_bits, busy_bits, busym_bits +}; + +static const uint8_t forbidden_bits[] = { + 0x00,0x00,0x00,0x80,0x1f,0x00,0xe0,0x7f,0x00,0xf0,0xf0,0x00,0x38,0xc0,0x01, + 0x7c,0x80,0x03,0xec,0x00,0x03,0xce,0x01,0x07,0x86,0x03,0x06,0x06,0x07,0x06, + 0x06,0x0e,0x06,0x06,0x1c,0x06,0x0e,0x38,0x07,0x0c,0x70,0x03,0x1c,0xe0,0x03, + 0x38,0xc0,0x01,0xf0,0xe0,0x00,0xe0,0x7f,0x00,0x80,0x1f,0x00,0x00,0x00,0x00 }; + +static const uint8_t forbiddenm_bits[] = { + 0x80,0x1f,0x00,0xe0,0x7f,0x00,0xf0,0xff,0x00,0xf8,0xff,0x01,0xfc,0xf0,0x03, + 0xfe,0xc0,0x07,0xfe,0x81,0x07,0xff,0x83,0x0f,0xcf,0x07,0x0f,0x8f,0x0f,0x0f, + 0x0f,0x1f,0x0f,0x0f,0x3e,0x0f,0x1f,0xfc,0x0f,0x1e,0xf8,0x07,0x3e,0xf0,0x07, + 0xfc,0xe0,0x03,0xf8,0xff,0x01,0xf0,0xff,0x00,0xe0,0x7f,0x00,0x80,0x1f,0x00}; + +static const uint8_t openhand_bits[] = { + 0x80,0x01,0x58,0x0e,0x64,0x12,0x64,0x52,0x48,0xb2,0x48,0x92, + 0x16,0x90,0x19,0x80,0x11,0x40,0x02,0x40,0x04,0x40,0x04,0x20, + 0x08,0x20,0x10,0x10,0x20,0x10,0x00,0x00}; +static const uint8_t openhandm_bits[] = { + 0x80,0x01,0xd8,0x0f,0xfc,0x1f,0xfc,0x5f,0xf8,0xff,0xf8,0xff, + 0xf6,0xff,0xff,0xff,0xff,0x7f,0xfe,0x7f,0xfc,0x7f,0xfc,0x3f, + 0xf8,0x3f,0xf0,0x1f,0xe0,0x1f,0x00,0x00}; +static const uint8_t closedhand_bits[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0x48,0x32,0x08,0x50, + 0x10,0x40,0x18,0x40,0x04,0x40,0x04,0x20,0x08,0x20,0x10,0x10, + 0x20,0x10,0x20,0x10,0x00,0x00,0x00,0x00}; +static const uint8_t closedhandm_bits[] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0xf8,0x3f,0xf8,0x7f, + 0xf0,0x7f,0xf8,0x7f,0xfc,0x7f,0xfc,0x3f,0xf8,0x3f,0xf0,0x1f, + 0xe0,0x1f,0xe0,0x1f,0x00,0x00,0x00,0x00}; + +static const uint8_t * const cursor_bits20[] = { + forbidden_bits, forbiddenm_bits +}; + +static const char * const cursorNames[] = { + "left_ptr", + "up_arrow", + "cross", + "wait", + "ibeam", + "size_ver", + "size_hor", + "size_bdiag", + "size_fdiag", + "size_all", + "blank", + "split_v", + "split_h", + "pointing_hand", + "forbidden", + "whats_this", + "left_ptr_watch", + "openhand", + "closedhand", + "copy", + "move", + "link" +}; + +QXcbCursor::QXcbCursor(QXcbConnection *conn, QXcbScreen *screen) + : QXcbObject(conn), QPlatformCursor(screen), m_screen(screen) +{ + if (cursorCount++) + return; + + cursorFont = xcb_generate_id(xcb_connection()); + const char *cursorStr = "cursor"; + xcb_open_font(xcb_connection(), cursorFont, strlen(cursorStr), cursorStr); + +#ifdef XCB_USE_XLIB + QLibrary xcursorLib(QLatin1String("Xcursor"), 1); + bool xcursorFound = xcursorLib.load(); + if (!xcursorFound) { // try without the version number + xcursorLib.setFileName(QLatin1String("Xcursor")); + xcursorFound = xcursorLib.load(); + } + if (xcursorFound) + ptrXcursorLibraryLoadCursor = + (PtrXcursorLibraryLoadCursor) xcursorLib.resolve("XcursorLibraryLoadCursor"); +#endif +} + +QXcbCursor::~QXcbCursor() +{ + if (!--cursorCount) + xcb_close_font(xcb_connection(), cursorFont); +} + +void QXcbCursor::changeCursor(QCursor *cursor, QWindow *widget) +{ + QXcbWindow *w = 0; + if (widget && widget->handle()) + w = static_cast<QXcbWindow *>(widget->handle()); + else + // No X11 cursor control when there is no widget under the cursor + return; + + xcb_cursor_t c; + if (cursor->shape() == Qt::BitmapCursor) { + qint64 id = cursor->pixmap().cacheKey(); + if (!m_bitmapCursorMap.contains(id)) + m_bitmapCursorMap.insert(id, createBitmapCursor(cursor)); + c = m_bitmapCursorMap.value(id); + } else { + int id = cursor->handle(); + if (!m_shapeCursorMap.contains(id)) + m_shapeCursorMap.insert(id, createFontCursor(cursor->shape())); + c = m_shapeCursorMap.value(id); + } + + w->setCursor(c); +} + +static int cursorIdForShape(int cshape) +{ + int cursorId = 0; + switch (cshape) { + case Qt::ArrowCursor: + cursorId = XC_left_ptr; + break; + case Qt::UpArrowCursor: + cursorId = XC_center_ptr; + break; + case Qt::CrossCursor: + cursorId = XC_crosshair; + break; + case Qt::WaitCursor: + cursorId = XC_watch; + break; + case Qt::IBeamCursor: + cursorId = XC_xterm; + break; + case Qt::SizeAllCursor: + cursorId = XC_fleur; + break; + case Qt::PointingHandCursor: + cursorId = XC_hand2; + break; + case Qt::SizeBDiagCursor: + cursorId = XC_top_right_corner; + break; + case Qt::SizeFDiagCursor: + cursorId = XC_bottom_right_corner; + break; + case Qt::SizeVerCursor: + case Qt::SplitVCursor: + cursorId = XC_sb_v_double_arrow; + break; + case Qt::SizeHorCursor: + case Qt::SplitHCursor: + cursorId = XC_sb_h_double_arrow; + break; + case Qt::WhatsThisCursor: + cursorId = XC_question_arrow; + break; + case Qt::ForbiddenCursor: + cursorId = XC_circle; + break; + case Qt::BusyCursor: + cursorId = XC_watch; + break; + default: + break; + } + return cursorId; +} + +xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape) +{ + xcb_cursor_t cursor = 0; + xcb_connection_t *conn = xcb_connection(); + + if (cshape == Qt::BlankCursor) { + xcb_pixmap_t cp = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), cur_blank_bits, 16, 16, + 1, 0, 0, 0); + xcb_pixmap_t mp = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), cur_blank_bits, 16, 16, + 1, 0, 0, 0); + cursor = xcb_generate_id(conn); + xcb_create_cursor(conn, cursor, cp, mp, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8); + } else if (cshape >= Qt::SizeVerCursor && cshape < Qt::SizeAllCursor) { + int i = (cshape - Qt::SizeVerCursor) * 2; + xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), + const_cast<uint8_t*>(cursor_bits16[i]), + 16, 16, 1, 0, 0, 0); + xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), + const_cast<uint8_t*>(cursor_bits16[i + 1]), + 16, 16, 1, 0, 0, 0); + cursor = xcb_generate_id(conn); + xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8); + } else if ((cshape >= Qt::SplitVCursor && cshape <= Qt::SplitHCursor) + || cshape == Qt::WhatsThisCursor || cshape == Qt::BusyCursor) { + int i = (cshape - Qt::SplitVCursor) * 2; + xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), + const_cast<uint8_t*>(cursor_bits32[i]), + 32, 32, 1, 0, 0, 0); + xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), + const_cast<uint8_t*>(cursor_bits32[i + 1]), + 32, 32, 1, 0, 0, 0); + int hs = (cshape == Qt::PointingHandCursor || cshape == Qt::WhatsThisCursor + || cshape == Qt::BusyCursor) ? 0 : 16; + cursor = xcb_generate_id(conn); + xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, hs, hs); + } else if (cshape == Qt::ForbiddenCursor) { + int i = (cshape - Qt::ForbiddenCursor) * 2; + xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), + const_cast<uint8_t*>(cursor_bits20[i]), + 20, 20, 1, 0, 0, 0); + xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), + const_cast<uint8_t*>(cursor_bits20[i + 1]), + 20, 20, 1, 0, 0, 0); + cursor = xcb_generate_id(conn); + xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 10, 10); + } else if (cshape == Qt::OpenHandCursor || cshape == Qt::ClosedHandCursor) { + bool open = cshape == Qt::OpenHandCursor; + xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), + const_cast<uint8_t*>(open ? openhand_bits : closedhand_bits), + 16, 16, 1, 0, 0, 0); + xcb_pixmap_t pmm = xcb_create_pixmap_from_bitmap_data(conn, m_screen->root(), + const_cast<uint8_t*>(open ? openhandm_bits : closedhandm_bits), + 16, 16, 1, 0, 0, 0); + cursor = xcb_generate_id(conn); + xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8); + } else if (cshape == Qt::DragCopyCursor || cshape == Qt::DragMoveCursor + || cshape == Qt::DragLinkCursor) { + QImage image = QGuiApplicationPrivate::instance()->getPixmapCursor(static_cast<Qt::CursorShape>(cshape)).toImage(); + xcb_pixmap_t pm = qt_xcb_XPixmapFromBitmap(m_screen, image); + xcb_pixmap_t pmm = qt_xcb_XPixmapFromBitmap(m_screen, image.createAlphaMask()); + cursor = xcb_generate_id(conn); + xcb_create_cursor(conn, cursor, pm, pmm, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 8, 8); + } + + return cursor; +} + +xcb_cursor_t QXcbCursor::createFontCursor(int cshape) +{ + xcb_connection_t *conn = xcb_connection(); + int cursorId = cursorIdForShape(cshape); + xcb_cursor_t cursor = XCB_NONE; + + // Try Xcursor first +#ifdef XCB_USE_XLIB + if (ptrXcursorLibraryLoadCursor && cshape >= 0 && cshape < Qt::LastCursor) { + void *dpy = connection()->xlib_display(); + // special case for non-standard dnd-* cursors + switch (cshape) { + case Qt::DragCopyCursor: + cursor = ptrXcursorLibraryLoadCursor(dpy, "dnd-copy"); + break; + case Qt::DragMoveCursor: + cursor = ptrXcursorLibraryLoadCursor(dpy, "dnd-move"); + break; + case Qt::DragLinkCursor: + cursor = ptrXcursorLibraryLoadCursor(dpy, "dnd-link"); + break; + default: + break; + } + if (!cursor) + cursor = ptrXcursorLibraryLoadCursor(dpy, cursorNames[cshape]); + } + if (cursor) + return cursor; +#endif + + // Non-standard X11 cursors are created from bitmaps + cursor = createNonStandardCursor(cshape); + + // Create a glpyh cursor if everything else failed + if (!cursor && cursorId) { + cursor = xcb_generate_id(conn); + xcb_create_glyph_cursor(conn, cursor, cursorFont, cursorFont, + cursorId, cursorId + 1, + 0xFFFF, 0xFFFF, 0xFFFF, 0, 0, 0); + } + + if (cursor && cshape >= 0 && cshape < Qt::LastCursor) { + const char *name = cursorNames[cshape]; + xcb_xfixes_set_cursor_name(conn, cursor, strlen(name), name); + } + + return cursor; +} + +xcb_cursor_t QXcbCursor::createBitmapCursor(QCursor *cursor) +{ + xcb_connection_t *conn = xcb_connection(); + QPoint spot = cursor->hotSpot(); + xcb_cursor_t c = XCB_NONE; + if (cursor->pixmap().depth() > 1) + c = qt_xcb_createCursorXRender(m_screen, cursor->pixmap().toImage(), spot); + if (!c) { + xcb_pixmap_t cp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->bitmap()->toImage()); + xcb_pixmap_t mp = qt_xcb_XPixmapFromBitmap(m_screen, cursor->mask()->toImage()); + c = xcb_generate_id(conn); + xcb_create_cursor(conn, c, cp, mp, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, + spot.x(), spot.y()); + xcb_free_pixmap(conn, cp); + xcb_free_pixmap(conn, mp); + } + return c; +} + +static void getPosAndRoot(xcb_connection_t *conn, xcb_window_t *rootWin, QPoint *pos) +{ + if (pos) + *pos = QPoint(); + xcb_screen_iterator_t it = xcb_setup_roots_iterator(xcb_get_setup(conn)); + while (it.rem) { + xcb_window_t root = it.data->root; + xcb_query_pointer_cookie_t cookie = xcb_query_pointer(conn, root); + xcb_generic_error_t *err = 0; + xcb_query_pointer_reply_t *reply = xcb_query_pointer_reply(conn, cookie, &err); + if (!err && reply) { + if (pos) + *pos = QPoint(reply->root_x, reply->root_y); + if (rootWin) + *rootWin = root; + free(reply); + return; + } + free(err); + free(reply); + xcb_screen_next(&it); + } +} + +QPoint QXcbCursor::pos() const +{ + QPoint p; + getPosAndRoot(xcb_connection(), 0, &p); + return p; +} + +void QXcbCursor::setPos(const QPoint &pos) +{ + xcb_connection_t *conn = xcb_connection(); + xcb_window_t root; + getPosAndRoot(conn, &root, 0); + xcb_warp_pointer(conn, XCB_NONE, root, 0, 0, 0, 0, pos.x(), pos.y()); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglconvenience/qeglconvenience.h b/src/plugins/platforms/xcb/qxcbcursor.h index da4a0cdded..4bbb9a928b 100644 --- a/src/plugins/platforms/eglconvenience/qeglconvenience.h +++ b/src/plugins/platforms/xcb/qxcbcursor.h @@ -39,22 +39,33 @@ ** ****************************************************************************/ -#ifndef QEGLCONVENIENCE_H -#define QEGLCONVENIENCE_H +#ifndef QXCBCURSOR_H +#define QXCBCURSOR_H +#include <QtGui/QPlatformCursor> +#include "qxcbscreen.h" -#include <QtGui/QPlatformWindowFormat> -#include <QtCore/QVector> - -#include <EGL/egl.h> QT_BEGIN_NAMESPACE -QVector<EGLint> q_createConfigAttributesFromFormat(const QPlatformWindowFormat &format); -bool q_reduceConfigAttributes(QVector<EGLint> *configAttributes); -EGLConfig q_configFromQPlatformWindowFormat(EGLDisplay display, const QPlatformWindowFormat &format, bool highestPixelFormat = false, int surfaceType = EGL_WINDOW_BIT); -QPlatformWindowFormat qt_qPlatformWindowFormatFromConfig(EGLDisplay display, const EGLConfig config); -bool q_hasEglExtension(EGLDisplay display,const char* extensionName); +class QXcbCursor : public QXcbObject, public QPlatformCursor +{ +public: + QXcbCursor(QXcbConnection *conn, QXcbScreen *screen); + ~QXcbCursor(); + void changeCursor(QCursor *cursor, QWindow *widget); + QPoint pos() const; + void setPos(const QPoint &pos); + +private: + xcb_cursor_t createFontCursor(int cshape); + xcb_cursor_t createBitmapCursor(QCursor *cursor); + xcb_cursor_t createNonStandardCursor(int cshape); + + QXcbScreen *m_screen; + QMap<int, xcb_cursor_t> m_shapeCursorMap; + QMap<qint64, xcb_cursor_t> m_bitmapCursorMap; +}; QT_END_NAMESPACE -#endif //QEGLCONVENIENCE_H +#endif diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp new file mode 100644 index 0000000000..f4e8afadc7 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -0,0 +1,1330 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxcbdrag.h" +#include <xcb/xcb.h> +#include "qxcbconnection.h" +#include "qxcbclipboard.h" +#include "qxcbmime.h" +#include "qxcbwindow.h" +#include "qxcbscreen.h" +#include "qwindow.h" +#include <private/qdnd_p.h> +#include <qdebug.h> +#include <qevent.h> +#include <qguiapplication.h> +#include <qrect.h> + +QT_BEGIN_NAMESPACE + +//#define DND_DEBUG +#ifdef DND_DEBUG +#define DEBUG qDebug +#else +#define DEBUG if(0) qDebug +#endif + +#ifdef DND_DEBUG +#define DNDDEBUG qDebug() +#else +#define DNDDEBUG if(0) qDebug() +#endif + +const int xdnd_version = 5; + +static inline xcb_window_t xcb_window(QWindow *w) +{ + return static_cast<QXcbWindow *>(w->handle())->xcb_window(); +} + + +static xcb_window_t xdndProxy(QXcbConnection *c, xcb_window_t w) +{ + xcb_window_t proxy = XCB_NONE; + + xcb_get_property_cookie_t cookie = Q_XCB_CALL2(xcb_get_property(c->xcb_connection(), false, w, c->atom(QXcbAtom::XdndProxy), + XCB_ATOM_WINDOW, 0, 1), c); + xcb_get_property_reply_t *reply = xcb_get_property_reply(c->xcb_connection(), cookie, 0); + + if (reply && reply->type == XCB_ATOM_WINDOW) + proxy = *((xcb_window_t *)xcb_get_property_value(reply)); + free(reply); + + if (proxy == XCB_NONE) + return proxy; + + // exists and is real? + cookie = Q_XCB_CALL2(xcb_get_property(c->xcb_connection(), false, proxy, c->atom(QXcbAtom::XdndProxy), + XCB_ATOM_WINDOW, 0, 1), c); + reply = xcb_get_property_reply(c->xcb_connection(), cookie, 0); + + if (reply && reply->type == XCB_ATOM_WINDOW) { + xcb_window_t p = *((xcb_window_t *)xcb_get_property_value(reply)); + if (proxy != p) + proxy = 0; + } else { + proxy = 0; + } + + free(reply); + + return proxy; +} + + +class QDropData : public QXcbMime +{ +public: + QDropData(QXcbDrag *d); + ~QDropData(); + +protected: + bool hasFormat_sys(const QString &mimeType) const; + QStringList formats_sys() const; + QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type) const; + + QVariant xdndObtainData(const QByteArray &format, QVariant::Type requestedType) const; + + QXcbDrag *drag; +}; + + +QXcbDrag::QXcbDrag(QXcbConnection *c) + : QXcbObject(c) +{ + dropData = new QDropData(this); + + init(); + heartbeat = -1; + + transaction_expiry_timer = -1; +} + +QXcbDrag::~QXcbDrag() +{ + delete dropData; +} + +void QXcbDrag::init() +{ + currentWindow.clear(); + + xdnd_dragsource = XCB_NONE; + last_target_accepted_action = Qt::IgnoreAction; + + waiting_for_status = false; + current_target = XCB_NONE; + current_proxy_target = XCB_NONE; + xdnd_dragging = false; + + source_time = XCB_CURRENT_TIME; + target_time = XCB_CURRENT_TIME; + + current_screen = 0; + drag_types.clear(); +} + +QMimeData *QXcbDrag::platformDropData() +{ + return dropData; +} + +void QXcbDrag::startDrag() +{ + init(); + + heartbeat = startTimer(200); + xdnd_dragging = true; + + xcb_set_selection_owner(xcb_connection(), connection()->clipboard()->owner(), + atom(QXcbAtom::XdndSelection), connection()->time()); + + QDragManager *manager = QDragManager::self(); + QStringList fmts = QXcbMime::formatsHelper(manager->dropData()); + for (int i = 0; i < fmts.size(); ++i) { + QList<xcb_atom_t> atoms = QXcbMime::mimeAtomsForFormat(connection(), fmts.at(i)); + for (int j = 0; j < atoms.size(); ++j) { + if (!drag_types.contains(atoms.at(j))) + drag_types.append(atoms.at(j)); + } + } + if (drag_types.size() > 3) + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, connection()->clipboard()->owner(), + atom(QXcbAtom::XdndTypelist), + XCB_ATOM_ATOM, 32, drag_types.size(), (const void *)drag_types.constData()); + + QMouseEvent me(QEvent::MouseMove, QCursor::pos(), QCursor::pos(), Qt::LeftButton, + QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); + move(&me); + +// if (!QWidget::mouseGrabber()) +// manager->shapedPixmapWindow->grabMouse(); +} + +void QXcbDrag::endDrag() +{ + Q_ASSERT(heartbeat != -1); + killTimer(heartbeat); + heartbeat = -1; + + xdnd_dragging = false; +} + +static xcb_translate_coordinates_reply_t * +translateCoordinates(QXcbConnection *c, xcb_window_t from, xcb_window_t to, int x, int y) +{ + xcb_translate_coordinates_cookie_t cookie = + xcb_translate_coordinates(c->xcb_connection(), from, to, x, y); + return xcb_translate_coordinates_reply(c->xcb_connection(), cookie, 0); +} + +void QXcbDrag::move(const QMouseEvent *me) +{ + DEBUG() << "QDragManager::move enter"; + + // ### + QPoint globalPos = me->globalPos(); + + if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid()) + return; + + const QList<QXcbScreen *> &screens = connection()->screens(); + QXcbScreen *screen = screens.at(connection()->primaryScreen()); + for (int i = 0; i < screens.size(); ++i) { + if (screens.at(i)->geometry().contains(globalPos)) { + screen = screens.at(i); + break; + } + } + if (screen != current_screen) { + // ### need to recreate the shaped pixmap window? +// int screen = QCursor::x11Screen(); +// if ((qt_xdnd_current_screen == -1 && screen != X11->defaultScreen) || (screen != qt_xdnd_current_screen)) { +// // recreate the pixmap on the new screen... +// delete xdnd_data.deco; +// QWidget* parent = object->source()->window()->x11Info().screen() == screen +// ? object->source()->window() : QApplication::desktop()->screen(screen); +// xdnd_data.deco = new QShapedPixmapWidget(parent); +// if (!QWidget::mouseGrabber()) { +// updatePixmap(); +// xdnd_data.deco->grabMouse(); +// } +// } +// xdnd_data.deco->move(QCursor::pos() - xdnd_data.deco->pm_hot); + current_screen = screen; + } + + +// qt_xdnd_current_screen = screen; + xcb_window_t rootwin = current_screen->root(); + xcb_translate_coordinates_reply_t *translate = + ::translateCoordinates(connection(), rootwin, rootwin, globalPos.x(), globalPos.y()); + if (!translate) + return; + xcb_window_t target = translate->child; + int lx = translate->dst_x; + int ly = translate->dst_y; + free (translate); + + if (target == rootwin) { + // Ok. + } else if (target) { + //me + xcb_window_t src = rootwin; + while (target != 0) { + DNDDEBUG << "checking target for XdndAware" << target; + + // translate coordinates + translate = ::translateCoordinates(connection(), src, target, lx, ly); + if (!translate) { + target = 0; + break; + } + lx = translate->dst_x; + ly = translate->dst_y; + src = translate->child; + free(translate); + + // check if it has XdndAware + xcb_get_property_cookie_t cookie = Q_XCB_CALL(xcb_get_property(xcb_connection(), false, target, + atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 0)); + xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, 0); + bool aware = reply && reply->type != XCB_NONE; + free(reply); + if (aware) { + DNDDEBUG << "Found XdndAware on " << target; + break; + } + + // find child at the coordinates + translate = ::translateCoordinates(connection(), src, src, lx, ly); + if (!translate) { + target = 0; + break; + } + target = translate->child; + free(translate); + } + // #### +// if (xdnd_data.deco && (!target || target == xdnd_data.deco->effectiveWinId())) { +// DNDDEBUG << "need to find real window"; +// target = findRealWindow(globalPos, rootwin, 6); +// DNDDEBUG << "real window found" << QWidget::find(target) << target; +// } + } + + QXcbWindow *w = 0; + if (target) { + w = connection()->platformWindowFromId(target); + if (w && (w->window()->windowType() == Qt::Desktop) /*&& !w->acceptDrops()*/) + w = 0; + } else { + w = 0; + target = rootwin; + } + + DNDDEBUG << "and the final target is " << target; + DNDDEBUG << "the widget w is" << (w ? w->window() : 0); + + xcb_window_t proxy_target = xdndProxy(connection(), target); + if (!proxy_target) + proxy_target = target; + int target_version = 1; + + if (proxy_target) { + xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, target, + atom(QXcbAtom::XdndAware), XCB_GET_PROPERTY_TYPE_ANY, 0, 1); + xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, 0); + if (!reply || reply->type == XCB_NONE) + target = 0; + target_version = xcb_get_property_value_length(reply) == 1 ? *(uint32_t *)xcb_get_property_value(reply) : 1; + if (target_version > xdnd_version) + target_version = xdnd_version; + + free(reply); + } + + DEBUG() << "target=" << target << "current_target=" << current_target; + if (target != current_target) { + if (current_target) + send_leave(); + + current_target = target; + current_proxy_target = proxy_target; + if (target) { + int flags = target_version << 24; + if (drag_types.size() > 3) + flags |= 0x0001; + + xcb_client_message_event_t enter; + enter.response_type = XCB_CLIENT_MESSAGE; + enter.window = target; + enter.format = 32; + enter.type = atom(QXcbAtom::XdndEnter); + enter.data.data32[0] = connection()->clipboard()->owner(); + enter.data.data32[1] = flags; + enter.data.data32[2] = drag_types.size()>0 ? drag_types.at(0) : 0; + enter.data.data32[3] = drag_types.size()>1 ? drag_types.at(1) : 0; + enter.data.data32[4] = drag_types.size()>2 ? drag_types.at(2) : 0; + // provisionally set the rectangle to 5x5 pixels... + source_sameanswer = QRect(globalPos.x() - 2, globalPos.y() -2 , 5, 5); + + DEBUG() << "sending Xdnd enter source=" << enter.data.data32[0]; + if (w) + handleEnter(w->window(), &enter); + else if (target) + xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&enter); + waiting_for_status = false; + } + } + if (waiting_for_status) + return; + + QDragManager *m = QDragManager::self(); + + if (target) { + waiting_for_status = true; + + xcb_client_message_event_t move; + move.response_type = XCB_CLIENT_MESSAGE; + move.window = target; + move.format = 32; + move.type = atom(QXcbAtom::XdndPosition); + move.window = target; + move.data.data32[0] = connection()->clipboard()->owner(); + move.data.data32[1] = 0; // flags + move.data.data32[2] = (globalPos.x() << 16) + globalPos.y(); + move.data.data32[3] = connection()->time(); + move.data.data32[4] = toXdndAction(m->defaultAction(m->dragPrivate()->possible_actions, QGuiApplication::keyboardModifiers())); + DEBUG() << "sending Xdnd position source=" << move.data.data32[0] << "target=" << move.window; + + source_time = connection()->time(); + + if (w) + handle_xdnd_position(w->window(), &move, false); + else + xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&move); + } else { + if (m->willDrop) { + m->willDrop = false; + m->updateCursor(); + } + } + DEBUG() << "QDragManager::move leave"; +} + +void QXcbDrag::drop(const QMouseEvent *) +{ + endDrag(); + + if (!current_target) + return; + + xcb_client_message_event_t drop; + drop.response_type = XCB_CLIENT_MESSAGE; + drop.window = current_target; + drop.format = 32; + drop.type = atom(QXcbAtom::XdndDrop); + drop.data.data32[0] = connection()->clipboard()->owner(); + drop.data.data32[1] = 0; // flags + drop.data.data32[2] = connection()->time(); + + drop.data.data32[3] = 0; + drop.data.data32[4] = 0; + + QXcbWindow *w = connection()->platformWindowFromId(current_proxy_target); + + if (w && (w->window()->windowType() == Qt::Desktop) /*&& !w->acceptDrops()*/) + w = 0; + + QDragManager *manager = QDragManager::self(); + + Transaction t = { + connection()->time(), + current_target, + current_proxy_target, + (w ? w->window() : 0), +// current_embedding_widget, + manager->object + }; + transactions.append(t); + restartDropExpiryTimer(); + + if (w) + handleDrop(w->window(), &drop, false); + else + xcb_send_event(xcb_connection(), false, current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&drop); + + current_target = 0; + current_proxy_target = 0; + source_time = 0; +// current_embedding_widget = 0; + manager->object = 0; +} + +Qt::DropAction QXcbDrag::toDropAction(xcb_atom_t a) const +{ + if (a == atom(QXcbAtom::XdndActionCopy) || a == 0) + return Qt::CopyAction; + if (a == atom(QXcbAtom::XdndActionLink)) + return Qt::LinkAction; + if (a == atom(QXcbAtom::XdndActionMove)) + return Qt::MoveAction; + return Qt::CopyAction; +} + +xcb_atom_t QXcbDrag::toXdndAction(Qt::DropAction a) const +{ + switch (a) { + case Qt::CopyAction: + return atom(QXcbAtom::XdndActionCopy); + case Qt::LinkAction: + return atom(QXcbAtom::XdndActionLink); + case Qt::MoveAction: + case Qt::TargetMoveAction: + return atom(QXcbAtom::XdndActionMove); + case Qt::IgnoreAction: + return XCB_NONE; + default: + return atom(QXcbAtom::XdndActionCopy); + } +} + +// timer used to discard old XdndDrop transactions +enum { XdndDropTransactionTimeout = 5000 }; // 5 seconds + +void QXcbDrag::restartDropExpiryTimer() +{ + if (transaction_expiry_timer != -1) + killTimer(transaction_expiry_timer); + transaction_expiry_timer = startTimer(XdndDropTransactionTimeout); +} + +int QXcbDrag::findTransactionByWindow(xcb_window_t window) +{ + int at = -1; + for (int i = 0; i < transactions.count(); ++i) { + const Transaction &t = transactions.at(i); + if (t.target == window || t.proxy_target == window) { + at = i; + break; + } + } + return at; +} + +int QXcbDrag::findTransactionByTime(xcb_timestamp_t timestamp) +{ + int at = -1; + for (int i = 0; i < transactions.count(); ++i) { + const Transaction &t = transactions.at(i); + if (t.timestamp == timestamp) { + at = i; + break; + } + } + return at; +} + +#if 0 + +// find an ancestor with XdndAware on it +static Window findXdndAwareParent(Window window) +{ + Window target = 0; + forever { + // check if window has XdndAware + Atom type = 0; + int f; + unsigned long n, a; + unsigned char *data = 0; + if (XGetWindowProperty(X11->display, window, ATOM(XdndAware), 0, 0, False, + AnyPropertyType, &type, &f,&n,&a,&data) == Success) { + if (data) + XFree(data); + if (type) { + target = window; + break; + } + } + + // try window's parent + Window root; + Window parent; + Window *children; + uint unused; + if (!XQueryTree(X11->display, window, &root, &parent, &children, &unused)) + break; + if (children) + XFree(children); + if (window == root) + break; + window = parent; + } + return target; +} + + +// for embedding only +static QWidget* current_embedding_widget = 0; +static xcb_client_message_event_t last_enter_event; + + +static bool checkEmbedded(QWidget* w, const XEvent* xe) +{ + if (!w) + return false; + + if (current_embedding_widget != 0 && current_embedding_widget != w) { + current_target = ((QExtraWidget*)current_embedding_widget)->extraData()->xDndProxy; + current_proxy_target = current_target; + qt_xdnd_send_leave(); + current_target = 0; + current_proxy_target = 0; + current_embedding_widget = 0; + } + + QWExtra* extra = ((QExtraWidget*)w)->extraData(); + if (extra && extra->xDndProxy != 0) { + + if (current_embedding_widget != w) { + + last_enter_event.xany.window = extra->xDndProxy; + XSendEvent(X11->display, extra->xDndProxy, False, NoEventMask, &last_enter_event); + current_embedding_widget = w; + } + + ((XEvent*)xe)->xany.window = extra->xDndProxy; + XSendEvent(X11->display, extra->xDndProxy, False, NoEventMask, (XEvent*)xe); + if (currentWindow != w) { + currentWindow = w; + } + return true; + } + current_embedding_widget = 0; + return false; +} +#endif + + +void QXcbDrag::handleEnter(QWindow *window, const xcb_client_message_event_t *event) +{ + Q_UNUSED(window); + DEBUG() << "handleEnter" << window; + + xdnd_types.clear(); +// motifdnd_active = false; +// last_enter_event.xclient = xe->xclient; + + int version = (int)(event->data.data32[1] >> 24); + if (version > xdnd_version) + return; + + xdnd_dragsource = event->data.data32[0]; + + if (event->data.data32[1] & 1) { + // get the types from XdndTypeList + xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, xdnd_dragsource, + atom(QXcbAtom::XdndTypelist), XCB_ATOM_ATOM, + 0, xdnd_max_type); + xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, 0); + if (reply && reply->type != XCB_NONE && reply->format == 32) { + int length = xcb_get_property_value_length(reply) / 4; + if (length > xdnd_max_type) + length = xdnd_max_type; + + xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply); + for (int i = 0; i < length; ++i) + xdnd_types.append(atoms[i]); + } + free(reply); + } else { + // get the types from the message + for(int i = 2; i < 5; i++) { + if (event->data.data32[i]) + xdnd_types.append(event->data.data32[i]); + } + } + for(int i = 0; i < xdnd_types.length(); ++i) + DEBUG() << " " << connection()->atomName(xdnd_types.at(i)); +} + +void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *e, bool passive) +{ + QPoint p((e->data.data32[2] & 0xffff0000) >> 16, e->data.data32[2] & 0x0000ffff); + Q_ASSERT(w); + QRect geometry = w->geometry(); + + p -= geometry.topLeft(); + + // #### +// if (!passive && checkEmbedded(w, e)) +// return; + + if (!w || (/*!w->acceptDrops() &&*/ (w->windowType() == Qt::Desktop))) + return; + + if (e->data.data32[0] != xdnd_dragsource) { + DEBUG("xdnd drag position from unexpected source (%x not %x)", e->data.data32[0], xdnd_dragsource); + return; + } + + // timestamp from the source + if (e->data.data32[3] != XCB_NONE) + target_time /*= X11->userTime*/ = e->data.data32[3]; + + QDragManager *manager = QDragManager::self(); + QMimeData *dropData = manager->dropData(); + + xcb_client_message_event_t response; + response.response_type = XCB_CLIENT_MESSAGE; + response.window = xdnd_dragsource; + response.format = 32; + response.type = atom(QXcbAtom::XdndStatus); + response.data.data32[0] = xcb_window(w); + response.data.data32[1] = 0; // flags + response.data.data32[2] = 0; // x, y + response.data.data32[3] = 0; // w, h + response.data.data32[4] = 0; // action + + if (!passive) { // otherwise just reject + QRect answerRect(p + geometry.topLeft(), QSize(1,1)); + + if (manager->object) { + manager->possible_actions = manager->dragPrivate()->possible_actions; + } else { + manager->possible_actions = Qt::DropActions(toDropAction(e->data.data32[4])); + } + QDragMoveEvent me(p, manager->possible_actions, dropData, + QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); + + Qt::DropAction accepted_action = Qt::IgnoreAction; + + currentPosition = p; + + if (w != currentWindow.data()) { + if (currentWindow) { + QDragLeaveEvent e; + QGuiApplication::sendEvent(currentWindow.data(), &e); + } + currentWindow = w; + + last_target_accepted_action = Qt::IgnoreAction; + QDragEnterEvent de(p, manager->possible_actions, dropData, + QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); + QGuiApplication::sendEvent(w, &de); + if (de.isAccepted() && de.dropAction() != Qt::IgnoreAction) + last_target_accepted_action = de.dropAction(); + } + + DEBUG() << "qt_handle_xdnd_position action=" << connection()->atomName(e->data.data32[4]); + + if (last_target_accepted_action != Qt::IgnoreAction) { + me.setDropAction(last_target_accepted_action); + me.accept(); + } + QGuiApplication::sendEvent(w, &me); + if (me.isAccepted()) { + response.data.data32[1] = 1; // yes + accepted_action = me.dropAction(); + last_target_accepted_action = accepted_action; + } else { + response.data.data32[0] = 0; + last_target_accepted_action = Qt::IgnoreAction; + } + answerRect = me.answerRect().translated(geometry.topLeft()).intersected(geometry); + + if (answerRect.left() < 0) + answerRect.setLeft(0); + if (answerRect.right() > 4096) + answerRect.setRight(4096); + if (answerRect.top() < 0) + answerRect.setTop(0); + if (answerRect.bottom() > 4096) + answerRect.setBottom(4096); + if (answerRect.width() < 0) + answerRect.setWidth(0); + if (answerRect.height() < 0) + answerRect.setHeight(0); + +// response.data.data32[2] = (answerRect.x() << 16) + answerRect.y(); +// response.data.data32[3] = (answerRect.width() << 16) + answerRect.height(); + response.data.data32[4] = toXdndAction(accepted_action); + } + + // reset + target_time = XCB_CURRENT_TIME; + + DEBUG() << "sending XdndStatus" << (xdnd_dragsource == connection()->clipboard()->owner()) << xdnd_dragsource + << response.data.data32[1] << connection()->atomName(response.data.data32[4]); + if (xdnd_dragsource == connection()->clipboard()->owner()) + handle_xdnd_status(&response, passive); + else + Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xdnd_dragsource, + XCB_EVENT_MASK_NO_EVENT, (const char *)&response)); +} + +namespace +{ + class ClientMessageScanner { + public: + ClientMessageScanner(xcb_atom_t a) : atom(a) {} + xcb_atom_t atom; + bool check(xcb_generic_event_t *event) const { + if (!event) + return false; + if ((event->response_type & 0x7f) != XCB_CLIENT_MESSAGE) + return false; + return ((xcb_client_message_event_t *)event)->type == atom; + } + }; +} + +void QXcbDrag::handlePosition(QWindow * w, const xcb_client_message_event_t *event, bool passive) +{ + xcb_client_message_event_t *lastEvent = const_cast<xcb_client_message_event_t *>(event); + xcb_generic_event_t *nextEvent; + ClientMessageScanner scanner(atom(QXcbAtom::XdndPosition)); + while ((nextEvent = connection()->checkEvent(scanner))) { + if (lastEvent != event) + free(lastEvent); + lastEvent = (xcb_client_message_event_t *)nextEvent; + } + + handle_xdnd_position(w, lastEvent, passive); + if (lastEvent != event) + free(lastEvent); +} + +void QXcbDrag::handle_xdnd_status(const xcb_client_message_event_t *event, bool) +{ + DEBUG("xdndHandleStatus"); + // ignore late status messages + if (event->data.data32[0] && event->data.data32[0] != current_proxy_target) + return; + + Qt::DropAction newAction = (event->data.data32[1] & 0x1) ? toDropAction(event->data.data32[4]) : Qt::IgnoreAction; + + if ((event->data.data32[1] & 2) == 0) { + QPoint p((event->data.data32[2] & 0xffff0000) >> 16, event->data.data32[2] & 0x0000ffff); + QSize s((event->data.data32[3] & 0xffff0000) >> 16, event->data.data32[3] & 0x0000ffff); + source_sameanswer = QRect(p, s); + } else { + source_sameanswer = QRect(); + } + QDragManager *manager = QDragManager::self(); + manager->willDrop = (event->data.data32[1] & 0x1); + if (manager->global_accepted_action != newAction) { + manager->global_accepted_action = newAction; + manager->emitActionChanged(newAction); + } + DEBUG() << "willDrop=" << manager->willDrop << "action=" << newAction; + manager->updateCursor(); + waiting_for_status = false; +} + +void QXcbDrag::handleStatus(const xcb_client_message_event_t *event, bool passive) +{ + if (event->window != connection()->clipboard()->owner()) + return; + + xcb_client_message_event_t *lastEvent = const_cast<xcb_client_message_event_t *>(event); + qDebug() << "handleStatus" << lastEvent->window << lastEvent->data.data32[0]; + xcb_generic_event_t *nextEvent; + ClientMessageScanner scanner(atom(QXcbAtom::XdndStatus)); + while ((nextEvent = connection()->checkEvent(scanner))) { + if (lastEvent != event) + free(lastEvent); + lastEvent = (xcb_client_message_event_t *)nextEvent; + } + + handle_xdnd_status(lastEvent, passive); + if (lastEvent != event) + free(lastEvent); + DEBUG("xdndHandleStatus end"); +} + +void QXcbDrag::handleLeave(QWindow *w, const xcb_client_message_event_t *event, bool /*passive*/) +{ + DEBUG("xdnd leave"); + if (!currentWindow || w != currentWindow.data()) + return; // sanity + + // ### +// if (checkEmbedded(current_embedding_widget, event)) { +// current_embedding_widget = 0; +// currentWindow.clear(); +// return; +// } + + if (event->data.data32[0] != xdnd_dragsource) { + // This often happens - leave other-process window quickly + DEBUG("xdnd drag leave from unexpected source (%x not %x", event->data.data32[0], xdnd_dragsource); + } + + QDragLeaveEvent e; + QGuiApplication::sendEvent(currentWindow.data(), &e); + + xdnd_dragsource = 0; + xdnd_types.clear(); + currentWindow.clear(); +} + +void QXcbDrag::send_leave() +{ + if (!current_target) + return; + + QDragManager *manager = QDragManager::self(); + + xcb_client_message_event_t leave; + leave.response_type = XCB_CLIENT_MESSAGE; + leave.window = current_target; + leave.format = 32; + leave.type = atom(QXcbAtom::XdndLeave); + leave.data.data32[0] = connection()->clipboard()->owner(); + leave.data.data32[1] = 0; // flags + leave.data.data32[2] = 0; // x, y + leave.data.data32[3] = 0; // w, h + leave.data.data32[4] = 0; // just null + + QXcbWindow *w = connection()->platformWindowFromId(current_proxy_target); + + if (w && (w->window()->windowType() == Qt::Desktop) /*&& !w->acceptDrops()*/) + w = 0; + + if (w) + handleLeave(w->window(), (const xcb_client_message_event_t *)&leave, false); + else + xcb_send_event(xcb_connection(), false,current_proxy_target, + XCB_EVENT_MASK_NO_EVENT, (const char *)&leave); + + // reset the drag manager state + manager->willDrop = false; + if (manager->global_accepted_action != Qt::IgnoreAction) + manager->emitActionChanged(Qt::IgnoreAction); + manager->global_accepted_action = Qt::IgnoreAction; + manager->updateCursor(); + current_target = 0; + current_proxy_target = 0; + source_time = XCB_CURRENT_TIME; + waiting_for_status = false; +} + +void QXcbDrag::handleDrop(QWindow *, const xcb_client_message_event_t *event, bool passive) +{ + DEBUG("xdndHandleDrop"); + if (!currentWindow) { + xdnd_dragsource = 0; + return; // sanity + } + + // ### +// if (!passive && checkEmbedded(currentWindow, xe)){ +// current_embedding_widget = 0; +// xdnd_dragsource = 0; +// currentWindow = 0; +// return; +// } + const uint32_t *l = event->data.data32; + + QDragManager *manager = QDragManager::self(); + DEBUG("xdnd drop"); + + if (l[0] != xdnd_dragsource) { + DEBUG("xdnd drop from unexpected source (%x not %x", l[0], xdnd_dragsource); + return; + } + + // update the "user time" from the timestamp in the event. + if (l[2] != 0) + target_time = /*X11->userTime =*/ l[2]; + + if (!passive) { + // this could be a same-application drop, just proxied due to + // some XEMBEDding, so try to find the real QMimeData used + // based on the timestamp for this drop. + QMimeData *dropData = 0; + // ### +// int at = findXdndDropTransactionByTime(target_time); +// if (at != -1) +// dropData = QDragManager::dragPrivate(X11->dndDropTransactions.at(at).object)->data; + // if we can't find it, then use the data in the drag manager + if (!dropData) + dropData = manager->dropData(); + + // Drop coming from another app? Update keyboard modifiers. +// if (!qt_xdnd_dragging) { +// QApplicationPrivate::modifier_buttons = currentKeyboardModifiers(); +// } + + QDropEvent de(currentPosition, manager->possible_actions, dropData, + QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); + QGuiApplication::sendEvent(currentWindow.data(), &de); + if (!de.isAccepted()) { + // Ignore a failed drag + manager->global_accepted_action = Qt::IgnoreAction; + } else { + manager->global_accepted_action = de.dropAction(); + } + xcb_client_message_event_t finished; + finished.response_type = XCB_CLIENT_MESSAGE; + finished.window = xdnd_dragsource; + finished.format = 32; + finished.type = atom(QXcbAtom::XdndFinished); + DNDDEBUG << "xdndHandleDrop" + << "currentWindow" << currentWindow.data() + << (currentWindow ? xcb_window(currentWindow.data()) : 0); + finished.data.data32[0] = currentWindow ? xcb_window(currentWindow.data()) : XCB_NONE; + finished.data.data32[1] = de.isAccepted() ? 1 : 0; // flags + finished.data.data32[2] = toXdndAction(manager->global_accepted_action); + Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xdnd_dragsource, + XCB_EVENT_MASK_NO_EVENT, (char *)&finished)); + } else { + QDragLeaveEvent e; + QGuiApplication::sendEvent(currentWindow.data(), &e); + } + xdnd_dragsource = 0; + currentWindow.clear(); + waiting_for_status = false; + + // reset + target_time = XCB_CURRENT_TIME; +} + + +void QXcbDrag::handleFinished(const xcb_client_message_event_t *event, bool) +{ + DEBUG("xdndHandleFinished"); + if (event->window != connection()->clipboard()->owner()) + return; + + const unsigned long *l = (const unsigned long *)event->data.data32; + + DNDDEBUG << "xdndHandleFinished, l[0]" << l[0] + << "current_target" << current_target + << "qt_xdnd_current_proxy_targe" << current_proxy_target; + + if (l[0]) { + int at = findTransactionByWindow(l[0]); + if (at != -1) { + restartDropExpiryTimer(); + + Transaction t = transactions.takeAt(at); +// QDragManager *manager = QDragManager::self(); + +// Window target = current_target; +// Window proxy_target = current_proxy_target; +// QWidget *embedding_widget = current_embedding_widget; +// QDrag *currentObject = manager->object; + +// current_target = t.target; +// current_proxy_target = t.proxy_target; +// current_embedding_widget = t.embedding_widget; +// manager->object = t.object; + +// if (!passive) +// (void) checkEmbedded(currentWindow, xe); + +// current_embedding_widget = 0; +// current_target = 0; +// current_proxy_target = 0; + + if (t.object) + t.object->deleteLater(); + +// current_target = target; +// current_proxy_target = proxy_target; +// current_embedding_widget = embedding_widget; +// manager->object = currentObject; + } + } + waiting_for_status = false; +} + + +void QXcbDrag::timerEvent(QTimerEvent* e) +{ + if (e->timerId() == heartbeat && source_sameanswer.isNull()) { + QMouseEvent me(QEvent::MouseMove, QCursor::pos(), QCursor::pos(), Qt::LeftButton, + QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); + move(&me); + } else if (e->timerId() == transaction_expiry_timer) { + for (int i = 0; i < transactions.count(); ++i) { + const Transaction &t = transactions.at(i); + if (t.targetWindow) { + // dnd within the same process, don't delete these + continue; + } + t.object->deleteLater(); + transactions.removeAt(i--); + } + + killTimer(transaction_expiry_timer); + transaction_expiry_timer = -1; + } +} + +void QXcbDrag::cancel() +{ + DEBUG("QXcbDrag::cancel"); + endDrag(); + + if (current_target) + send_leave(); + + current_target = 0; +} + +#if 0 + +static +Window findRealWindow(const QPoint & pos, Window w, int md) +{ + if (xdnd_data.deco && w == xdnd_data.deco->effectiveWinId()) + return 0; + + if (md) { + X11->ignoreBadwindow(); + XWindowAttributes attr; + XGetWindowAttributes(X11->display, w, &attr); + if (X11->badwindow()) + return 0; + + if (attr.map_state == IsViewable + && QRect(attr.x,attr.y,attr.width,attr.height).contains(pos)) { + { + Atom type = XNone; + int f; + unsigned long n, a; + unsigned char *data; + + XGetWindowProperty(X11->display, w, ATOM(XdndAware), 0, 0, False, + AnyPropertyType, &type, &f,&n,&a,&data); + if (data) XFree(data); + if (type) + return w; + } + + Window r, p; + Window* c; + uint nc; + if (XQueryTree(X11->display, w, &r, &p, &c, &nc)) { + r=0; + for (uint i=nc; !r && i--;) { + r = findRealWindow(pos-QPoint(attr.x,attr.y), + c[i], md-1); + } + XFree(c); + if (r) + return r; + + // We didn't find a client window! Just use the + // innermost window. + } + + // No children! + return w; + } + } + return 0; +} +#endif + +void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event) +{ + xcb_selection_notify_event_t notify; + notify.response_type = XCB_SELECTION_NOTIFY; + notify.requestor = event->requestor; + notify.selection = event->selection; + notify.target = XCB_NONE; + notify.property = XCB_NONE; + notify.time = event->time; + + QDragManager *manager = QDragManager::self(); + QDrag *currentObject = manager->object; + + // which transaction do we use? (note: -2 means use current manager->object) + int at = -1; + + // figure out which data the requestor is really interested in + if (manager->object && event->time == source_time) { + // requestor wants the current drag data + at = -2; + } else { + // if someone has requested data in response to XdndDrop, find the corresponding transaction. the + // spec says to call XConvertSelection() using the timestamp from the XdndDrop + at = findTransactionByTime(event->time); + if (at == -1) { + // no dice, perhaps the client was nice enough to use the same window id in XConvertSelection() + // that we sent the XdndDrop event to. + at = findTransactionByWindow(event->requestor); + } +// if (at == -1 && event->time == XCB_CURRENT_TIME) { +// // previous Qt versions always requested the data on a child of the target window +// // using CurrentTime... but it could be asking for either drop data or the current drag's data +// Window target = findXdndAwareParent(event->requestor); +// if (target) { +// if (current_target && current_target == target) +// at = -2; +// else +// at = findXdndDropTransactionByWindow(target); +// } +// } + } + if (at >= 0) { + restartDropExpiryTimer(); + + // use the drag object from an XdndDrop tansaction + manager->object = transactions.at(at).object; + } else if (at != -2) { + // no transaction found, we'll have to reject the request + manager->object = 0; + } + if (manager->object) { + xcb_atom_t atomFormat = event->target; + int dataFormat = 0; + QByteArray data; + if (QXcbMime::mimeDataForAtom(connection(), event->target, manager->dragPrivate()->data, + &data, &atomFormat, &dataFormat)) { + int dataSize = data.size() / (dataFormat / 8); + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, event->requestor, event->property, + atomFormat, dataFormat, dataSize, (const void *)data.constData()); + notify.property = event->property; + notify.target = atomFormat; + } + } + + // reset manager->object in case we modified it above + manager->object = currentObject; + + xcb_send_event(xcb_connection(), false, event->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)¬ify); +} + + +bool QXcbDrag::dndEnable(QXcbWindow *w, bool on) +{ + DNDDEBUG << "xdndEnable" << w << on; + if (on) { + QXcbWindow *xdnd_widget = 0; + if ((w->window()->windowType() == Qt::Desktop)) { + if (desktop_proxy) // *WE* already have one. + return false; + + xcb_grab_server(xcb_connection()); + + // As per Xdnd4, use XdndProxy + xcb_window_t proxy_id = xdndProxy(connection(), w->xcb_window()); + + if (!proxy_id) { + desktop_proxy = new QWindow; + xdnd_widget = static_cast<QXcbWindow *>(desktop_proxy->handle()); + proxy_id = xdnd_widget->xcb_window(); + xcb_atom_t xdnd_proxy = atom(QXcbAtom::XdndProxy); + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, w->xcb_window(), xdnd_proxy, + XCB_ATOM_WINDOW, 32, 1, &proxy_id); + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, proxy_id, xdnd_proxy, + XCB_ATOM_WINDOW, 32, 1, &proxy_id); + } + + xcb_ungrab_server(xcb_connection()); + } else { + xdnd_widget = w; + } + if (xdnd_widget) { + DNDDEBUG << "setting XdndAware for" << xdnd_widget << xdnd_widget->xcb_window(); + xcb_atom_t atm = xdnd_version; + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, xdnd_widget->xcb_window(), + atom(QXcbAtom::XdndAware), XCB_ATOM_ATOM, 32, 1, &atm); + return true; + } else { + return false; + } + } else { + if ((w->window()->windowType() == Qt::Desktop)) { + xcb_delete_property(xcb_connection(), w->xcb_window(), atom(QXcbAtom::XdndProxy)); + delete desktop_proxy; + desktop_proxy = 0; + } else { + DNDDEBUG << "not deleting XDndAware"; + } + return true; + } +} + + + + +QDropData::QDropData(QXcbDrag *d) + : QXcbMime(), + drag(d) +{ +} + +QDropData::~QDropData() +{ +} + +QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type requestedType) const +{ + QByteArray mime = mimetype.toLatin1(); + QVariant data = /*X11->motifdnd_active + ? X11->motifdndObtainData(mime) + :*/ xdndObtainData(mime, requestedType); + return data; +} + +QVariant QDropData::xdndObtainData(const QByteArray &format, QVariant::Type requestedType) const +{ + QByteArray result; + + QDragManager *manager = QDragManager::self(); + QXcbConnection *c = drag->connection(); + QXcbWindow *xcb_window = c->platformWindowFromId(drag->xdnd_dragsource); + if (xcb_window && manager->object && xcb_window->window()->windowType() != Qt::Desktop) { + QDragPrivate *o = manager->dragPrivate(); + if (o->data->hasFormat(QLatin1String(format))) + result = o->data->data(QLatin1String(format)); + return result; + } + + QList<xcb_atom_t> atoms = drag->xdnd_types; + QByteArray encoding; + xcb_atom_t a = mimeAtomForFormat(c, QLatin1String(format), requestedType, atoms, &encoding); + if (a == XCB_NONE) + return result; + + if (c->clipboard()->getSelectionOwner(drag->atom(QXcbAtom::XdndSelection)) == XCB_NONE) + return result; // should never happen? + + xcb_atom_t xdnd_selection = c->atom(QXcbAtom::XdndSelection); + result = c->clipboard()->getSelection(xdnd_selection, a, xdnd_selection); + + return mimeConvertToFormat(c, a, result, QLatin1String(format), requestedType, encoding); +} + + +bool QDropData::hasFormat_sys(const QString &format) const +{ + return formats().contains(format); +} + +QStringList QDropData::formats_sys() const +{ + QStringList formats; +// if (X11->motifdnd_active) { +// int i = 0; +// QByteArray fmt; +// while (!(fmt = X11->motifdndFormat(i)).isEmpty()) { +// formats.append(QLatin1String(fmt)); +// ++i; +// } +// } else { + for (int i = 0; i < drag->xdnd_types.size(); ++i) { + QString f = mimeAtomToString(drag->connection(), drag->xdnd_types.at(i)); + if (!formats.contains(f)) + formats.append(f); + } +// } + return formats; +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h new file mode 100644 index 0000000000..ce0f8faa54 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbdrag.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXCBDRAG_H +#define QXCBDRAG_H + +#include <qplatformdrag_qpa.h> +#include <qxcbobject.h> +#include <xcb/xcb.h> +#include <qlist.h> +#include <qpoint.h> +#include <qrect.h> +#include <qsharedpointer.h> +#include <qvector.h> + +QT_BEGIN_NAMESPACE + +class QMouseEvent; +class QWindow; +class QXcbConnection; +class QXcbWindow; +class QDropData; +class QXcbScreen; +class QDrag; + +class QXcbDrag : public QObject, public QXcbObject, public QPlatformDrag +{ +public: + QXcbDrag(QXcbConnection *c); + ~QXcbDrag(); + + virtual QMimeData *platformDropData(); + +// virtual Qt::DropAction drag(QDrag *); + + virtual void startDrag(); + virtual void cancel(); + virtual void move(const QMouseEvent *me); + virtual void drop(const QMouseEvent *me); + void endDrag(); + + void handleEnter(QWindow *window, const xcb_client_message_event_t *event); + void handlePosition(QWindow *w, const xcb_client_message_event_t *event, bool passive); + void handleLeave(QWindow *w, const xcb_client_message_event_t *event, bool /*passive*/); + void handleDrop(QWindow *, const xcb_client_message_event_t *event, bool passive); + + void handleStatus(const xcb_client_message_event_t *event, bool passive); + void handleSelectionRequest(const xcb_selection_request_event_t *event); + void handleFinished(const xcb_client_message_event_t *event, bool passive); + + bool dndEnable(QXcbWindow *win, bool on); + +protected: + void timerEvent(QTimerEvent* e); + +private: + friend class QDropData; + + void init(); + + void handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *event, bool passive); + void handle_xdnd_status(const xcb_client_message_event_t *event, bool); + void send_leave(); + + Qt::DropAction toDropAction(xcb_atom_t atom) const; + xcb_atom_t toXdndAction(Qt::DropAction a) const; + + QWeakPointer<QWindow> currentWindow; + QPoint currentPosition; + + QDropData *dropData; + + QWindow *desktop_proxy; + + xcb_atom_t xdnd_dragsource; + + // the types in this drop. 100 is no good, but at least it's big. + enum { xdnd_max_type = 100 }; + QList<xcb_atom_t> xdnd_types; + + xcb_timestamp_t target_time; + xcb_timestamp_t source_time; + Qt::DropAction last_target_accepted_action; + + // rectangle in which the answer will be the same + QRect source_sameanswer; + bool waiting_for_status; + + // top-level window we sent position to last. + xcb_window_t current_target; + // window to send events to (always valid if current_target) + xcb_window_t current_proxy_target; + + QXcbScreen *current_screen; + + int heartbeat; + bool xdnd_dragging; + + QVector<xcb_atom_t> drag_types; + + struct Transaction + { + xcb_timestamp_t timestamp; + xcb_window_t target; + xcb_window_t proxy_target; + QWindow *targetWindow; +// QWidget *embedding_widget; + QDrag *object; + }; + QList<Transaction> transactions; + + int transaction_expiry_timer; + void restartDropExpiryTimer(); + int findTransactionByWindow(xcb_window_t window); + int findTransactionByTime(xcb_timestamp_t timestamp); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/xcb/qxcbimage.cpp b/src/plugins/platforms/xcb/qxcbimage.cpp new file mode 100644 index 0000000000..569e4fc4e4 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbimage.cpp @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxcbimage.h" +#include <QtGui/QColor> +#include <QtGui/private/qimage_p.h> +#include <QtGui/private/qdrawhelper_p.h> +#ifdef XCB_USE_RENDER +#include <xcb/render.h> +// 'template' is used as a function argument name in xcb_renderutil.h +#define template template_param +// extern "C" is missing too +extern "C" { +#include <xcb/xcb_renderutil.h> +} +#undef template +#endif + +QT_BEGIN_NAMESPACE + +QImage::Format qt_xcb_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 qt_xcb_pixmapFromXPixmap(QXcbConnection *connection, xcb_pixmap_t pixmap, + int width, int height, int depth, + const xcb_visualtype_t *visual) +{ + xcb_connection_t *conn = connection->xcb_connection(); + xcb_generic_error_t *error = 0; + + xcb_get_image_cookie_t get_image_cookie = + xcb_get_image(conn, XCB_IMAGE_FORMAT_Z_PIXMAP, pixmap, + 0, 0, width, height, 0xffffffff); + + xcb_get_image_reply_t *image_reply = + xcb_get_image_reply(conn, get_image_cookie, &error); + + if (!image_reply) { + if (error) { + 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 = qt_xcb_imageFormatForVisual(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 = 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; + } + } + + result = QPixmap::fromImage(image.copy()); + } + + free(image_reply); + return result; +} + +xcb_pixmap_t qt_xcb_XPixmapFromBitmap(QXcbScreen *screen, const QImage &image) +{ + xcb_connection_t *conn = screen->xcb_connection(); + QImage bitmap = image.convertToFormat(QImage::Format_MonoLSB); + const QRgb c0 = QColor(Qt::black).rgb(); + const QRgb c1 = QColor(Qt::white).rgb(); + if (bitmap.color(0) == c0 && bitmap.color(1) == c1) { + bitmap.invertPixels(); + bitmap.setColor(0, c1); + bitmap.setColor(1, c0); + } + const int width = bitmap.width(); + const int height = bitmap.height(); + const int bytesPerLine = bitmap.bytesPerLine(); + int destLineSize = width / 8; + if (width % 8) + ++destLineSize; + const uchar *map = bitmap.bits(); + uint8_t *buf = new uint8_t[height * destLineSize]; + for (int i = 0; i < height; i++) + memcpy(buf + (destLineSize * i), map + (bytesPerLine * i), destLineSize); + xcb_pixmap_t pm = xcb_create_pixmap_from_bitmap_data(conn, screen->root(), buf, + width, height, 1, 0, 0, 0); + delete[] buf; + return pm; +} + +xcb_cursor_t qt_xcb_createCursorXRender(QXcbScreen *screen, const QImage &image, + const QPoint &spot) +{ +#ifdef XCB_USE_RENDER + xcb_connection_t *conn = screen->xcb_connection(); + const int w = image.width(); + const int h = image.height(); + xcb_generic_error_t *error = 0; + xcb_render_query_pict_formats_cookie_t formatsCookie = xcb_render_query_pict_formats(conn); + xcb_render_query_pict_formats_reply_t *formatsReply = xcb_render_query_pict_formats_reply(conn, + formatsCookie, + &error); + if (!formatsReply || error) { + qWarning("createCursorXRender: query_pict_formats failed"); + free(formatsReply); + free(error); + return XCB_NONE; + } + xcb_render_pictforminfo_t *fmt = xcb_render_util_find_standard_format(formatsReply, + XCB_PICT_STANDARD_ARGB_32); + if (!fmt) { + qWarning("createCursorXRender: Failed to find format PICT_STANDARD_ARGB_32"); + free(formatsReply); + return XCB_NONE; + } + + QImage img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + xcb_image_t *xi = xcb_image_create(w, h, XCB_IMAGE_FORMAT_Z_PIXMAP, + 32, 32, 32, 32, + QSysInfo::ByteOrder == QSysInfo::BigEndian ? XCB_IMAGE_ORDER_MSB_FIRST : XCB_IMAGE_ORDER_LSB_FIRST, + XCB_IMAGE_ORDER_MSB_FIRST, + 0, 0, 0); + if (!xi) { + qWarning("createCursorXRender: xcb_image_create failed"); + free(formatsReply); + return XCB_NONE; + } + xi->data = (uint8_t *) malloc(xi->stride * h); + if (!xi->data) { + qWarning("createCursorXRender: Failed to malloc() image data"); + xcb_image_destroy(xi); + free(formatsReply); + return XCB_NONE; + } + memcpy(xi->data, img.constBits(), img.byteCount()); + + xcb_pixmap_t pix = xcb_generate_id(conn); + xcb_create_pixmap(conn, 32, pix, screen->root(), w, h); + + xcb_render_picture_t pic = xcb_generate_id(conn); + xcb_render_create_picture(conn, pic, pix, fmt->id, 0, 0); + + xcb_gcontext_t gc = xcb_generate_id(conn); + xcb_create_gc(conn, gc, pix, 0, 0); + xcb_image_put(conn, pix, gc, xi, 0, 0, 0); + xcb_free_gc(conn, gc); + + xcb_cursor_t cursor = xcb_generate_id(conn); + xcb_render_create_cursor(conn, cursor, pic, spot.x(), spot.y()); + + free(xi->data); + xcb_image_destroy(xi); + xcb_render_free_picture(conn, pic); + xcb_free_pixmap(conn, pix); + free(formatsReply); + return cursor; + +#else + Q_UNUSED(screen); + Q_UNUSED(image); + Q_UNUSED(spot); + return XCB_NONE; +#endif +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/glxconvenience/qglxconvenience.h b/src/plugins/platforms/xcb/qxcbimage.h index 7478abfeba..1e7f104084 100644 --- a/src/plugins/platforms/glxconvenience/qglxconvenience.h +++ b/src/plugins/platforms/xcb/qxcbimage.h @@ -39,18 +39,26 @@ ** ****************************************************************************/ -#ifndef QGLXCONVENIENCE_H -#define QGLXCONVENIENCE_H +#ifndef QXCBIMAGE_H +#define QXCBIMAGE_H -#include <QPlatformWindowFormat> +#include "qxcbscreen.h" +#include <QtCore/QPair> +#include <QtGui/QImage> +#include <QtGui/QPixmap> +#include <xcb/xcb_image.h> -#include <X11/Xlib.h> -#include <GL/glx.h> +QT_BEGIN_NAMESPACE -XVisualInfo *qglx_findVisualInfo(Display *display, int screen, const QPlatformWindowFormat &format); -GLXFBConfig qglx_findConfig(Display *display, int screen, const QPlatformWindowFormat &format, int drawableBit = GLX_WINDOW_BIT); -QPlatformWindowFormat qglx_platformWindowFromGLXFBConfig(Display *display, GLXFBConfig config, GLXContext context); -QVector<int> qglx_buildSpec(const QPlatformWindowFormat &format, int drawableBit = GLX_WINDOW_BIT); -QPlatformWindowFormat qglx_reducePlatformWindowFormat(const QPlatformWindowFormat &format, bool *reduced); +QImage::Format qt_xcb_imageFormatForVisual(QXcbConnection *connection, + uint8_t depth, const xcb_visualtype_t *visual); +QPixmap qt_xcb_pixmapFromXPixmap(QXcbConnection *connection, xcb_pixmap_t pixmap, + int width, int height, int depth, + const xcb_visualtype_t *visual); +xcb_pixmap_t qt_xcb_XPixmapFromBitmap(QXcbScreen *screen, const QImage &image); +xcb_cursor_t qt_xcb_createCursorXRender(QXcbScreen *screen, const QImage &image, + const QPoint &spot); -#endif // QGLXCONVENIENCE_H +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index 12b63f36ea..45d9d69199 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -45,12 +45,17 @@ #include "qxcbwindow.h" #include "qxcbwindowsurface.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/qgenericunixfontdatabase_p.h> #include <stdio.h> @@ -58,8 +63,14 @@ #include <EGL/egl.h> #endif +#if defined(XCB_USE_GLX) +#include "qglxintegration.h" +#elif defined(XCB_USE_EGL) +#include "../eglconvenience/qeglplatformcontext.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; @@ -87,16 +98,26 @@ 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); +} + +QPlatformGLContext *QXcbIntegration::createPlatformGLContext(const QGuiGLFormat &glFormat, QPlatformGLContext *share) const +{ +#if defined(XCB_USE_GLX) + return new QGLXContext(static_cast<QXcbScreen *>(m_screens.at(0)), glFormat, share); +#elif defined(XCB_USE_EGL) + return new QEGLPlatformContext(glFormat, share, m_connection->egl_display()); +#elif defined(XCB_USE_DRI2) + return new QDri2Context(glFormat, share); +#endif } -QWindowSurface *QXcbIntegration::createWindowSurface(QWidget *widget, WId winId) const +QWindowSurface *QXcbIntegration::createWindowSurface(QWindow *window, WId winId) const { Q_UNUSED(winId); - return new QXcbWindowSurface(widget); + return new QXcbWindowSurface(window); } QList<QPlatformScreen *> QXcbIntegration::screens() const @@ -104,7 +125,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 +143,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 +279,18 @@ 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(); +} diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index cd68919b54..d931e2a787 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -57,11 +57,12 @@ public: bool hasCapability(Capability cap) const; QPixmapData *createPixmapData(QPixmapData::PixelType type) const; - QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId) const; - QWindowSurface *createWindowSurface(QWidget *widget, WId winId) const; + QPlatformWindow *createPlatformWindow(QWindow *window) const; + QPlatformGLContext *createPlatformGLContext(const QGuiGLFormat &glFormat, QPlatformGLContext *share) const; + QWindowSurface *createWindowSurface(QWindow *window, WId winId) const; QList<QPlatformScreen *> screens() const; - void moveToScreen(QWidget *window, int screen); + void moveToScreen(QWindow *window, int screen); bool isVirtualDesktop(); QPixmap grabWindow(WId window, int x, int y, int width, int height) const; @@ -69,6 +70,10 @@ public: QPlatformNativeInterface *nativeInterface()const; + QPlatformPrinterSupport *printerSupport() const; + QPlatformClipboard *clipboard() const; + QPlatformDrag *drag() const; + private: bool hasOpenGL() const; QList<QPlatformScreen *> m_screens; @@ -76,6 +81,7 @@ private: QPlatformFontDatabase *m_fontDatabase; QPlatformNativeInterface *m_nativeInterface; + QPlatformPrinterSupport *m_printerSupport; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 6bbc3c18ca..5c034252d3 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -40,14 +40,12 @@ ****************************************************************************/ #include "qxcbkeyboard.h" - +#include "qxcbwindow.h" +#include "qxcbscreen.h" #include <xcb/xcb_keysyms.h> - #include <X11/keysym.h> - #include <QtGui/QWindowSystemInterface> #include <QtCore/QTextCodec> - #include <stdio.h> #ifndef XK_ISO_Left_Tab @@ -898,12 +896,9 @@ QString QXcbKeyboard::translateKeySym(xcb_keysym_t keysym, uint xmodifiers, QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection) : QXcbObject(connection) - , m_alt_mask(0) - , m_super_mask(0) - , m_hyper_mask(0) - , m_meta_mask(0) { m_key_symbols = xcb_key_symbols_alloc(xcb_connection()); + setupModifiers(); } QXcbKeyboard::~QXcbKeyboard() @@ -911,18 +906,113 @@ QXcbKeyboard::~QXcbKeyboard() xcb_key_symbols_free(m_key_symbols); } -// #define XCB_KEYBOARD_DEBUG +void QXcbKeyboard::setupModifiers() +{ + m_alt_mask = 0; + m_super_mask = 0; + m_hyper_mask = 0; + m_meta_mask = 0; + m_mode_switch_mask = 0; + m_num_lock_mask = 0; + m_caps_lock_mask = 0; + + xcb_generic_error_t *error = 0; + xcb_connection_t *conn = xcb_connection(); + xcb_get_modifier_mapping_cookie_t modMapCookie = xcb_get_modifier_mapping(conn); + xcb_get_modifier_mapping_reply_t *modMapReply = + xcb_get_modifier_mapping_reply(conn, modMapCookie, &error); + if (error) { + qWarning("xcb keyboard: failed to get modifier mapping"); + free(error); + return; + } + + // Figure out the modifier mapping, ICCCM 6.6 + typedef QPair<uint, xcb_keycode_t *> SymCodes; + QList<SymCodes> modKeyCodes; + + // for Alt and Meta L and R are the same + modKeyCodes << SymCodes(XK_Alt_L, xcb_key_symbols_get_keycode(m_key_symbols, XK_Alt_L)); + modKeyCodes << SymCodes(XK_Meta_L, xcb_key_symbols_get_keycode(m_key_symbols, XK_Meta_L)); + modKeyCodes << SymCodes(XK_Super_L, xcb_key_symbols_get_keycode(m_key_symbols, XK_Super_L)); + modKeyCodes << SymCodes(XK_Super_R, xcb_key_symbols_get_keycode(m_key_symbols, XK_Super_R)); + modKeyCodes << SymCodes(XK_Hyper_L, xcb_key_symbols_get_keycode(m_key_symbols, XK_Hyper_L)); + modKeyCodes << SymCodes(XK_Hyper_R, xcb_key_symbols_get_keycode(m_key_symbols, XK_Hyper_R)); + modKeyCodes << SymCodes(XK_Num_Lock, xcb_key_symbols_get_keycode(m_key_symbols, XK_Num_Lock)); + modKeyCodes << SymCodes(XK_Mode_switch, xcb_key_symbols_get_keycode(m_key_symbols, XK_Mode_switch)); + modKeyCodes << SymCodes(XK_Caps_Lock, xcb_key_symbols_get_keycode(m_key_symbols, XK_Caps_Lock)); + + xcb_keycode_t *modMap = xcb_get_modifier_mapping_keycodes(modMapReply); + const int w = modMapReply->keycodes_per_modifier; + for (int i = 0; i < modKeyCodes.count(); ++i) { + for (int bit = 0; bit < 8; ++bit) { + uint mask = 1 << bit; + for (int x = 0; x < w; ++x) { + xcb_keycode_t keyCode = modMap[x + bit * w]; + xcb_keycode_t *itk = modKeyCodes.at(i).second; + while (itk && *itk != XCB_NO_SYMBOL) + if (*itk++ == keyCode) + setMask(modKeyCodes.at(i).first, mask); + } + } + } + + for (int i = 0; i < modKeyCodes.count(); ++i) + free(modKeyCodes.at(i).second); + free(modMapReply); +} -void QXcbKeyboard::handleKeyEvent(QWidget *widget, QEvent::Type type, xcb_keycode_t code, quint16 state, xcb_timestamp_t time) +void QXcbKeyboard::setMask(uint sym, uint mask) { - int col = state & XCB_MOD_MASK_SHIFT ? 1 : 0; + if (m_alt_mask == 0 + && m_meta_mask != mask + && m_super_mask != mask + && m_hyper_mask != mask + && (sym == XK_Alt_L || sym == XK_Alt_R)) + m_alt_mask = mask; + + if (m_meta_mask == 0 + && m_alt_mask != mask + && m_super_mask != mask + && m_hyper_mask != mask + && (sym == XK_Meta_L || sym == XK_Meta_R)) + m_meta_mask = mask; + + if (m_super_mask == 0 + && m_alt_mask != mask + && m_meta_mask != mask + && m_hyper_mask != mask + && (sym == XK_Super_L || sym == XK_Super_R)) + m_super_mask = mask; + + if (m_hyper_mask == 0 + && m_alt_mask != mask + && m_meta_mask != mask + && m_super_mask != mask + && (sym == XK_Hyper_L || sym == XK_Hyper_R)) + m_hyper_mask = mask; + + if (m_mode_switch_mask == 0 + && m_alt_mask != mask + && m_meta_mask != mask + && m_super_mask != mask + && m_hyper_mask != mask + && sym == XK_Mode_switch) + m_mode_switch_mask = mask; + + if (m_num_lock_mask == 0 && sym == XK_Num_Lock) + m_num_lock_mask = mask; + + if (m_caps_lock_mask == 0 && sym == XK_Caps_Lock) + m_caps_lock_mask = mask; +} - const int altGrOffset = 4; - if (state & 128) - col += altGrOffset; +// #define XCB_KEYBOARD_DEBUG +void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycode_t code, + quint16 state, xcb_timestamp_t time) +{ Q_XCB_NOOP(connection()); - #ifdef XCB_KEYBOARD_DEBUG printf("key code: %d, state: %d, syms: ", code, state); for (int i = 0; i <= 5; ++i) { @@ -931,43 +1021,91 @@ void QXcbKeyboard::handleKeyEvent(QWidget *widget, QEvent::Type type, xcb_keycod printf("\n"); #endif - Q_XCB_NOOP(connection()); + QByteArray chars; + xcb_keysym_t sym = lookupString(window, state, code, type, &chars); + Qt::KeyboardModifiers modifiers; + int qtcode = 0; + int count = chars.count(); + QString string = translateKeySym(sym, state, qtcode, modifiers, chars, count); + QWindowSystemInterface::handleExtendedKeyEvent(window, time, type, qtcode, modifiers, + code, 0, state, string.left(count)); +} + +#ifdef XCB_USE_XLIB +extern "C" { + int XLookupString(void *event, char *buf, int count, void *keysym, void *comp); +} +typedef struct { // must match XKeyEvent in Xlib.h + int type; + unsigned long serial; + int send_event; + void *display; + unsigned long window; + unsigned long root; + unsigned long subwindow; + unsigned long time; + int x, y; + int x_root, y_root; + unsigned int state; + unsigned int keycode; + int same_screen; +} FakeXKeyEvent; +#endif +xcb_keysym_t QXcbKeyboard::lookupString(QWindow *window, uint state, xcb_keycode_t code, + QEvent::Type type, QByteArray *chars) +{ +#ifdef XCB_USE_XLIB + + xcb_keysym_t sym = XCB_NO_SYMBOL; + chars->resize(512); + FakeXKeyEvent event; + memset(&event, 0, sizeof(event)); + event.type = (type == QEvent::KeyRelease ? 3 : 2); + event.display = connection()->xlib_display(); + event.window = static_cast<QXcbWindow *>(window->handle())->xcb_window(); + event.root = connection()->screens().at(0)->root(); + event.state = state; + event.keycode = code; + int count = XLookupString(&event, chars->data(), chars->size(), &sym, 0); + chars->resize(count); + return sym; + +#else + + // No XLookupString available. The following is really incomplete... + + int col = state & XCB_MOD_MASK_SHIFT ? 1 : 0; + const int altGrOffset = 4; + if (state & 128) + col += altGrOffset; xcb_keysym_t sym = xcb_key_symbols_get_keysym(m_key_symbols, code, col); if (sym == XCB_NO_SYMBOL) sym = xcb_key_symbols_get_keysym(m_key_symbols, code, col ^ 0x1); - if (state & XCB_MOD_MASK_LOCK && sym <= 0x7f && isprint(sym)) { if (isupper(sym)) sym = tolower(sym); else sym = toupper(sym); } + return sym; - Q_XCB_NOOP(connection()); - - QByteArray chars; - - Qt::KeyboardModifiers modifiers; - int qtcode = 0; - int count = 0; - - QString string = translateKeySym(sym, state, qtcode, modifiers, chars, count); - - QWindowSystemInterface::handleExtendedKeyEvent(widget, time, type, qtcode, modifiers, code, 0, state, string.left(count)); +#endif } -void QXcbKeyboard::handleKeyPressEvent(QWidget *widget, const xcb_key_press_event_t *event) +void QXcbKeyboard::handleKeyPressEvent(QXcbWindow *window, const xcb_key_press_event_t *event) { - handleKeyEvent(widget, QEvent::KeyPress, event->detail, event->state, event->time); + window->updateNetWmUserTime(event->time); + handleKeyEvent(window->window(), QEvent::KeyPress, event->detail, event->state, event->time); } -void QXcbKeyboard::handleKeyReleaseEvent(QWidget *widget, const xcb_key_release_event_t *event) +void QXcbKeyboard::handleKeyReleaseEvent(QXcbWindow *window, const xcb_key_release_event_t *event) { - handleKeyEvent(widget, QEvent::KeyRelease, event->detail, event->state, event->time); + handleKeyEvent(window->window(), QEvent::KeyRelease, event->detail, event->state, event->time); } void QXcbKeyboard::handleMappingNotifyEvent(const xcb_mapping_notify_event_t *event) { xcb_refresh_keyboard_mapping(m_key_symbols, const_cast<xcb_mapping_notify_event_t *>(event)); + setupModifiers(); } diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h index 095c3e4efb..d85698d936 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.h +++ b/src/plugins/platforms/xcb/qxcbkeyboard.h @@ -48,26 +48,32 @@ #include <QEvent> +class QWindow; + class QXcbKeyboard : public QXcbObject { public: QXcbKeyboard(QXcbConnection *connection); ~QXcbKeyboard(); - void handleKeyPressEvent(QWidget *widget, const xcb_key_press_event_t *event); - void handleKeyReleaseEvent(QWidget *widget, const xcb_key_release_event_t *event); + void handleKeyPressEvent(QXcbWindow *window, const xcb_key_press_event_t *event); + void handleKeyReleaseEvent(QXcbWindow *window, const xcb_key_release_event_t *event); void handleMappingNotifyEvent(const xcb_mapping_notify_event_t *event); Qt::KeyboardModifiers translateModifiers(int s); private: - void handleKeyEvent(QWidget *widget, QEvent::Type type, xcb_keycode_t code, quint16 state, xcb_timestamp_t time); + void handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycode_t code, quint16 state, xcb_timestamp_t time); int translateKeySym(uint key) const; QString translateKeySym(xcb_keysym_t keysym, uint xmodifiers, int &code, Qt::KeyboardModifiers &modifiers, QByteArray &chars, int &count); + void setupModifiers(); + void setMask(uint sym, uint mask); + xcb_keysym_t lookupString(QWindow *window, uint state, xcb_keycode_t code, + QEvent::Type type, QByteArray *chars); uint m_alt_mask; uint m_super_mask; @@ -75,8 +81,12 @@ private: uint m_meta_mask; uint m_mode_switch_mask; uint m_num_lock_mask; + uint m_caps_lock_mask; xcb_key_symbols_t *m_key_symbols; +#ifndef QT_NO_XCB_XKB + struct xkb_desc *m_xkb; +#endif }; #endif diff --git a/src/plugins/platforms/xcb/qxcbmime.cpp b/src/plugins/platforms/xcb/qxcbmime.cpp new file mode 100644 index 0000000000..d4f80ca09d --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbmime.cpp @@ -0,0 +1,288 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxcbmime.h" + +#include <QtCore/QTextCodec> +#include <QtGui/QImageWriter> +#include <QtCore/QBuffer> +#include <qdebug.h> + +#include <X11/Xutil.h> + +#undef XCB_ATOM_STRING +#undef XCB_ATOM_PIXMAP +#undef XCB_ATOM_BITMAP + +QXcbMime::QXcbMime() + : QInternalMimeData() +{ } + +QXcbMime::~QXcbMime() +{} + + + +QString QXcbMime::mimeAtomToString(QXcbConnection *connection, xcb_atom_t a) +{ + if (a == XCB_NONE) + return QString(); + + // special cases for string type + if (a == XCB_ATOM_STRING + || a == connection->atom(QXcbAtom::UTF8_STRING) + || a == connection->atom(QXcbAtom::TEXT)) + return QLatin1String("text/plain"); + + // special case for images + if (a == XCB_ATOM_PIXMAP) + return QLatin1String("image/ppm"); + + QByteArray atomName = connection->atomName(a); + + // special cases for uris + if (atomName == "text/x-moz-url") + atomName = "text/uri-list"; + + return QString::fromLatin1(atomName.constData()); +} + +bool QXcbMime::mimeDataForAtom(QXcbConnection *connection, xcb_atom_t a, QMimeData *mimeData, QByteArray *data, + xcb_atom_t *atomFormat, int *dataFormat) +{ + if (!data) + return false; + + bool ret = false; + *atomFormat = a; + *dataFormat = 8; + + if ((a == connection->atom(QXcbAtom::UTF8_STRING) + || a == XCB_ATOM_STRING + || a == connection->atom(QXcbAtom::TEXT)) + && QInternalMimeData::hasFormatHelper(QLatin1String("text/plain"), mimeData)) { + if (a == connection->atom(QXcbAtom::UTF8_STRING)) { + *data = QInternalMimeData::renderDataHelper(QLatin1String("text/plain"), mimeData); + ret = true; + } else if (a == XCB_ATOM_STRING || + a == connection->atom(QXcbAtom::TEXT)) { + // ICCCM says STRING is latin1 + *data = QString::fromUtf8(QInternalMimeData::renderDataHelper( + QLatin1String("text/plain"), mimeData)).toLatin1(); + ret = true; + } + return ret; + } + + QString atomName = mimeAtomToString(connection, a); + if (QInternalMimeData::hasFormatHelper(atomName, mimeData)) { + *data = QInternalMimeData::renderDataHelper(atomName, mimeData); + if (atomName == QLatin1String("application/x-color")) + *dataFormat = 16; + ret = true; + } else if (atomName == QLatin1String("text/x-moz-url") && + QInternalMimeData::hasFormatHelper(QLatin1String("text/uri-list"), mimeData)) { + QByteArray uri = QInternalMimeData::renderDataHelper( + QLatin1String("text/uri-list"), mimeData).split('\n').first(); + QString mozUri = QString::fromLatin1(uri, uri.size()); + mozUri += QLatin1Char('\n'); + *data = QByteArray(reinterpret_cast<const char *>(mozUri.utf16()), mozUri.length() * 2); + ret = true; + } else if ((a == XCB_ATOM_PIXMAP || a == XCB_ATOM_BITMAP) && mimeData->hasImage()) { + ret = true; + } + return ret; +} + +QList<xcb_atom_t> QXcbMime::mimeAtomsForFormat(QXcbConnection *connection, const QString &format) +{ + QList<xcb_atom_t> atoms; + atoms.append(connection->internAtom(format.toLatin1())); + + // special cases for strings + if (format == QLatin1String("text/plain")) { + atoms.append(connection->atom(QXcbAtom::UTF8_STRING)); + atoms.append(XCB_ATOM_STRING); + atoms.append(connection->atom(QXcbAtom::TEXT)); + } + + // special cases for uris + if (format == QLatin1String("text/uri-list")) + atoms.append(connection->internAtom("text/x-moz-url")); + + //special cases for images + if (format == QLatin1String("image/ppm")) + atoms.append(XCB_ATOM_PIXMAP); + if (format == QLatin1String("image/pbm")) + atoms.append(XCB_ATOM_BITMAP); + + return atoms; +} + +QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, const QByteArray &data, const QString &format, + QVariant::Type requestedType, const QByteArray &encoding) +{ + QString atomName = mimeAtomToString(connection, a); +// qDebug() << "mimeConvertDataToFormat" << format << atomName << data; + + if (!encoding.isEmpty() + && atomName == format + QLatin1String(";charset=") + QString::fromLatin1(encoding)) { + + if (requestedType == QVariant::String) { + QTextCodec *codec = QTextCodec::codecForName(encoding); + if (codec) + return codec->toUnicode(data); + } + + return data; + } + + // special cases for string types + if (format == QLatin1String("text/plain")) { + if (a == connection->atom(QXcbAtom::UTF8_STRING)) + return QString::fromUtf8(data); + if (a == XCB_ATOM_STRING || + a == connection->atom(QXcbAtom::TEXT)) + return QString::fromLatin1(data); + } + + // special case for uri types + if (format == QLatin1String("text/uri-list")) { + if (atomName == QLatin1String("text/x-moz-url")) { + // we expect this as utf16 <url><space><title> + // the first part is a url that should only contain ascci char + // so it should be safe to check that the second char is 0 + // to verify that it is utf16 + if (data.size() > 1 && data.at(1) == 0) + return QString::fromRawData((const QChar *)data.constData(), + data.size() / 2).split(QLatin1Char('\n')).first().toLatin1(); + } + } + + if (atomName == format) + return data; + +#if 0 // ### + // special case for images + if (format == QLatin1String("image/ppm")) { + if (a == XCB_ATOM_PIXMAP && data.size() == sizeof(Pixmap)) { + Pixmap xpm = *((Pixmap*)data.data()); + if (!xpm) + return QByteArray(); + Window root; + int x; + int y; + uint width; + uint height; + uint border_width; + uint depth; + + XGetGeometry(display, xpm, &root, &x, &y, &width, &height, &border_width, &depth); + XImage *ximg = XGetImage(display,xpm,x,y,width,height,AllPlanes,depth==1 ? XYPixmap : ZPixmap); + QImage qimg = QXlibStatic::qimageFromXImage(ximg); + XDestroyImage(ximg); + + QImageWriter imageWriter; + imageWriter.setFormat("PPMRAW"); + QBuffer buf; + buf.open(QIODevice::WriteOnly); + imageWriter.setDevice(&buf); + imageWriter.write(qimg); + return buf.buffer(); + } + } +#endif + return QVariant(); +} + +xcb_atom_t QXcbMime::mimeAtomForFormat(QXcbConnection *connection, const QString &format, QVariant::Type requestedType, + const QList<xcb_atom_t> &atoms, QByteArray *requestedEncoding) +{ + requestedEncoding->clear(); + + // find matches for string types + if (format == QLatin1String("text/plain")) { + if (atoms.contains(connection->atom(QXcbAtom::UTF8_STRING))) + return connection->atom(QXcbAtom::UTF8_STRING); + if (atoms.contains(XCB_ATOM_STRING)) + return XCB_ATOM_STRING; + if (atoms.contains(connection->atom(QXcbAtom::TEXT))) + return connection->atom(QXcbAtom::TEXT); + } + + // find matches for uri types + if (format == QLatin1String("text/uri-list")) { + xcb_atom_t a = connection->internAtom(format.toLatin1()); + if (a && atoms.contains(a)) + return a; + a = connection->internAtom("text/x-moz-url"); + if (a && atoms.contains(a)) + return a; + } + + // find match for image + if (format == QLatin1String("image/ppm")) { + if (atoms.contains(XCB_ATOM_PIXMAP)) + return XCB_ATOM_PIXMAP; + } + + // for string/text requests try to use a format with a well-defined charset + // first to avoid encoding problems + if (requestedType == QVariant::String + && format.startsWith(QLatin1String("text/")) + && !format.contains(QLatin1String("charset="))) { + + QString formatWithCharset = format; + formatWithCharset.append(QLatin1String(";charset=utf-8")); + + xcb_atom_t a = connection->internAtom(formatWithCharset.toLatin1()); + if (a && atoms.contains(a)) { + *requestedEncoding = "utf-8"; + return a; + } + } + + xcb_atom_t a = connection->internAtom(format.toLatin1()); + if (a && atoms.contains(a)) + return a; + + return 0; +} diff --git a/src/plugins/platforms/xcb/qxcbmime.h b/src/plugins/platforms/xcb/qxcbmime.h new file mode 100644 index 0000000000..4ab38ed803 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbmime.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QXCBMIME_H +#define QXCBMIME_H + +#include <private/qdnd_p.h> + +#include <QtGui/QClipboard> + +#include "qxcbintegration.h" +#include "qxcbconnection.h" + +class QXcbMime : public QInternalMimeData { + Q_OBJECT +public: + QXcbMime(); + ~QXcbMime(); + + static QList<xcb_atom_t> mimeAtomsForFormat(QXcbConnection *connection, const QString &format); + static QString mimeAtomToString(QXcbConnection *connection, xcb_atom_t a); + static bool mimeDataForAtom(QXcbConnection *connection, xcb_atom_t a, QMimeData *mimeData, QByteArray *data, + xcb_atom_t *atomFormat, int *dataFormat); + static QVariant mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a, const QByteArray &data, const QString &format, + QVariant::Type requestedType, const QByteArray &encoding); + static xcb_atom_t mimeAtomForFormat(QXcbConnection *connection, const QString &format, QVariant::Type requestedType, + const QList<xcb_atom_t> &atoms, QByteArray *requestedEncoding); +}; + +#endif // QXCBMIME_H diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 6423f1b798..45823fcc57 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -43,13 +43,15 @@ #include "qxcbscreen.h" -#include <QtGui/private/qapplication_p.h> +#include <private/qguiapplication_p.h> #include <QtCore/QMap> #include <QtCore/QDebug> +#include <QtGui/qguiglcontext_qpa.h> + #if defined(XCB_USE_EGL) -#include "../eglconvenience/qeglplatformcontext.h" +#include "QtPlatformSupport/private/qeglplatformcontext_p.h" #elif defined (XCB_USE_DRI2) #include "qdri2context.h" #endif @@ -71,29 +73,29 @@ public: Q_GLOBAL_STATIC(QXcbResourceMap, qXcbResourceMap) -void *QXcbNativeInterface::nativeResourceForWidget(const QByteArray &resourceString, QWidget *widget) +void *QXcbNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) { QByteArray lowerCaseResource = resourceString.toLower(); ResourceType resource = qXcbResourceMap()->value(lowerCaseResource); void *result = 0; switch(resource) { case Display: - result = displayForWidget(widget); + result = displayForWindow(window); break; case EglDisplay: - result = eglDisplayForWidget(widget); + result = eglDisplayForWindow(window); break; case Connection: - result = connectionForWidget(widget); + result = connectionForWindow(window); break; case Screen: - result = qPlatformScreenForWidget(widget); + result = qPlatformScreenForWindow(window); break; case GraphicsDevice: - result = graphicsDeviceForWidget(widget); + result = graphicsDeviceForWindow(window); break; case EglContext: - result = eglContextForWidget(widget); + result = eglContextForWindow(window); break; default: result = 0; @@ -101,75 +103,71 @@ void *QXcbNativeInterface::nativeResourceForWidget(const QByteArray &resourceStr return result; } -QXcbScreen *QXcbNativeInterface::qPlatformScreenForWidget(QWidget *widget) +QXcbScreen *QXcbNativeInterface::qPlatformScreenForWindow(QWindow *window) { QXcbScreen *screen; - if (widget) { - screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(widget)); + if (window) { + screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWindow(window)); }else { - screen = static_cast<QXcbScreen *>(QApplicationPrivate::platformIntegration()->screens()[0]); + screen = static_cast<QXcbScreen *>(QGuiApplicationPrivate::platformIntegration()->screens()[0]); } return screen; } -void *QXcbNativeInterface::displayForWidget(QWidget *widget) +void *QXcbNativeInterface::displayForWindow(QWindow *window) { #if defined(XCB_USE_XLIB) - QXcbScreen *screen = qPlatformScreenForWidget(widget); + QXcbScreen *screen = qPlatformScreenForWindow(window); return screen->connection()->xlib_display(); #else - Q_UNUSED(widget); + Q_UNUSED(window); return 0; #endif } -void *QXcbNativeInterface::eglDisplayForWidget(QWidget *widget) +void *QXcbNativeInterface::eglDisplayForWindow(QWindow *window) { #if defined(XCB_USE_DRI2) || defined(XCB_USE_EGL) - QXcbScreen *screen = qPlatformScreenForWidget(widget); + QXcbScreen *screen = qPlatformScreenForWindow(window); return screen->connection()->egl_display(); #else - Q_UNUSED(widget) + Q_UNUSED(window) return 0; #endif } -void *QXcbNativeInterface::connectionForWidget(QWidget *widget) +void *QXcbNativeInterface::connectionForWindow(QWindow *window) { - QXcbScreen *screen = qPlatformScreenForWidget(widget); + QXcbScreen *screen = qPlatformScreenForWindow(window); return screen->xcb_connection(); } -void *QXcbNativeInterface::screenForWidget(QWidget *widget) +void *QXcbNativeInterface::screenForWindow(QWindow *window) { - QXcbScreen *screen = qPlatformScreenForWidget(widget); + QXcbScreen *screen = qPlatformScreenForWindow(window); return screen->screen(); } -void *QXcbNativeInterface::graphicsDeviceForWidget(QWidget *widget) +void *QXcbNativeInterface::graphicsDeviceForWindow(QWindow *window) { #if defined(XCB_USE_DRI2) - QXcbScreen *screen = qPlatformScreenForWidget(widget); + QXcbScreen *screen = qPlatformScreenForWindow(window); QByteArray deviceName = screen->connection()->dri2DeviceName(); return deviceName.data(); #else - Q_UNUSED(widget); + Q_UNUSED(window); return 0; #endif } -void * QXcbNativeInterface::eglContextForWidget(QWidget *widget) +void * QXcbNativeInterface::eglContextForWindow(QWindow *window) { - Q_ASSERT(widget); - if (!widget->platformWindow()) { - qDebug() << "QPlatformWindow does not exist for widget" << widget - << "cannot return EGLContext"; - return 0; - } - QPlatformGLContext *platformContext = widget->platformWindow()->glContext(); +#if 0 + Q_ASSERT(window); + QPlatformGLContext *platformContext = window->glContext()->handle(); if (!platformContext) { - qDebug() << "QPlatformWindow" << widget->platformWindow() << "does not have a glContext" + qDebug() << "QWindow" << window << "does not have a glContext" << "cannot return EGLContext"; return 0; } @@ -182,4 +180,7 @@ void * QXcbNativeInterface::eglContextForWidget(QWidget *widget) #else return 0; #endif +#else + return 0; +#endif } diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index 3fb0fa5e2d..10e3f6350c 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -59,17 +59,17 @@ public: EglContext }; - void *nativeResourceForWidget(const QByteArray &resourceString, QWidget *widget); + void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window); - void *displayForWidget(QWidget *widget); - void *eglDisplayForWidget(QWidget *widget); - void *connectionForWidget(QWidget *widget); - void *screenForWidget(QWidget *widget); - void *graphicsDeviceForWidget(QWidget *widget); - void *eglContextForWidget(QWidget *widget); + void *displayForWindow(QWindow *window); + void *eglDisplayForWindow(QWindow *window); + void *connectionForWindow(QWindow *window); + void *screenForWindow(QWindow *window); + void *graphicsDeviceForWindow(QWindow *window); + void *eglContextForWindow(QWindow *window); private: - static QXcbScreen *qPlatformScreenForWidget(QWidget *widget); + static QXcbScreen *qPlatformScreenForWindow(QWindow *window); }; #endif // QXCBNATIVEINTERFACE_H diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 9a4858123b..6c3d1813b0 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -40,6 +40,8 @@ ****************************************************************************/ #include "qxcbscreen.h" +#include "qxcbwindow.h" +#include "qxcbcursor.h" #include <stdio.h> @@ -102,10 +104,103 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int num free(reply); m_syncRequestSupported = m_windowManagerName != QLatin1String("KWin"); + + m_clientLeader = xcb_generate_id(xcb_connection()); + Q_XCB_CALL2(xcb_create_window(xcb_connection(), + XCB_COPY_FROM_PARENT, + m_clientLeader, + m_screen->root, + 0, 0, 1, 1, + 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + m_screen->root_visual, + 0, 0), connection); + + Q_XCB_CALL2(xcb_change_property(xcb_connection(), + XCB_PROP_MODE_REPLACE, + m_clientLeader, + atom(QXcbAtom::WM_CLIENT_LEADER), + XCB_ATOM_WINDOW, + 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); + } + + m_cursor = new QXcbCursor(connection, this); } QXcbScreen::~QXcbScreen() { + delete m_cursor; +} + +QWindow *QXcbScreen::topLevelAt(const QPoint &p) const +{ + xcb_window_t root = m_screen->root; + + int x = p.x(); + int y = p.y(); + + xcb_generic_error_t *error; + + xcb_window_t parent = root; + xcb_window_t child = root; + + do { + xcb_translate_coordinates_cookie_t translate_cookie = + xcb_translate_coordinates(xcb_connection(), parent, child, x, y); + + xcb_translate_coordinates_reply_t *translate_reply = + xcb_translate_coordinates_reply(xcb_connection(), translate_cookie, &error); + + if (!translate_reply) { + if (error) { + connection()->handleXcbError(error); + free(error); + } + return 0; + } + + parent = child; + child = translate_reply->child; + x = translate_reply->dst_x; + y = translate_reply->dst_y; + + free(translate_reply); + + if (!child || child == root) + return 0; + + QPlatformWindow *platformWindow = connection()->platformWindowFromId(child); + if (platformWindow) + return platformWindow->window(); + } while (parent != child); + + return 0; +} + +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 diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index a78ee822f4..5b8492faa5 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -50,6 +50,7 @@ #include "qxcbobject.h" class QXcbConnection; +class QXcbCursor; class QXcbScreen : public QXcbObject, public QPlatformScreen { @@ -57,6 +58,8 @@ public: QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int number); ~QXcbScreen(); + QWindow *topLevelAt(const QPoint &point) const; + QRect geometry() const; int depth() const; QImage::Format format() const; @@ -67,14 +70,21 @@ public: xcb_screen_t *screen() const { return m_screen; } xcb_window_t root() const { return m_screen->root; } + xcb_window_t clientLeader() const { return m_clientLeader; } + 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; + QXcbCursor *m_cursor; }; #endif diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 0a02c7eff5..86a8c75878 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -45,13 +45,17 @@ #include "qxcbconnection.h" #include "qxcbscreen.h" +#include "qxcbdrag.h" +#include "qxcbwmsupport.h" + #ifdef XCB_USE_DRI2 #include "qdri2context.h" #endif #include <xcb/xcb_icccm.h> -#include <private/qapplication_p.h> +#include <private/qguiapplication_p.h> +#include <private/qwindow_p.h> #include <private/qwindowsurface_p.h> #include <QtGui/QWindowSystemInterface> @@ -65,38 +69,69 @@ #if defined(XCB_USE_GLX) #include "qglxintegration.h" -#include "qglxconvenience.h" +#include <QtPlatformSupport/private/qglxconvenience_p.h> #elif defined(XCB_USE_EGL) -#include "../eglconvenience/qeglplatformcontext.h" -#include "../eglconvenience/qeglconvenience.h" -#include "../eglconvenience/qxlibeglintegration.h" +#include <QtPlatformSupport/private/qeglplatformcontext_p.h> +#include <QtPlatformSupport/private/qeglconvenience_p.h> +#include <QtPlatformSupport/private/qxlibeglintegration_p.h> #endif +#define XCOORD_MAX 16383 + +//#ifdef NET_WM_STATE_DEBUG + // Returns true if we should set WM_TRANSIENT_FOR on \a w -static inline bool isTransient(const QWidget *w) +static inline bool isTransient(const QWindow *w) { - return ((w->windowType() == Qt::Dialog - || w->windowType() == Qt::Sheet - || w->windowType() == Qt::Tool - || w->windowType() == Qt::SplashScreen - || w->windowType() == Qt::ToolTip - || w->windowType() == Qt::Drawer - || w->windowType() == Qt::Popup) - && !w->testAttribute(Qt::WA_X11BypassTransientForHint)); + return w->windowType() == Qt::Dialog + || w->windowType() == Qt::Sheet + || w->windowType() == Qt::Tool + || w->windowType() == Qt::SplashScreen + || w->windowType() == Qt::ToolTip + || w->windowType() == Qt::Drawer + || w->windowType() == Qt::Popup; } -QXcbWindow::QXcbWindow(QWidget *tlw) - : QPlatformWindow(tlw) - , m_context(0) +QXcbWindow::QXcbWindow(QWindow *window) + : QPlatformWindow(window) + , m_window(0) + , m_syncCounter(0) + , m_mapped(false) + , m_netWmUserTimeWindow(XCB_NONE) { - m_screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(tlw)); + m_screen = static_cast<QXcbScreen *>(QGuiApplicationPrivate::platformIntegration()->screens().at(0)); setConnection(m_screen->connection()); - const quint32 mask = XCB_CW_BACK_PIXMAP | XCB_CW_EVENT_MASK; + create(); +} + +void QXcbWindow::create() +{ + bool wasCreated = (m_window != 0); + destroy(); + + m_windowState = Qt::WindowNoState; + m_hasReceivedSyncRequest = false; + + Qt::WindowType type = window()->windowType(); + + if (type == Qt::Desktop) { + m_window = m_screen->root(); + m_depth = m_screen->screen()->root_depth; + m_format = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; + connection()->addWindow(m_window, this); + return; + } + + const quint32 mask = XCB_CW_BACK_PIXMAP | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER | XCB_CW_EVENT_MASK; const quint32 values[] = { // XCB_CW_BACK_PIXMAP XCB_NONE, + // XCB_CW_OVERRIDE_REDIRECT + type == Qt::Popup || type == Qt::ToolTip, + // XCB_CW_SAVE_UNDER + type == Qt::Popup || type == Qt::Tool || type == Qt::SplashScreen || type == Qt::ToolTip || type == Qt::Drawer, // XCB_CW_EVENT_MASK XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY @@ -107,20 +142,28 @@ QXcbWindow::QXcbWindow(QWidget *tlw) | XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW + | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_FOCUS_CHANGE }; + QRect rect = window()->geometry(); + + xcb_window_t xcb_parent_id = m_screen->root(); + if (parent()) + xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window(); + #if defined(XCB_USE_GLX) || defined(XCB_USE_EGL) - if (tlw->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL - && QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL) - || tlw->platformWindowFormat().alpha()) + if ((window()->surfaceType() == QWindow::OpenGLSurface + && QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) + || window()->glFormat().hasAlpha()) { #if defined(XCB_USE_GLX) - XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen),m_screen->screenNumber(), tlw->platformWindowFormat()); + XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen),m_screen->screenNumber(), window()->glFormat()); + #elif defined(XCB_USE_EGL) EGLDisplay eglDisplay = connection()->egl_display(); - EGLConfig eglConfig = q_configFromQPlatformWindowFormat(eglDisplay,tlw->platformWindowFormat(),true); + EGLConfig eglConfig = q_configFromGLFormat(eglDisplay, window()->glFormat(), true); VisualID id = QXlibEglIntegration::getCompatibleVisualId(DISPLAY_FROM_XCB(this), eglDisplay, eglConfig); XVisualInfo visualInfoTemplate; @@ -134,17 +177,15 @@ QXcbWindow::QXcbWindow(QWidget *tlw) if (visualInfo) { m_depth = visualInfo->depth; m_format = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; - Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), m_screen->root(), visualInfo->visual, AllocNone); + Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), xcb_parent_id, visualInfo->visual, AllocNone); XSetWindowAttributes a; a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber()); a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber()); a.colormap = cmap; - m_window = XCreateWindow(DISPLAY_FROM_XCB(this), m_screen->root(), tlw->x(), tlw->y(), tlw->width(), tlw->height(), + m_window = XCreateWindow(DISPLAY_FROM_XCB(this), xcb_parent_id, rect.x(), rect.y(), rect.width(), rect.height(), 0, visualInfo->depth, InputOutput, visualInfo->visual, CWBackPixel|CWBorderPixel|CWColormap, &a); - - printf("created GL window: %d\n", m_window); } else { qFatal("no window!"); } @@ -158,20 +199,20 @@ QXcbWindow::QXcbWindow(QWidget *tlw) Q_XCB_CALL(xcb_create_window(xcb_connection(), XCB_COPY_FROM_PARENT, // depth -- same as root m_window, // window id - m_screen->root(), // parent window id - tlw->x(), - tlw->y(), - tlw->width(), - tlw->height(), + xcb_parent_id, // parent window id + rect.x(), + rect.y(), + rect.width(), + rect.height(), 0, // border width XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class m_screen->screen()->root_visual, // visual 0, // value mask 0)); // value list - - printf("created regular window: %d\n", m_window); } + connection()->addWindow(m_window, this); + Q_XCB_CALL(xcb_change_window_attributes(xcb_connection(), m_window, mask, values)); xcb_atom_t properties[4]; @@ -183,7 +224,7 @@ QXcbWindow::QXcbWindow(QWidget *tlw) if (m_screen->syncRequestSupported()) properties[propertyCount++] = atom(QXcbAtom::_NET_WM_SYNC_REQUEST); - if (tlw->windowFlags() & Qt::WindowContextHelpButtonHint) + if (window()->windowFlags() & Qt::WindowContextHelpButtonHint) properties[propertyCount++] = atom(QXcbAtom::_NET_WM_CONTEXT_HELP); Q_XCB_CALL(xcb_change_property(xcb_connection(), @@ -211,29 +252,43 @@ QXcbWindow::QXcbWindow(QWidget *tlw) &m_syncCounter)); } - if (isTransient(tlw) && tlw->parentWidget()) { - // ICCCM 4.1.2.6 - QWidget *p = tlw->parentWidget()->window(); - xcb_window_t parentWindow = p->winId(); - Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, - XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32, - 1, &parentWindow)); - - } - // set the PID to let the WM kill the application if unresponsive long pid = getpid(); Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, atom(QXcbAtom::_NET_WM_PID), XCB_ATOM_CARDINAL, 32, 1, &pid)); + + xcb_wm_hints_t hints; + memset(&hints, 0, sizeof(hints)); + xcb_wm_hints_set_normal(&hints); + + xcb_set_wm_hints(xcb_connection(), m_window, &hints); + + xcb_window_t leader = m_screen->clientLeader(); + Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + atom(QXcbAtom::WM_CLIENT_LEADER), XCB_ATOM_WINDOW, 32, + 1, &leader)); + + if (wasCreated) + setWindowFlags(window()->windowFlags()); + + connection()->drag()->dndEnable(this, true); } QXcbWindow::~QXcbWindow() { - delete m_context; - if (m_screen->syncRequestSupported()) + destroy(); +} + +void QXcbWindow::destroy() +{ + if (m_syncCounter && m_screen->syncRequestSupported()) Q_XCB_CALL(xcb_sync_destroy_counter(xcb_connection(), m_syncCounter)); - Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window)); + if (m_window) { + connection()->removeWindow(m_window); + Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window)); + } + m_mapped = false; } void QXcbWindow::setGeometry(const QRect &rect) @@ -241,40 +296,93 @@ void QXcbWindow::setGeometry(const QRect &rect) QPlatformWindow::setGeometry(rect); const quint32 mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; - const quint32 values[] = { rect.x(), rect.y(), rect.width(), rect.height() }; + const quint32 values[] = { rect.x(), + rect.y(), + qBound(1, rect.width(), XCOORD_MAX), + qBound(1, rect.height(), XCOORD_MAX) }; Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values)); } void QXcbWindow::setVisible(bool visible) { - xcb_wm_hints_t hints; - if (visible) { - if (widget()->isMinimized()) + if (visible) + show(); + else + hide(); +} + +void QXcbWindow::show() +{ + if (window()->isTopLevel()) { + xcb_get_property_cookie_t cookie = xcb_get_wm_hints(xcb_connection(), m_window); + + xcb_generic_error_t *error; + + xcb_wm_hints_t hints; + xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, &error); + + if (error) { + connection()->handleXcbError(error); + free(error); + } + + if (window()->windowState() & Qt::WindowMinimized) xcb_wm_hints_set_iconic(&hints); else xcb_wm_hints_set_normal(&hints); + xcb_set_wm_hints(xcb_connection(), m_window, &hints); - Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window)); - connection()->sync(); - } else { - Q_XCB_CALL(xcb_unmap_window(xcb_connection(), m_window)); - - // send synthetic UnmapNotify event according to icccm 4.1.4 - xcb_unmap_notify_event_t event; - event.response_type = XCB_UNMAP_NOTIFY; - event.sequence = 0; // does this matter? - event.event = m_screen->root(); - event.window = m_window; - event.from_configure = false; - Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_screen->root(), - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event)); - xcb_flush(xcb_connection()); + // update WM_NORMAL_HINTS + propagateSizeHints(); + + // update WM_TRANSIENT_FOR + if (window()->transientParent() && isTransient(window())) { + QXcbWindow *transientXcbParent = static_cast<QXcbWindow *>(window()->transientParent()->handle()); + if (transientXcbParent) { + // ICCCM 4.1.2.6 + xcb_window_t parentWindow = transientXcbParent->xcb_window(); + + // todo: set transient for group (wm_client_leader) if no parent, a la qwidget_x11.cpp + Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32, + 1, &parentWindow)); + } + } + + // update _MOTIF_WM_HINTS + updateMotifWmHintsBeforeMap(); + + // update _NET_WM_STATE + updateNetWmStateBeforeMap(); } + + Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window)); + xcb_flush(xcb_connection()); + + connection()->sync(); +} + +void QXcbWindow::hide() +{ + Q_XCB_CALL(xcb_unmap_window(xcb_connection(), m_window)); + + // send synthetic UnmapNotify event according to icccm 4.1.4 + xcb_unmap_notify_event_t event; + event.response_type = XCB_UNMAP_NOTIFY; + event.event = m_screen->root(); + event.window = m_window; + event.from_configure = false; + Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_screen->root(), + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event)); + + xcb_flush(xcb_connection()); + + m_mapped = false; } -struct QtMWMHints { +struct QtMotifWmHints { quint32 flags, functions, decorations; qint32 input_mode; quint32 status; @@ -307,33 +415,142 @@ enum { MWM_INPUT_FULL_APPLICATION_MODAL = 3L }; +static QtMotifWmHints getMotifWmHints(QXcbConnection *c, xcb_window_t window) +{ + QtMotifWmHints hints; + + xcb_get_property_cookie_t get_cookie = + xcb_get_property(c->xcb_connection(), 0, window, c->atom(QXcbAtom::_MOTIF_WM_HINTS), + c->atom(QXcbAtom::_MOTIF_WM_HINTS), 0, 20); + + xcb_generic_error_t *error; + + xcb_get_property_reply_t *reply = + xcb_get_property_reply(c->xcb_connection(), get_cookie, &error); + + if (reply && reply->format == 32 && reply->type == c->atom(QXcbAtom::_MOTIF_WM_HINTS)) { + hints = *((QtMotifWmHints *)xcb_get_property_value(reply)); + } else if (error) { + c->handleXcbError(error); + free(error); + + hints.flags = 0L; + hints.functions = MWM_FUNC_ALL; + hints.decorations = MWM_DECOR_ALL; + hints.input_mode = 0L; + hints.status = 0L; + } + + free(reply); + + return hints; +} + +static void setMotifWmHints(QXcbConnection *c, xcb_window_t window, const QtMotifWmHints &hints) +{ + if (hints.flags != 0l) { + Q_XCB_CALL2(xcb_change_property(c->xcb_connection(), + XCB_PROP_MODE_REPLACE, + window, + c->atom(QXcbAtom::_MOTIF_WM_HINTS), + c->atom(QXcbAtom::_MOTIF_WM_HINTS), + 32, + 5, + &hints), c); + } else { + Q_XCB_CALL2(xcb_delete_property(c->xcb_connection(), window, c->atom(QXcbAtom::_MOTIF_WM_HINTS)), c); + } +} + +void QXcbWindow::printNetWmState(const QVector<xcb_atom_t> &state) +{ + printf("_NET_WM_STATE (%d): ", state.size()); + for (int i = 0; i < state.size(); ++i) { +#define CHECK_WM_STATE(state_atom) \ + if (state.at(i) == atom(QXcbAtom::state_atom))\ + printf(#state_atom " "); + CHECK_WM_STATE(_NET_WM_STATE_ABOVE) + CHECK_WM_STATE(_NET_WM_STATE_BELOW) + CHECK_WM_STATE(_NET_WM_STATE_FULLSCREEN) + CHECK_WM_STATE(_NET_WM_STATE_MAXIMIZED_HORZ) + CHECK_WM_STATE(_NET_WM_STATE_MAXIMIZED_VERT) + CHECK_WM_STATE(_NET_WM_STATE_MODAL) + CHECK_WM_STATE(_NET_WM_STATE_STAYS_ON_TOP) + CHECK_WM_STATE(_NET_WM_STATE_DEMANDS_ATTENTION) +#undef CHECK_WM_STATE + } + printf("\n"); +} + +QVector<xcb_atom_t> QXcbWindow::getNetWmState() +{ + QVector<xcb_atom_t> result; + + xcb_get_property_cookie_t get_cookie = + xcb_get_property(xcb_connection(), 0, m_window, atom(QXcbAtom::_NET_WM_STATE), + XCB_ATOM_ATOM, 0, 1024); + + xcb_generic_error_t *error; + + xcb_get_property_reply_t *reply = + xcb_get_property_reply(xcb_connection(), get_cookie, &error); + + if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) { + result.resize(reply->length); + + memcpy(result.data(), xcb_get_property_value(reply), reply->length * sizeof(xcb_atom_t)); + +#ifdef NET_WM_STATE_DEBUG + printf("getting net wm state (%x)\n", m_window); + printNetWmState(result); +#endif + + free(reply); + } else if (error) { + connection()->handleXcbError(error); + free(error); + } else { +#ifdef NET_WM_STATE_DEBUG + printf("getting net wm state (%x), empty\n", m_window); +#endif + } + + return result; +} + +void QXcbWindow::setNetWmState(const QVector<xcb_atom_t> &atoms) +{ + if (atoms.isEmpty()) { + Q_XCB_CALL(xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_STATE))); + } else { + Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, + atom(QXcbAtom::_NET_WM_STATE), XCB_ATOM_ATOM, 32, + atoms.count(), atoms.constData())); + } + xcb_flush(xcb_connection()); +} + + Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags) { Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask)); - setNetWmWindowTypes(flags); - if (type == Qt::ToolTip) flags |= Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint; if (type == Qt::Popup) flags |= Qt::X11BypassWindowManagerHint; - bool topLevel = (flags & Qt::Window); - bool popup = (type == Qt::Popup); - bool dialog = (type == Qt::Dialog - || type == Qt::Sheet); - bool desktop = (type == Qt::Desktop); - bool tool = (type == Qt::Tool || type == Qt::SplashScreen - || type == Qt::ToolTip || type == Qt::Drawer); + setNetWmWindowFlags(flags); + setMotifWindowFlags(flags); - Q_UNUSED(topLevel); - Q_UNUSED(dialog); - Q_UNUSED(desktop); - Q_UNUSED(tool); + return flags; +} - bool tooltip = (type == Qt::ToolTip); +void QXcbWindow::setMotifWindowFlags(Qt::WindowFlags flags) +{ + Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask)); - QtMWMHints mwmhints; + QtMotifWmHints mwmhints; mwmhints.flags = 0L; mwmhints.functions = 0L; mwmhints.decorations = 0; @@ -393,30 +610,88 @@ Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags) mwmhints.decorations = 0; } - if (mwmhints.flags != 0l) { - Q_XCB_CALL(xcb_change_property(xcb_connection(), - XCB_PROP_MODE_REPLACE, - m_window, - atom(QXcbAtom::_MOTIF_WM_HINTS), - atom(QXcbAtom::_MOTIF_WM_HINTS), - 32, - 5, - &mwmhints)); - } else { - Q_XCB_CALL(xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_MOTIF_WM_HINTS))); - } + setMotifWmHints(connection(), m_window, mwmhints); +} + +void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two) +{ + xcb_client_message_event_t event; + + event.response_type = XCB_CLIENT_MESSAGE; + event.format = 32; + event.window = m_window; + event.type = atom(QXcbAtom::_NET_WM_STATE); + event.data.data32[0] = set ? 1 : 0; + event.data.data32[1] = one; + event.data.data32[2] = two; + event.data.data32[3] = 0; + event.data.data32[4] = 0; + + Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event)); +} - if (popup || tooltip) { - const quint32 mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER; - const quint32 values[] = { true, true }; +Qt::WindowState QXcbWindow::setWindowState(Qt::WindowState state) +{ + if (state == m_windowState) + return state; - Q_XCB_CALL(xcb_change_window_attributes(xcb_connection(), m_window, mask, values)); + // unset old state + switch (m_windowState) { + case Qt::WindowMinimized: + Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window)); + break; + case Qt::WindowMaximized: + changeNetWmState(false, + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ), + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); + break; + case Qt::WindowFullScreen: + changeNetWmState(false, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); + break; + default: + break; + } + + // set new state + switch (state) { + case Qt::WindowMinimized: + { + xcb_client_message_event_t event; + + event.response_type = XCB_CLIENT_MESSAGE; + event.format = 32; + event.window = m_window; + event.type = atom(QXcbAtom::WM_CHANGE_STATE); + event.data.data32[0] = XCB_WM_STATE_ICONIC; + event.data.data32[1] = 0; + event.data.data32[2] = 0; + event.data.data32[3] = 0; + event.data.data32[4] = 0; + + Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event)); + } + break; + case Qt::WindowMaximized: + changeNetWmState(true, + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ), + atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); + break; + case Qt::WindowFullScreen: + changeNetWmState(true, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); + break; + case Qt::WindowNoState: + break; + default: + break; } - return QPlatformWindow::setWindowFlags(flags); + connection()->sync(); + + m_windowState = state; + return m_windowState; } -void QXcbWindow::setNetWmWindowTypes(Qt::WindowFlags flags) +void QXcbWindow::setNetWmWindowFlags(Qt::WindowFlags flags) { // in order of decreasing priority QVector<uint> windowTypes; @@ -452,6 +727,127 @@ void QXcbWindow::setNetWmWindowTypes(Qt::WindowFlags flags) windowTypes.count(), windowTypes.constData())); } +void QXcbWindow::updateMotifWmHintsBeforeMap() +{ + QtMotifWmHints mwmhints = getMotifWmHints(connection(), m_window); + + if (window()->windowModality() != Qt::NonModal) { + switch (window()->windowModality()) { + case Qt::WindowModal: + mwmhints.input_mode = MWM_INPUT_PRIMARY_APPLICATION_MODAL; + break; + case Qt::ApplicationModal: + default: + mwmhints.input_mode = MWM_INPUT_FULL_APPLICATION_MODAL; + break; + } + mwmhints.flags |= MWM_HINTS_INPUT_MODE; + } else { + mwmhints.input_mode = MWM_INPUT_MODELESS; + mwmhints.flags &= ~MWM_HINTS_INPUT_MODE; + } + + if (window()->minimumSize() == window()->maximumSize()) { + // fixed size, remove the resize handle (since mwm/dtwm + // isn't smart enough to do it itself) + mwmhints.flags |= MWM_HINTS_FUNCTIONS; + if (mwmhints.functions == MWM_FUNC_ALL) { + mwmhints.functions = MWM_FUNC_MOVE; + } else { + mwmhints.functions &= ~MWM_FUNC_RESIZE; + } + + if (mwmhints.decorations == MWM_DECOR_ALL) { + mwmhints.flags |= MWM_HINTS_DECORATIONS; + mwmhints.decorations = (MWM_DECOR_BORDER + | MWM_DECOR_TITLE + | MWM_DECOR_MENU); + } else { + mwmhints.decorations &= ~MWM_DECOR_RESIZEH; + } + } + + if (window()->windowFlags() & Qt::WindowMinimizeButtonHint) { + mwmhints.flags |= MWM_HINTS_DECORATIONS; + mwmhints.decorations |= MWM_DECOR_MINIMIZE; + mwmhints.functions |= MWM_FUNC_MINIMIZE; + } + if (window()->windowFlags() & Qt::WindowMaximizeButtonHint) { + mwmhints.flags |= MWM_HINTS_DECORATIONS; + mwmhints.decorations |= MWM_DECOR_MAXIMIZE; + mwmhints.functions |= MWM_FUNC_MAXIMIZE; + } + if (window()->windowFlags() & Qt::WindowCloseButtonHint) + mwmhints.functions |= MWM_FUNC_CLOSE; + + setMotifWmHints(connection(), m_window, mwmhints); +} + +void QXcbWindow::updateNetWmStateBeforeMap() +{ + QVector<xcb_atom_t> netWmState; + + Qt::WindowFlags flags = window()->windowFlags(); + if (flags & Qt::WindowStaysOnTopHint) { + netWmState.append(atom(QXcbAtom::_NET_WM_STATE_ABOVE)); + netWmState.append(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP)); + } else if (flags & Qt::WindowStaysOnBottomHint) { + netWmState.append(atom(QXcbAtom::_NET_WM_STATE_BELOW)); + } + + if (window()->windowState() & Qt::WindowFullScreen) { + netWmState.append(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); + } + + if (window()->windowState() & Qt::WindowMaximized) { + netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ)); + netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)); + } + + if (window()->windowModality() != Qt::NonModal) { + netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MODAL)); + } + + setNetWmState(netWmState); +} + +void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp) +{ + xcb_window_t wid = m_window; + + const bool isSupportedByWM = connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW)); + if (m_netWmUserTimeWindow || isSupportedByWM) { + if (!m_netWmUserTimeWindow) { + m_netWmUserTimeWindow = xcb_generate_id(xcb_connection()); + Q_XCB_CALL(xcb_create_window(xcb_connection(), + XCB_COPY_FROM_PARENT, // depth -- same as root + m_netWmUserTimeWindow, // window id + m_window, // parent window id + -1, -1, 1, 1, + 0, // border width + XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class + m_screen->screen()->root_visual, // visual + 0, // value mask + 0)); // value list + wid = m_netWmUserTimeWindow; + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW), + XCB_ATOM_WINDOW, 32, 1, &m_netWmUserTimeWindow); + xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_USER_TIME)); + } else if (!isSupportedByWM) { + // WM no longer supports it, then we should remove the + // _NET_WM_USER_TIME_WINDOW atom. + xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW)); + xcb_destroy_window(xcb_connection(), m_netWmUserTimeWindow); + m_netWmUserTimeWindow = XCB_NONE; + } else { + wid = m_netWmUserTimeWindow; + } + } + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, wid, atom(QXcbAtom::_NET_WM_USER_TIME), + XCB_ATOM_CARDINAL, 32, 1, ×tamp); +} + + WId QXcbWindow::winId() const { return m_window; @@ -459,8 +855,13 @@ WId QXcbWindow::winId() const void QXcbWindow::setParent(const QPlatformWindow *parent) { + // re-create for compatibility + create(); + QPoint topLeft = geometry().topLeft(); - Q_XCB_CALL(xcb_reparent_window(xcb_connection(), window(), static_cast<const QXcbWindow *>(parent)->window(), topLeft.x(), topLeft.y())); + + xcb_window_t xcb_parent_id = parent ? static_cast<const QXcbWindow *>(parent)->xcb_window() : m_screen->root(); + Q_XCB_CALL(xcb_reparent_window(xcb_connection(), xcb_window(), xcb_parent_id, topLeft.x(), topLeft.y())); } void QXcbWindow::setWindowTitle(const QString &title) @@ -490,56 +891,92 @@ void QXcbWindow::lower() Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values)); } +void QXcbWindow::propagateSizeHints() +{ + // update WM_NORMAL_HINTS + xcb_size_hints_t hints; + memset(&hints, 0, sizeof(hints)); + + QRect rect = geometry(); + + xcb_size_hints_set_position(&hints, true, rect.x(), rect.y()); + xcb_size_hints_set_size(&hints, true, rect.width(), rect.height()); + + QWindow *win = window(); + + QSize minimumSize = win->minimumSize(); + QSize maximumSize = win->maximumSize(); + QSize baseSize = win->baseSize(); + QSize sizeIncrement = win->sizeIncrement(); + + if (minimumSize.width() > 0 || minimumSize.height() > 0) + xcb_size_hints_set_min_size(&hints, minimumSize.width(), minimumSize.height()); + + if (maximumSize.width() < QWINDOWSIZE_MAX || maximumSize.height() < QWINDOWSIZE_MAX) + xcb_size_hints_set_max_size(&hints, + qMin(XCOORD_MAX, maximumSize.width()), + qMin(XCOORD_MAX, maximumSize.height())); + + if (sizeIncrement.width() > 0 || sizeIncrement.height() > 0) { + xcb_size_hints_set_base_size(&hints, baseSize.width(), baseSize.height()); + xcb_size_hints_set_resize_inc(&hints, sizeIncrement.width(), sizeIncrement.height()); + } + + xcb_set_wm_normal_hints(xcb_connection(), m_window, &hints); +} + void QXcbWindow::requestActivateWindow() { - Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, XCB_TIME_CURRENT_TIME)); + if (m_mapped){ + updateNetWmUserTime(connection()->time()); + Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, connection()->time())); + } connection()->sync(); } -QPlatformGLContext *QXcbWindow::glContext() const +QPlatformGLSurface *QXcbWindow::createGLSurface() const { - if (!QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) { - printf("no opengl\n"); + if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) { + qWarning() << "QXcb::createGLSurface() called without OpenGL support"; return 0; } - if (!m_context) { + + QGuiGLFormat format = window()->glFormat(); + #if defined(XCB_USE_GLX) - QXcbWindow *that = const_cast<QXcbWindow *>(this); - that->m_context = new QGLXContext(m_window, m_screen, widget()->platformWindowFormat()); + return new QGLXSurface(m_window, format); #elif defined(XCB_USE_EGL) - EGLDisplay display = connection()->egl_display(); - EGLConfig config = q_configFromQPlatformWindowFormat(display,widget()->platformWindowFormat(),true); - QVector<EGLint> eglContextAttrs; - eglContextAttrs.append(EGL_CONTEXT_CLIENT_VERSION); - eglContextAttrs.append(2); - eglContextAttrs.append(EGL_NONE); - - EGLSurface eglSurface = eglCreateWindowSurface(display,config,(EGLNativeWindowType)m_window,0); - QXcbWindow *that = const_cast<QXcbWindow *>(this); - that->m_context = new QEGLPlatformContext(display, config, eglContextAttrs.data(), eglSurface, EGL_OPENGL_ES_API); -#elif defined(XCB_USE_DRI2) - QXcbWindow *that = const_cast<QXcbWindow *>(this); - that->m_context = new QDri2Context(that); + EGLDisplay display = connection()->egl_display(); + EGLConfig config = q_configFromGLFormat(display, format, true); + + EGLSurface eglSurface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)m_window, 0); + + return new QEGLSurface(eglSurface, window()->glFormat()); +#else + return 0; #endif - } - return m_context; } void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event) { - QWindowSurface *surface = widget()->windowSurface(); + QWindowSurface *surface = window()->surface(); if (surface) { QRect rect(event->x, event->y, event->width, event->height); - surface->flush(widget(), rect, QPoint()); + QWindowSystemInterface::handleExposeEvent(window(), rect); } } void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *event) { - if (event->format == 32 && event->type == atom(QXcbAtom::WM_PROTOCOLS)) { + if (event->format != 32) + return; + + if (event->type == atom(QXcbAtom::WM_PROTOCOLS)) { if (event->data.data32[0] == atom(QXcbAtom::WM_DELETE_WINDOW)) { - QWindowSystemInterface::handleCloseEvent(widget()); + QWindowSystemInterface::handleCloseEvent(window()); + } else if (event->data.data32[0] == atom(QXcbAtom::WM_TAKE_FOCUS)) { + connection()->setTime(event->data.data32[1]); } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_PING)) { xcb_client_message_event_t reply = *event; @@ -549,13 +986,26 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&reply); xcb_flush(xcb_connection()); } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_SYNC_REQUEST)) { + connection()->setTime(event->data.data32[1]); if (!m_hasReceivedSyncRequest) { m_hasReceivedSyncRequest = true; printf("Window manager supports _NET_WM_SYNC_REQUEST, syncing resizes\n"); } m_syncValue.lo = event->data.data32[2]; m_syncValue.hi = event->data.data32[3]; + } else { + qWarning() << "unhandled WM_PROTOCOLS message:" << connection()->atomName(event->data.data32[0]); } + } else if (event->type == atom(QXcbAtom::XdndEnter)) { + connection()->drag()->handleEnter(window(), event); + } else if (event->type == atom(QXcbAtom::XdndPosition)) { + connection()->drag()->handlePosition(window(), event, false); + } else if (event->type == atom(QXcbAtom::XdndLeave)) { + connection()->drag()->handleLeave(window(), event, false); + } else if (event->type == atom(QXcbAtom::XdndDrop)) { + connection()->drag()->handleDrop(window(), event, false); + } else { + qWarning() << "unhandled client message:" << connection()->atomName(event->type); } } @@ -575,7 +1025,7 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * return; QPlatformWindow::setGeometry(rect); - QWindowSystemInterface::handleGeometryChange(widget(), rect); + QWindowSystemInterface::handleGeometryChange(window(), rect); #if XCB_USE_DRI2 if (m_context) @@ -583,6 +1033,22 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * #endif } +void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event) +{ + if (event->window == m_window) { + m_mapped = true; + QWindowSystemInterface::handleMapEvent(window()); + } +} + +void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event) +{ + if (event->window == m_window) { + m_mapped = false; + QWindowSystemInterface::handleUnmapEvent(window()); + } +} + static Qt::MouseButtons translateMouseButtons(int s) { Qt::MouseButtons ret = 0; @@ -611,6 +1077,8 @@ static Qt::MouseButton translateMouseButton(xcb_button_t s) void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event) { + updateNetWmUserTime(event->time); + QPoint local(event->event_x, event->event_y); QPoint global(event->root_x, event->root_y); @@ -623,7 +1091,7 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event) && (modifiers & Qt::AltModifier)) || (event->detail == 6 || event->detail == 7)); - QWindowSystemInterface::handleWheelEvent(widget(), event->time, + QWindowSystemInterface::handleWheelEvent(window(), event->time, local, global, delta, hor ? Qt::Horizontal : Qt::Vertical); return; } @@ -649,32 +1117,65 @@ void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event) void QXcbWindow::handleMouseEvent(xcb_button_t detail, uint16_t state, xcb_timestamp_t time, const QPoint &local, const QPoint &global) { + connection()->setTime(time); + Qt::MouseButtons buttons = translateMouseButtons(state); Qt::MouseButton button = translateMouseButton(detail); buttons ^= button; // X event uses state *before*, Qt uses state *after* - QWindowSystemInterface::handleMouseEvent(widget(), time, local, global, buttons); + QWindowSystemInterface::handleMouseEvent(window(), time, local, global, buttons); } -void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *) +void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event) { - QWindowSystemInterface::handleEnterEvent(widget()); + connection()->setTime(event->time); + + if ((event->mode != XCB_NOTIFY_MODE_NORMAL && event->mode != XCB_NOTIFY_MODE_UNGRAB) + || event->detail == XCB_NOTIFY_DETAIL_VIRTUAL + || event->detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL) + { + return; + } + + QWindowSystemInterface::handleEnterEvent(window()); } -void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *) +void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event) { - QWindowSystemInterface::handleLeaveEvent(widget()); + connection()->setTime(event->time); + + if ((event->mode != XCB_NOTIFY_MODE_NORMAL && event->mode != XCB_NOTIFY_MODE_UNGRAB) + || event->detail == XCB_NOTIFY_DETAIL_INFERIOR) + { + return; + } + + QWindowSystemInterface::handleLeaveEvent(window()); } void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *) { - QWindowSystemInterface::handleWindowActivated(widget()); + QWindowSystemInterface::handleWindowActivated(window()); +} + +static bool focusInPeeker(xcb_generic_event_t *event) +{ + if (!event) { + // FocusIn event is not in the queue, proceed with FocusOut normally. + QWindowSystemInterface::handleWindowActivated(0); + return true; + } + uint response_type = event->response_type & ~0x80; + return response_type == XCB_FOCUS_IN; } void QXcbWindow::handleFocusOutEvent(const xcb_focus_out_event_t *) { - QWindowSystemInterface::handleWindowActivated(0); + // Do not set the active window to 0 if there is a FocusIn coming. + // There is however no equivalent for XPutBackEvent so register a + // callback for QXcbConnection instead. + connection()->addPeekFunc(focusInPeeker); } void QXcbWindow::updateSyncRequestCounter() @@ -688,3 +1189,46 @@ void QXcbWindow::updateSyncRequestCounter() m_syncValue.hi = 0; } } + +bool QXcbWindow::setKeyboardGrabEnabled(bool grab) +{ + if (!grab) { + xcb_ungrab_keyboard(xcb_connection(), XCB_TIME_CURRENT_TIME); + return true; + } + xcb_grab_keyboard_cookie_t cookie = xcb_grab_keyboard(xcb_connection(), false, + m_window, XCB_TIME_CURRENT_TIME, + GrabModeAsync, GrabModeAsync); + xcb_generic_error_t *err; + xcb_grab_keyboard_reply_t *reply = xcb_grab_keyboard_reply(xcb_connection(), cookie, &err); + bool result = !(err || !reply || reply->status != XCB_GRAB_STATUS_SUCCESS); + free(reply); + free(err); + return result; +} + +bool QXcbWindow::setMouseGrabEnabled(bool grab) +{ + if (!grab) { + xcb_ungrab_pointer(xcb_connection(), XCB_TIME_CURRENT_TIME); + return true; + } + xcb_grab_pointer_cookie_t cookie = xcb_grab_pointer(xcb_connection(), false, m_window, + (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask + | EnterWindowMask | LeaveWindowMask | PointerMotionMask), + GrabModeAsync, GrabModeAsync, + XCB_WINDOW_NONE, XCB_CURSOR_NONE, + XCB_TIME_CURRENT_TIME); + xcb_generic_error_t *err; + xcb_grab_pointer_reply_t *reply = xcb_grab_pointer_reply(xcb_connection(), cookie, &err); + bool result = !(err || !reply || reply->status != XCB_GRAB_STATUS_SUCCESS); + free(reply); + free(err); + return result; +} + +void QXcbWindow::setCursor(xcb_cursor_t cursor) +{ + xcb_change_window_attributes(xcb_connection(), m_window, XCB_CW_CURSOR, &cursor); + xcb_flush(xcb_connection()); +} diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 69d0bc2f1d..f50a611b4e 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -43,7 +43,7 @@ #define QXCBWINDOW_H #include <QtGui/QPlatformWindow> -#include <QtGui/QPlatformWindowFormat> +#include <QtGui/QGuiGLFormat> #include <QtGui/QImage> #include <xcb/xcb.h> @@ -56,31 +56,40 @@ class QXcbScreen; class QXcbWindow : public QXcbObject, public QPlatformWindow { public: - QXcbWindow(QWidget *tlw); + QXcbWindow(QWindow *window); ~QXcbWindow(); void setGeometry(const QRect &rect); void setVisible(bool visible); Qt::WindowFlags setWindowFlags(Qt::WindowFlags flags); + Qt::WindowState setWindowState(Qt::WindowState state); WId winId() const; void setParent(const QPlatformWindow *window); void setWindowTitle(const QString &title); void raise(); void lower(); + void propagateSizeHints(); + + QPlatformGLSurface *createGLSurface() const; void requestActivateWindow(); - QPlatformGLContext *glContext() const; + bool setKeyboardGrabEnabled(bool grab); + bool setMouseGrabEnabled(bool grab); + + void setCursor(xcb_cursor_t cursor); - xcb_window_t window() const { return m_window; } + xcb_window_t xcb_window() const { return m_window; } uint depth() const { return m_depth; } QImage::Format format() const { return m_format; } void handleExposeEvent(const xcb_expose_event_t *event); void handleClientMessageEvent(const xcb_client_message_event_t *event); void handleConfigureNotifyEvent(const xcb_configure_notify_event_t *event); + void handleMapNotifyEvent(const xcb_map_notify_event_t *event); + void handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event); void handleButtonPressEvent(const xcb_button_press_event_t *event); void handleButtonReleaseEvent(const xcb_button_release_event_t *event); void handleMotionNotifyEvent(const xcb_motion_notify_event_t *event); @@ -93,14 +102,31 @@ public: void handleMouseEvent(xcb_button_t detail, uint16_t state, xcb_timestamp_t time, const QPoint &local, const QPoint &global); void updateSyncRequestCounter(); + void updateNetWmUserTime(xcb_timestamp_t timestamp); + void netWmUserTime() const; private: - void setNetWmWindowTypes(Qt::WindowFlags flags); + void changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two = 0); + QVector<xcb_atom_t> getNetWmState(); + void setNetWmState(const QVector<xcb_atom_t> &atoms); + void printNetWmState(const QVector<xcb_atom_t> &state); + + void setNetWmWindowFlags(Qt::WindowFlags flags); + void setMotifWindowFlags(Qt::WindowFlags flags); + + void updateMotifWmHintsBeforeMap(); + void updateNetWmStateBeforeMap(); + + + void create(); + void destroy(); + + void show(); + void hide(); QXcbScreen *m_screen; xcb_window_t m_window; - QPlatformGLContext *m_context; uint m_depth; QImage::Format m_format; @@ -109,6 +135,10 @@ private: xcb_sync_counter_t m_syncCounter; bool m_hasReceivedSyncRequest; + Qt::WindowState m_windowState; + + bool m_mapped; + xcb_window_t m_netWmUserTimeWindow; }; #endif diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp index 4fcd207df3..63378515cc 100644 --- a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp +++ b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp @@ -52,6 +52,7 @@ #include <sys/shm.h> #include <stdio.h> +#include <errno.h> #include <qdebug.h> #include <qpainter.h> @@ -97,9 +98,16 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QI ~0, 0); - m_shm_info.shmid = shmget (IPC_PRIVATE, - m_xcb_image->stride * m_xcb_image->height, IPC_CREAT|0777); + const int segmentSize = m_xcb_image->stride * m_xcb_image->height; + if (!segmentSize) + return; + int id = shmget(IPC_PRIVATE, segmentSize, IPC_CREAT | 0777); + if (id == -1) + qWarning("QXcbShmImage: shmget() failed (%d) for size %d (%dx%d)", + errno, segmentSize, size.width(), size.height()); + else + m_shm_info.shmid = id; m_shm_info.shmaddr = m_xcb_image->data = (quint8 *)shmat (m_shm_info.shmid, 0, 0); m_shm_info.shmseg = xcb_generate_id(xcb_connection()); @@ -117,10 +125,17 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QI void QXcbShmImage::destroy() { - Q_XCB_CALL(xcb_shm_detach(xcb_connection(), m_shm_info.shmseg)); + const int segmentSize = m_xcb_image ? (m_xcb_image->stride * m_xcb_image->height) : 0; + if (segmentSize) + Q_XCB_CALL(xcb_shm_detach(xcb_connection(), m_shm_info.shmseg)); + xcb_image_destroy(m_xcb_image); - shmdt(m_shm_info.shmaddr); - shmctl(m_shm_info.shmid, IPC_RMID, 0); + + if (segmentSize) { + shmdt(m_shm_info.shmaddr); + shmctl(m_shm_info.shmid, IPC_RMID, 0); + } + if (m_gc) Q_XCB_CALL(xcb_free_gc(xcb_connection(), m_gc)); } @@ -168,12 +183,12 @@ void QXcbShmImage::preparePaint(const QRegion ®ion) } } -QXcbWindowSurface::QXcbWindowSurface(QWidget *widget, bool setDefaultSurface) - : QWindowSurface(widget, setDefaultSurface) +QXcbWindowSurface::QXcbWindowSurface(QWindow *window, bool setDefaultSurface) + : QWindowSurface(window, setDefaultSurface) , m_image(0) , m_syncingResize(false) { - QXcbScreen *screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(widget)); + QXcbScreen *screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWindow(window)); setConnection(screen->connection()); } @@ -206,7 +221,7 @@ void QXcbWindowSurface::endPaint(const QRegion &) { } -void QXcbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +void QXcbWindowSurface::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) { QRect bounds = region.boundingRect(); @@ -215,14 +230,11 @@ void QXcbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoi Q_XCB_NOOP(connection()); - QXcbWindow *window = static_cast<QXcbWindow *>(widget->window()->platformWindow()); - - extern QWidgetData* qt_widget_data(QWidget *); - QPoint widgetOffset = qt_qwidget_data(widget)->wrect.topLeft(); + QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window->handle()); QVector<QRect> rects = region.rects(); for (int i = 0; i < rects.size(); ++i) - m_image->put(window->window(), rects.at(i).topLeft() - widgetOffset, rects.at(i).translated(offset)); + m_image->put(platformWindow->xcb_window(), rects.at(i).topLeft(), rects.at(i).translated(offset)); Q_XCB_NOOP(connection()); @@ -230,7 +242,7 @@ void QXcbWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoi xcb_flush(xcb_connection()); connection()->sync(); m_syncingResize = false; - window->updateSyncRequestCounter(); + platformWindow->updateSyncRequestCounter(); } } @@ -242,8 +254,8 @@ void QXcbWindowSurface::resize(const QSize &size) Q_XCB_NOOP(connection()); QWindowSurface::resize(size); - QXcbScreen *screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(window())); - QXcbWindow* win = static_cast<QXcbWindow *>(window()->platformWindow()); + QXcbScreen *screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWindow(window())); + QXcbWindow* win = static_cast<QXcbWindow *>(window()->handle()); delete m_image; m_image = new QXcbShmImage(screen, size, win->depth(), win->format()); @@ -256,7 +268,7 @@ extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &o bool QXcbWindowSurface::scroll(const QRegion &area, int dx, int dy) { - if (m_image->image()->isNull()) + if (!m_image || m_image->image()->isNull()) return false; m_image->preparePaint(area); diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.h b/src/plugins/platforms/xcb/qxcbwindowsurface.h index 5f61815b65..8f401d94a3 100644 --- a/src/plugins/platforms/xcb/qxcbwindowsurface.h +++ b/src/plugins/platforms/xcb/qxcbwindowsurface.h @@ -53,11 +53,11 @@ class QXcbShmImage; class QXcbWindowSurface : public QXcbObject, public QWindowSurface { public: - QXcbWindowSurface(QWidget *widget, bool setDefaultSurface = true); + QXcbWindowSurface(QWindow *widget, bool setDefaultSurface = true); ~QXcbWindowSurface(); QPaintDevice *paintDevice(); - void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset); void resize(const QSize &size); bool scroll(const QRegion &area, int dx, int dy); diff --git a/src/plugins/platforms/xcb/qxcbwmsupport.cpp b/src/plugins/platforms/xcb/qxcbwmsupport.cpp new file mode 100644 index 0000000000..5fb67b6377 --- /dev/null +++ b/src/plugins/platforms/xcb/qxcbwmsupport.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qxcbwmsupport.h" +#include "qxcbscreen.h" + +#include <qdebug.h> + +QXcbWMSupport::QXcbWMSupport(QXcbConnection *c) + : QXcbObject(c) +{ + updateNetWMAtoms(); + updateVirtualRoots(); +} + +bool QXcbWMSupport::isSupportedByWM(xcb_atom_t atom) const +{ + return net_wm_atoms.contains(atom); +} + + + +void QXcbWMSupport::updateNetWMAtoms() +{ + net_wm_atoms.clear(); + + xcb_window_t root = connection()->screens().at(connection()->primaryScreen())->root(); + int offset = 0; + int remaining = 0; + do { + xcb_generic_error_t *error = 0; + xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, root, atom(QXcbAtom::_NET_SUPPORTED), XCB_ATOM_ATOM, offset, 1024); + xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, &error); + if (!reply || error) + break; + + remaining = 0; + + if (reply->type == XCB_ATOM_ATOM && reply->format == 32) { + int len = xcb_get_property_value_length(reply)/4; + xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply); + int s = net_wm_atoms.size(); + net_wm_atoms.resize(s + len); + memcpy(net_wm_atoms.data() + s, atoms, len*sizeof(xcb_atom_t)); + + remaining = reply->bytes_after; + offset += len; + } + + free(reply); + } while (remaining > 0); + +// qDebug() << "======== updateNetWMAtoms"; +// for (int i = 0; i < net_wm_atoms.size(); ++i) +// qDebug() << atomName(net_wm_atoms.at(i)); +// qDebug() << "======== updateNetWMAtoms"; +} + +// update the virtual roots array +void QXcbWMSupport::updateVirtualRoots() +{ + net_virtual_roots.clear(); + + if (!isSupportedByWM(atom(QXcbAtom::_NET_VIRTUAL_ROOTS))) + return; + + xcb_window_t root = connection()->screens().at(connection()->primaryScreen())->root(); + int offset = 0; + int remaining = 0; + do { + xcb_generic_error_t *error = 0; + xcb_get_property_cookie_t cookie = xcb_get_property(xcb_connection(), false, root, atom(QXcbAtom::_NET_VIRTUAL_ROOTS), XCB_ATOM_ATOM, offset, 1024); + xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, &error); + if (!reply || error) + break; + + remaining = 0; + + if (reply->type == XCB_ATOM_ATOM && reply->format == 32) { + int len = xcb_get_property_value_length(reply)/4; + xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply); + int s = net_wm_atoms.size(); + net_wm_atoms.resize(s + len); + memcpy(net_wm_atoms.data() + s, atoms, len*sizeof(xcb_atom_t)); + + remaining = reply->bytes_after; + offset += len; + } + + free(reply); + } while (remaining > 0); + + qDebug() << "======== updateVirtualRoots"; + for (int i = 0; i < net_virtual_roots.size(); ++i) + qDebug() << connection()->atomName(net_virtual_roots.at(i)); + qDebug() << "======== updateVirtualRoots"; +} + diff --git a/src/plugins/platforms/cocoa/qcocoaeventloopintegration.h b/src/plugins/platforms/xcb/qxcbwmsupport.h index 5765483fc7..3b02ef3e7e 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventloopintegration.h +++ b/src/plugins/platforms/xcb/qxcbwmsupport.h @@ -38,28 +38,30 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#ifndef QXCBWMSUPPORT_H +#define QXCBWMSUPPORT_H -#ifndef QCOCAEVENTLOOPINTEGRATION_H -#define QCOCAEVENTLOOPINTEGRATION_H +#include "qxcbobject.h" +#include "qxcbconnection.h" +#include <qvector.h> -#include <Cocoa/Cocoa.h> - -#include <QPlatformEventLoopIntegration> - - -class QCocoaEventLoopIntegration : public QPlatformEventLoopIntegration +class QXcbWMSupport : public QXcbObject { public: - QCocoaEventLoopIntegration(); - void startEventLoop(); - void quitEventLoop(); - void qtNeedsToProcessEvents(); + QXcbWMSupport(QXcbConnection *c); + + + bool isSupportedByWM(xcb_atom_t atom) const; + const QVector<xcb_window_t> &virtualRoots() const { return net_virtual_roots; } private: - CFRunLoopSourceContext m_sourceContext; - CFRunLoopTimerContext m_timerContext; - CFRunLoopSourceRef m_source; + friend class QXcbConnection; + void updateNetWMAtoms(); + void updateVirtualRoots(); + + QVector<xcb_atom_t> net_wm_atoms; + QVector<xcb_window_t> net_virtual_roots; }; -#endif // QCOCAEVENTLOOPINTEGRATION_H +#endif diff --git a/src/plugins/platforms/xcb/xcb.pro b/src/plugins/platforms/xcb/xcb.pro index 27d10b6756..c8814b04f6 100644 --- a/src/plugins/platforms/xcb/xcb.pro +++ b/src/plugins/platforms/xcb/xcb.pro @@ -3,34 +3,54 @@ TARGET = xcb load(qt_plugin) QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms -QT += core-private gui-private +QT += core-private gui-private platformsupport-private SOURCES = \ + qxcbclipboard.cpp \ qxcbconnection.cpp \ qxcbintegration.cpp \ qxcbkeyboard.cpp \ + qxcbmime.cpp \ + qxcbdrag.cpp \ qxcbscreen.cpp \ qxcbwindow.cpp \ qxcbwindowsurface.cpp \ + qxcbwmsupport.cpp \ main.cpp \ - qxcbnativeinterface.cpp + qxcbnativeinterface.cpp \ + qxcbcursor.cpp \ + qxcbimage.cpp HEADERS = \ + qxcbclipboard.h \ qxcbconnection.h \ qxcbintegration.h \ qxcbkeyboard.h \ + qxcbdrag.h \ + qxcbmime.h \ qxcbobject.h \ qxcbscreen.h \ qxcbwindow.h \ qxcbwindowsurface.h \ - qxcbnativeinterface.h + qxcbwmsupport.h \ + qxcbnativeinterface.h \ + qxcbcursor.h \ + qxcbimage.h + +QT += gui-private core-private + +# needed by GLX, Xcursor, XLookupString, ... +DEFINES += XCB_USE_XLIB + +# to support custom cursors with depth > 1 +DEFINES += XCB_USE_RENDER contains(QT_CONFIG, opengl) { QT += opengl # DEFINES += XCB_USE_DRI2 contains(DEFINES, XCB_USE_DRI2) { - LIBS += -lxcb-dri2 -lxcb-xfixes -lEGL + LIBS += -lxcb-dri2 -lEGL CONFIG += link_pkgconfig PKGCONFIG += libdrm @@ -39,34 +59,26 @@ contains(QT_CONFIG, opengl) { SOURCES += qdri2context.cpp } else { - DEFINES += XCB_USE_XLIB - LIBS += -lX11 -lX11-xcb - contains(QT_CONFIG, opengles2) { DEFINES += XCB_USE_EGL - HEADERS += \ - ../eglconvenience/qeglplatformcontext.h \ - ../eglconvenience/qeglconvenience.h \ - ../eglconvenience/qxlibeglintegration.h - - SOURCES += \ - ../eglconvenience/qeglplatformcontext.cpp \ - ../eglconvenience/qeglconvenience.cpp \ - ../eglconvenience/qxlibeglintegration.cpp - LIBS += -lEGL } else { DEFINES += XCB_USE_GLX - include (../glxconvenience/glxconvenience.pri) HEADERS += qglxintegration.h SOURCES += qglxintegration.cpp } } } -LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync +LIBS += -lxcb -lxcb-image -lxcb-keysyms -lxcb-icccm -lxcb-sync -lxcb-xfixes +contains(DEFINES, XCB_USE_XLIB): LIBS += -lX11 -lX11-xcb +contains(DEFINES, XCB_USE_RENDER): LIBS += -lxcb-render -lxcb-render-util + +DEFINES += $$QMAKE_DEFINES_XCB +LIBS += $$QMAKE_LIBS_XCB +QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_XCB -include (../fontdatabases/genericunix/genericunix.pri) +CONFIG += qpa/genericunixfontdatabase target.path += $$[QT_INSTALL_PLUGINS]/platforms INSTALLS += target diff --git a/src/plugins/platforms/xlib/xlib.pro b/src/plugins/platforms/xlib/xlib.pro index 2cba5513d5..b6d0e0bf27 100644 --- a/src/plugins/platforms/xlib/xlib.pro +++ b/src/plugins/platforms/xlib/xlib.pro @@ -1,6 +1,6 @@ TARGET = qxlib -load(qt_plugin) +load(qpa/plugin) DESTDIR = $$QT.gui.plugins/platforms QT += core-private gui-private opengl-private @@ -43,19 +43,13 @@ include (../fontdatabases/genericunix/genericunix.pri) contains(QT_CONFIG, opengl) { QT += opengl !contains(QT_CONFIG, opengles2) { - include (../glxconvenience/glxconvenience.pri) + load(qpa/glx/convenience) HEADERS += qglxintegration.h SOURCES += qglxintegration.cpp } else { # There is no easy way to detect if we'r suppose to use glx or not - HEADERS += \ - ../eglconvenience/qeglplatformcontext.h \ - ../eglconvenience/qeglconvenience.h \ - ../eglconvenience/qxlibeglintegration.h - - SOURCES += \ - ../eglconvenience/qeglplatformcontext.cpp \ - ../eglconvenience/qeglconvenience.cpp \ - ../eglconvenience/qxlibeglintegration.cpp + load(qpa/egl/context) + load(qpa/egl/convenience) + load(qpa/egl/xlibintegration) LIBS += -lEGL } } |