diff options
author | Liang Qi <liang.qi@theqtcompany.com> | 2015-09-25 14:02:04 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@theqtcompany.com> | 2015-09-25 14:02:04 +0200 |
commit | a1ad9a74ebb3c556c5f70f7e03be68b09598ac53 (patch) | |
tree | 615a96db418219a57a745a5899e39a9ac90744ec /src/plugins | |
parent | 6d78b7a0c46ea04f4bb771d960e2f7dff1362341 (diff) | |
parent | 462f355e4fb16cc7a1838fa2dda0f763eee58c84 (diff) |
Merge remote-tracking branch 'origin/5.6' into dev
Conflicts:
src/corelib/io/io.pri
src/corelib/io/qdatastream.cpp
src/corelib/io/qdatastream.h
src/network/socket/qabstractsocket.cpp
src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
src/widgets/styles/qgtkstyle.cpp
tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-cache/qmimedatabase-cache.pro
tests/auto/corelib/mimetypes/qmimedatabase/qmimedatabase-xml/qmimedatabase-xml.pro
tests/auto/dbus/qdbusconnection/qdbusconnection.pro
tests/auto/dbus/qdbuspendingcall/tst_qdbuspendingcall.cpp
tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
Change-Id: I347549a024eb5bfa986699e0a11f96cc55c797a7
Diffstat (limited to 'src/plugins')
76 files changed, 1252 insertions, 2521 deletions
diff --git a/src/plugins/imageformats/ico/qicohandler.cpp b/src/plugins/imageformats/ico/qicohandler.cpp index 2ddbc4519b..19525397fa 100644 --- a/src/plugins/imageformats/ico/qicohandler.cpp +++ b/src/plugins/imageformats/ico/qicohandler.cpp @@ -100,9 +100,10 @@ public: static bool write(QIODevice *device, const QVector<QImage> &images); + bool readIconEntry(int index, ICONDIRENTRY * iconEntry); + private: bool readHeader(); - bool readIconEntry(int index, ICONDIRENTRY * iconEntry); bool readBMPHeader(quint32 imageOffset, BMP_INFOHDR * header); void findColorInfo(QImage & image); @@ -341,7 +342,7 @@ bool ICOReader::readHeader() bool ICOReader::readIconEntry(int index, ICONDIRENTRY *iconEntry) { - if (iod) { + if (readHeader()) { if (iod->seek(startpos + ICONDIR_SIZE + (index * ICONDIRENTRY_SIZE))) { return readIconDirEntry(iod, iconEntry); } @@ -558,10 +559,10 @@ QImage ICOReader::iconAt(int index) if (icoAttrib.ncolors > 256) //color table can't be more than 256 return img; icoAttrib.w = iconEntry.bWidth; - if (icoAttrib.w == 0) + if (icoAttrib.w == 0) // means 256 pixels icoAttrib.w = header.biWidth; icoAttrib.h = iconEntry.bHeight; - if (icoAttrib.h == 0) + if (icoAttrib.h == 0) // means 256 pixels icoAttrib.h = header.biHeight/2; QImage::Format format = QImage::Format_ARGB32; @@ -658,10 +659,11 @@ bool ICOReader::write(QIODevice *device, const QVector<QImage> &images) for (int i=0; i<id.idCount; i++) { QImage image = images[i]; - // Scale down the image if it is larger than 128 pixels in either width or height - if (image.width() > 128 || image.height() > 128) + // Scale down the image if it is larger than 256 pixels in either width or height + // because this is a maximum size of image in the ICO file. + if (image.width() > 256 || image.height() > 256) { - image = image.scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation); + image = image.scaled(256, 256, Qt::KeepAspectRatio, Qt::SmoothTransformation); } QImage maskImage(image.width(), image.height(), QImage::Format_Mono); image = image.convertToFormat(QImage::Format_ARGB32); @@ -778,25 +780,37 @@ QtIcoHandler::~QtIcoHandler() QVariant QtIcoHandler::option(ImageOption option) const { - if (option == Size) { - QIODevice *device = QImageIOHandler::device(); - qint64 oldPos = device->pos(); + if (option == Size || option == ImageFormat) { ICONDIRENTRY iconEntry; - if (device->seek(oldPos + ICONDIR_SIZE + (m_currentIconIndex * ICONDIRENTRY_SIZE))) { - if (readIconDirEntry(device, &iconEntry)) { - device->seek(oldPos); - return QSize(iconEntry.bWidth, iconEntry.bHeight); + if (m_pICOReader->readIconEntry(m_currentIconIndex, &iconEntry)) { + switch (option) { + case Size: + return QSize(iconEntry.bWidth ? iconEntry.bWidth : 256, + iconEntry.bHeight ? iconEntry.bHeight : 256); + + case ImageFormat: + switch (iconEntry.wBitCount) { + case 2: + return QImage::Format_Mono; + case 24: + return QImage::Format_RGB32; + case 32: + return QImage::Format_ARGB32; + default: + return QImage::Format_Indexed8; + } + break; + default: + break; } } - if (!device->isSequential()) - device->seek(oldPos); } return QVariant(); } bool QtIcoHandler::supportsOption(ImageOption option) const { - return option == Size; + return (option == Size || option == ImageFormat); } /*! @@ -881,9 +895,10 @@ bool QtIcoHandler::jumpToImage(int imageNumber) { if (imageNumber < imageCount()) { m_currentIconIndex = imageNumber; + return true; } - return imageNumber < imageCount(); + return false; } /*! \reimp diff --git a/src/plugins/platforminputcontexts/compose/compose.json b/src/plugins/platforminputcontexts/compose/compose.json index 2daf89ed30..fb95f1bfb0 100644 --- a/src/plugins/platforminputcontexts/compose/compose.json +++ b/src/plugins/platforminputcontexts/compose/compose.json @@ -1,3 +1,3 @@ { - "Keys": [ "compose" ] + "Keys": [ "compose", "xim" ] } diff --git a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp index 96f6424ba2..15c98ed006 100644 --- a/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp +++ b/src/plugins/platforminputcontexts/compose/qcomposeplatforminputcontextmain.cpp @@ -52,7 +52,8 @@ QComposeInputContext *QComposePlatformInputContextPlugin::create(const QString & { Q_UNUSED(paramList); - if (system.compare(system, QLatin1String("compose"), Qt::CaseInsensitive) == 0) + if (system.compare(system, QLatin1String("compose"), Qt::CaseInsensitive) == 0 + || system.compare(system, QLatin1String("xim"), Qt::CaseInsensitive) == 0) return new QComposeInputContext; return 0; } diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp index 2027e010d0..9a41244c63 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp @@ -301,12 +301,12 @@ bool QIBusPlatformInputContext::filterEvent(const QEvent *event) quint32 sym = keyEvent->nativeVirtualKey(); quint32 code = keyEvent->nativeScanCode(); quint32 state = keyEvent->nativeModifiers(); + quint32 ibusState = state; if (keyEvent->type() != QEvent::KeyPress) - state |= IBUS_RELEASE_MASK; + ibusState |= IBUS_RELEASE_MASK; - code -= 8; // ### - QDBusPendingReply<bool> reply = d->context->ProcessKeyEvent(sym, code, state); + QDBusPendingReply<bool> reply = d->context->ProcessKeyEvent(sym, code - 8, ibusState); if (m_eventFilterUseSynchronousMode || reply.isFinished()) { bool retval = reply.value(); @@ -315,17 +315,36 @@ bool QIBusPlatformInputContext::filterEvent(const QEvent *event) } Qt::KeyboardModifiers modifiers = keyEvent->modifiers(); + const int qtcode = keyEvent->key(); + + // From QKeyEvent::modifiers() + switch (qtcode) { + case Qt::Key_Shift: + modifiers ^= Qt::ShiftModifier; + break; + case Qt::Key_Control: + modifiers ^= Qt::ControlModifier; + break; + case Qt::Key_Alt: + modifiers ^= Qt::AltModifier; + break; + case Qt::Key_Meta: + modifiers ^= Qt::MetaModifier; + break; + case Qt::Key_AltGr: + modifiers ^= Qt::GroupSwitchModifier; + break; + } QVariantList args; args << QVariant::fromValue(keyEvent->timestamp()); args << QVariant::fromValue(static_cast<uint>(keyEvent->type())); - args << QVariant::fromValue(keyEvent->key()); + args << QVariant::fromValue(qtcode); args << QVariant::fromValue(code) << QVariant::fromValue(sym) << QVariant::fromValue(state); args << QVariant::fromValue(keyEvent->text()); args << QVariant::fromValue(keyEvent->isAutoRepeat()); - args << QVariant::fromValue(keyEvent->count()); - QIBusFilterEventWatcher *watcher = new QIBusFilterEventWatcher(reply, this, qApp->focusObject(), modifiers, args); + QIBusFilterEventWatcher *watcher = new QIBusFilterEventWatcher(reply, this, QGuiApplication::focusWindow(), modifiers, args); QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, &QIBusPlatformInputContext::filterEventFinished); return true; @@ -343,9 +362,9 @@ void QIBusPlatformInputContext::filterEventFinished(QDBusPendingCallWatcher *cal // Use watcher's window instead of the current focused window // since there is a time lag until filterEventFinished() returns. - QObject *input = watcher->input(); + QWindow *window = watcher->window(); - if (!input) { + if (!window) { call->deleteLater(); return; } @@ -360,14 +379,12 @@ void QIBusPlatformInputContext::filterEventFinished(QDBusPendingCallWatcher *cal const quint32 state = args.at(5).toUInt(); const QString string = args.at(6).toString(); const bool isAutoRepeat = args.at(7).toBool(); - const int count = args.at(8).toInt(); // copied from QXcbKeyboard::handleKeyEvent() bool retval = reply.value(); qCDebug(qtQpaInputMethods) << "filterEventFinished return" << code << sym << state << retval; if (!retval) { #ifndef QT_NO_CONTEXTMENU - QWindow *window = dynamic_cast<QWindow *>(input); if (type == QEvent::KeyPress && qtcode == Qt::Key_Menu && window != NULL) { const QPoint globalPos = window->screen()->handle()->cursor()->pos(); @@ -376,10 +393,9 @@ void QIBusPlatformInputContext::filterEventFinished(QDBusPendingCallWatcher *cal globalPos, modifiers); } #endif // QT_NO_CONTEXTMENU - QKeyEvent event(type, qtcode, modifiers, code, sym, - state, string, isAutoRepeat, count); - event.setTimestamp(time); - QCoreApplication::sendEvent(input, &event); + QWindowSystemInterface::handleExtendedKeyEvent(window, time, type, qtcode, modifiers, + code, sym, state, string, isAutoRepeat); + } call->deleteLater(); } diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h index 91f15ea159..127db7df8b 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h @@ -38,6 +38,7 @@ #include <QtCore/qpointer.h> #include <QtDBus/qdbuspendingreply.h> #include <QLoggingCategory> +#include <QWindow> QT_BEGIN_NAMESPACE @@ -51,23 +52,23 @@ class QIBusFilterEventWatcher: public QDBusPendingCallWatcher public: explicit QIBusFilterEventWatcher(const QDBusPendingCall &call, QObject *parent = 0, - QObject *input = 0, + QWindow *window = 0, const Qt::KeyboardModifiers modifiers = 0, const QVariantList arguments = QVariantList()) : QDBusPendingCallWatcher(call, parent) - , m_input(input) + , m_window(window) , m_modifiers(modifiers) , m_arguments(arguments) {} ~QIBusFilterEventWatcher() {} - inline QObject *input() const { return m_input; } + inline QWindow *window() const { return m_window; } inline const Qt::KeyboardModifiers modifiers() const { return m_modifiers; } inline const QVariantList arguments() const { return m_arguments; } private: - QPointer<QObject> m_input; + QPointer<QWindow> m_window; const Qt::KeyboardModifiers m_modifiers; const QVariantList m_arguments; }; diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.h b/src/plugins/platforms/cocoa/qcocoaaccessibility.h index 18ea884091..2d1aa41a9a 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.h +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.h @@ -38,6 +38,8 @@ #include <QtGui> #include <qpa/qplatformaccessibility.h> +#ifndef QT_NO_ACCESSIBILITY + QT_BEGIN_NAMESPACE class QCocoaAccessibility : public QPlatformAccessibility @@ -85,4 +87,6 @@ id getValueAttribute(QAccessibleInterface *interface); QT_END_NAMESPACE -#endif +#endif // QT_NO_ACCESSIBILITY + +#endif // QCOCOAACCESIBILITY_H diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm index 56042e72ea..f83d15f48e 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm @@ -37,6 +37,8 @@ QT_BEGIN_NAMESPACE +#ifndef QT_NO_ACCESSIBILITY + QCocoaAccessibility::QCocoaAccessibility() { @@ -378,5 +380,7 @@ id getValueAttribute(QAccessibleInterface *interface) } // namespace QCocoaAccessible +#endif // QT_NO_ACCESSIBILITY + QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h index 33a7ef4add..73aeae129b 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h @@ -37,7 +37,10 @@ #include "qt_mac_p.h" -#import <AppKit/AppKit.h> +#ifndef QT_NO_ACCESSIBILITY + +#import <Cocoa/Cocoa.h> +#import <AppKit/NSAccessibility.h> #import <qaccessible.h> @@ -55,4 +58,6 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement); -#endif +#endif // QT_NO_ACCESSIBILITY + +#endif // QCOCOAACCESIBILITYELEMENT_H diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index fd5962cc34..050fb7ba0a 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -42,6 +42,8 @@ QT_USE_NAMESPACE +#ifndef QT_NO_ACCESSIBILITY + static void convertLineOffset(QAccessibleTextInterface *text, int &line, int &offset, NSUInteger *start = 0, NSUInteger *end = 0) { Q_ASSERT(line == -1 || offset == -1); @@ -582,3 +584,5 @@ static void convertLineOffset(QAccessibleTextInterface *text, int &line, int &of } @end + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index cac50825af..caa8884661 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -221,12 +221,8 @@ QT_END_NAMESPACE const QWindowList topLevels = QGuiApplication::topLevelWindows(); for (int i = 0; i < topLevels.size(); ++i) { QWindow *topLevelWindow = topLevels.at(i); - // Widgets have alreay received a CloseEvent from the QApplication - // QCloseEvent handler. (see canQuit above). Prevent running the - // CloseEvent logic twice, call close() directly. - if (topLevelWindow->inherits("QWidgetWindow")) - topLevelWindow->close(); - else + // Already closed windows will not have a platform window, skip those + if (topLevelWindow->handle()) QWindowSystemInterface::handleCloseEvent(topLevelWindow); } QWindowSystemInterface::flushWindowSystemEvents(); diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index 6a4f7ed8ee..ca92103826 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -44,6 +44,8 @@ QCocoaBackingStore::QCocoaBackingStore(QWindow *window) QCocoaBackingStore::~QCocoaBackingStore() { + if (QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window()->handle())) + [cocoaWindow->m_qtView clearBackingStore:this]; } QPaintDevice *QCocoaBackingStore::paintDevice() diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 93ee4e8624..9dc013ba4d 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -588,9 +588,6 @@ void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_filterSelected(int menuInd emit filterSelected(menuIndex >= 0 && menuIndex < filters.size() ? filters.at(menuIndex) : QString()); } -extern OSErr qt_mac_create_fsref(const QString &, FSRef *); // qglobal.cpp -extern void qt_mac_to_pascal_string(QString s, Str255 str, TextEncoding encoding=0, int len=-1); // qglobal.cpp - void QCocoaFileDialogHelper::setDirectory(const QUrl &directory) { if (mDelegate) diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index cdeef1c6db..d43c8e5ee9 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -146,19 +146,25 @@ QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLCo QMacAutoReleasePool pool; // For the SG Canvas render thread + // create native context for the requested pixel format and share NSOpenGLPixelFormat *pixelFormat = static_cast <NSOpenGLPixelFormat *>(qcgl_createNSOpenGLPixelFormat(m_format)); m_shareContext = share ? static_cast<QCocoaGLContext *>(share)->nsOpenGLContext() : nil; + m_context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:m_shareContext]; - m_context = [NSOpenGLContext alloc]; - [m_context initWithFormat:pixelFormat shareContext:m_shareContext]; - + // retry without sharing on context creation failure. if (!m_context && m_shareContext) { - // try without shared context m_shareContext = nil; - [m_context initWithFormat:pixelFormat shareContext:nil]; + m_context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil]; + if (m_context) + qWarning("QCocoaGLContext: Falling back to unshared context."); } + // give up if we still did not get a native context [pixelFormat release]; + if (!m_context) { + qWarning("QCocoaGLContext: Failed to create context."); + return; + } const GLint interval = format.swapInterval() >= 0 ? format.swapInterval() : 1; [m_context setValues:&interval forParameter:NSOpenGLCPSwapInterval]; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index 5977d88e87..c7875af83e 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -121,7 +121,9 @@ public: QCoreTextFontDatabase *fontDatabase() const Q_DECL_OVERRIDE; QCocoaNativeInterface *nativeInterface() const Q_DECL_OVERRIDE; QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE; +#ifndef QT_NO_ACCESSIBILITY QCocoaAccessibility *accessibility() const Q_DECL_OVERRIDE; +#endif QCocoaClipboard *clipboard() const Q_DECL_OVERRIDE; QCocoaDrag *drag() const Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index c988bdc6a7..e469ec5c74 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -47,6 +47,7 @@ #include "qcocoamimetypes.h" #include "qcocoaaccessibility.h" +#include <qpa/qplatforminputcontextfactory_p.h> #include <qpa/qplatformaccessibility.h> #include <qpa/qplatforminputcontextfactory_p.h> #include <QtCore/qcoreapplication.h> @@ -286,9 +287,9 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) qWarning("Creating multiple Cocoa platform integrations is not supported"); mInstance = this; - mInputContext.reset(QPlatformInputContextFactory::create()); - if (mInputContext.isNull()) - mInputContext.reset(new QCocoaInputContext()); + QString icStr = QPlatformInputContextFactory::requested(); + icStr.isNull() ? mInputContext.reset(new QCocoaInputContext) + : mInputContext.reset(QPlatformInputContextFactory::create(icStr)); initResources(); QMacAutoReleasePool pool; @@ -501,14 +502,12 @@ QPlatformInputContext *QCocoaIntegration::inputContext() const return mInputContext.data(); } +#ifndef QT_NO_ACCESSIBILITY QCocoaAccessibility *QCocoaIntegration::accessibility() const { -#ifndef QT_NO_ACCESSIBILITY return mAccessibility.data(); -#else - return 0; -#endif } +#endif QCocoaClipboard *QCocoaIntegration::clipboard() const { diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h index 7e09116a37..a49a42378d 100644 --- a/src/plugins/platforms/cocoa/qnsview.h +++ b/src/plugins/platforms/cocoa/qnsview.h @@ -51,8 +51,7 @@ QT_END_NAMESPACE Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)); @interface QT_MANGLE_NAMESPACE(QNSView) : NSView <NSTextInputClient> { - QImage m_backingStore; - qreal m_pixelRatio; + QCocoaBackingStore* m_backingStore; QPoint m_backingStoreOffset; CGImageRef m_maskImage; uchar *m_maskData; @@ -86,6 +85,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper)); - (void)setQCocoaGLContext:(QCocoaGLContext *)context; #endif - (void)flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset; +- (void)clearBackingStore:(QCocoaBackingStore *)backingStore; - (void)setMaskRegion:(const QRegion *)region; - (void)invalidateWindowShadowIfNeeded; - (void)drawRect:(NSRect)dirtyRect; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index edcbd16dca..4db55c1b73 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -134,7 +134,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; { self = [super initWithFrame : NSMakeRect(0,0, 300,300)]; if (self) { - m_pixelRatio = 1.; + m_backingStore = 0; m_maskImage = 0; m_shouldInvalidateWindowShadow = false; m_window = 0; @@ -376,7 +376,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; if (!m_platformWindow->m_inSetGeometry) QWindowSystemInterface::flushWindowSystemEvents(); else - m_backingStore = QImage(); + m_backingStore = 0; } } @@ -481,12 +481,16 @@ QT_WARNING_POP - (void) flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset { - m_backingStore = backingStore->toImage(); - m_pixelRatio = backingStore->getBackingStoreDevicePixelRatio(); - m_backingStoreOffset = offset * m_pixelRatio; - foreach (QRect rect, region.rects()) { + m_backingStore = backingStore; + m_backingStoreOffset = offset * m_backingStore->getBackingStoreDevicePixelRatio(); + foreach (QRect rect, region.rects()) [self setNeedsDisplayInRect:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())]; - } +} + +- (void)clearBackingStore:(QCocoaBackingStore *)backingStore +{ + if (backingStore == m_backingStore) + m_backingStore = 0; } - (BOOL) hasMask @@ -549,7 +553,7 @@ QT_WARNING_POP if (m_platformWindow->m_drawContentBorderGradient) NSDrawWindowBackground(dirtyRect); - if (m_backingStore.isNull()) + if (!m_backingStore) return; // Calculate source and target rects. The target rect is the dirtyRect: @@ -557,10 +561,11 @@ QT_WARNING_POP // The backing store source rect will be larger on retina displays. // Scale dirtyRect by the device pixel ratio: - CGRect dirtyBackingRect = CGRectMake(dirtyRect.origin.x * m_pixelRatio, - dirtyRect.origin.y * m_pixelRatio, - dirtyRect.size.width * m_pixelRatio, - dirtyRect.size.height * m_pixelRatio); + const qreal devicePixelRatio = m_backingStore->getBackingStoreDevicePixelRatio(); + CGRect dirtyBackingRect = CGRectMake(dirtyRect.origin.x * devicePixelRatio, + dirtyRect.origin.y * devicePixelRatio, + dirtyRect.size.width * devicePixelRatio, + dirtyRect.size.height * devicePixelRatio); NSGraphicsContext *nsGraphicsContext = [NSGraphicsContext currentContext]; CGContextRef cgContext = (CGContextRef) [nsGraphicsContext graphicsPort]; @@ -586,7 +591,7 @@ QT_WARNING_POP dirtyBackingRect.size.width, dirtyBackingRect.size.height ); - CGImageRef bsCGImage = qt_mac_toCGImage(m_backingStore); + CGImageRef bsCGImage = qt_mac_toCGImage(m_backingStore->toImage()); CGImageRef cleanImg = CGImageCreateWithImageInRect(bsCGImage, backingStoreRect); // Optimization: Copy frame buffer content instead of blending for diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm index 93f0817aad..1f15da5b3b 100644 --- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm +++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm @@ -44,6 +44,8 @@ #import <AppKit/NSAccessibility.h> +#ifndef QT_NO_ACCESSIBILITY + @implementation QNSView (QNSViewAccessibility) - (id)childAccessibleElement { @@ -80,3 +82,5 @@ } @end + +#endif // QT_NO_ACCESSIBILITY diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp index aec5a5e179..f0946b9b64 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp @@ -40,6 +40,7 @@ #include <QtGui/QScreen> #include <QtGui/QOffscreenSurface> #include <QtGui/QWindow> +#include <QtCore/QLoggingCategory> #include <qpa/qwindowsysteminterface.h> #include <qpa/qplatforminputcontextfactory_p.h> @@ -62,6 +63,10 @@ #include <QtPlatformHeaders/QEGLNativeContext> +#ifndef QT_NO_LIBINPUT +#include <QtPlatformSupport/private/qlibinputhandler_p.h> +#endif + #if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) #include <QtPlatformSupport/private/qevdevmousemanager_p.h> #include <QtPlatformSupport/private/qevdevkeyboardmanager_p.h> @@ -124,13 +129,14 @@ void QEglFSIntegration::initialize() m_vtHandler.reset(new QFbVtHandler); - if (!m_disableInputHandlers) - createInputHandlers(); - if (qt_egl_device_integration()->usesDefaultScreen()) addScreen(new QEglFSScreen(display())); else qt_egl_device_integration()->screenInit(); + + // Input code may rely on the screens, so do it only after the screen init. + if (!m_disableInputHandlers) + createInputHandlers(); } void QEglFSIntegration::destroy() @@ -389,6 +395,13 @@ void QEglFSIntegration::loadKeymapStatic(const QString &filename) void QEglFSIntegration::createInputHandlers() { +#ifndef QT_NO_LIBINPUT + if (!qEnvironmentVariableIntValue("QT_QPA_EGLFS_NO_LIBINPUT")) { + new QLibInputHandler(QLatin1String("libinput"), QString()); + return; + } +#endif + #if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) m_kbdMgr = new QEvdevKeyboardManager(QLatin1String("EvdevKeyboard"), QString() /* spec */, this); new QEvdevMouseManager(QLatin1String("EvdevMouse"), QString() /* spec */, this); diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index e2c61e1161..e4917593db 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -344,6 +344,46 @@ // ------------------------------------------------------------------------- +- (void)sendKeyPressRelease:(Qt::Key)key modifiers:(Qt::KeyboardModifiers)modifiers +{ + QKeyEvent press(QEvent::KeyPress, key, modifiers); + QKeyEvent release(QEvent::KeyRelease, key, modifiers); + [self sendEventToFocusObject:press]; + [self sendEventToFocusObject:release]; +} + +- (void)cut:(id)sender +{ + Q_UNUSED(sender); + [self sendKeyPressRelease:Qt::Key_X modifiers:Qt::ControlModifier]; +} + +- (void)copy:(id)sender +{ + Q_UNUSED(sender); + [self sendKeyPressRelease:Qt::Key_C modifiers:Qt::ControlModifier]; +} + +- (void)paste:(id)sender +{ + Q_UNUSED(sender); + [self sendKeyPressRelease:Qt::Key_V modifiers:Qt::ControlModifier]; +} + +- (void)selectAll:(id)sender +{ + Q_UNUSED(sender); + [self sendKeyPressRelease:Qt::Key_A modifiers:Qt::ControlModifier]; +} + +- (void)delete:(id)sender +{ + Q_UNUSED(sender); + [self sendKeyPressRelease:Qt::Key_Delete modifiers:Qt::ControlModifier]; +} + +// ------------------------------------------------------------------------- + - (void)notifyInputDelegate:(Qt::InputMethodQueries)updatedProperties { // As documented, we should not report textWillChange/textDidChange unless the text @@ -560,7 +600,7 @@ if (cursorPos != int(r.location + r.length) || cursorPos != anchorPos) { attrs = QList<QInputMethodEvent::Attribute>(); - attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, cursorPos, (cursorPos - anchorPos), 0); + attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, qMin(cursorPos, anchorPos), qAbs(cursorPos - anchorPos), 0); e = QInputMethodEvent(m_markedText, attrs); [self sendEventToFocusObject:e]; } @@ -678,10 +718,7 @@ return; if ([text isEqualToString:@"\n"]) { - QKeyEvent press(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier); - QKeyEvent release(QEvent::KeyRelease, Qt::Key_Return, Qt::NoModifier); - [self sendEventToFocusObject:press]; - [self sendEventToFocusObject:release]; + [self sendKeyPressRelease:Qt::Key_Return modifiers:Qt::NoModifier]; if (self.returnKeyType == UIReturnKeyDone || self.returnKeyType == UIReturnKeyGo || self.returnKeyType == UIReturnKeySend || self.returnKeyType == UIReturnKeySearch) @@ -700,10 +737,7 @@ // Since we're posting im events directly to the focus object, we should do the // same for key events. Otherwise they might end up in a different place or out // of sync with im events. - QKeyEvent press(QEvent::KeyPress, (int)Qt::Key_Backspace, Qt::NoModifier); - QKeyEvent release(QEvent::KeyRelease, (int)Qt::Key_Backspace, Qt::NoModifier); - [self sendEventToFocusObject:press]; - [self sendEventToFocusObject:release]; + [self sendKeyPressRelease:Qt::Key_Backspace modifiers:Qt::NoModifier]; } @end diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm index 4ea5fc7de1..67b33ce235 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.mm +++ b/src/plugins/platforms/ios/qiosviewcontroller.mm @@ -143,7 +143,7 @@ if (uiWindow.screen != [UIScreen mainScreen] && self.subviews.count == 1) { // Removing the last view of an external screen, go back to mirror mode - uiWindow.screen = nil; + uiWindow.screen = [UIScreen mainScreen]; uiWindow.hidden = YES; } } @@ -190,8 +190,9 @@ - (void)setBounds:(CGRect)newBounds { + Q_UNUSED(newBounds); CGRect transformedWindowBounds = [self convertRect:self.window.bounds fromView:self.window]; - [super setBounds:CGRectMake(0, 0, CGRectGetWidth(newBounds), CGRectGetHeight(transformedWindowBounds))]; + [super setBounds:CGRectMake(0, 0, CGRectGetWidth(transformedWindowBounds), CGRectGetHeight(transformedWindowBounds))]; } - (void)setCenter:(CGPoint)newCenter diff --git a/src/plugins/platforms/kms/kms.json b/src/plugins/platforms/kms/kms.json deleted file mode 100644 index be662226ae..0000000000 --- a/src/plugins/platforms/kms/kms.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Keys": [ "kms" ] -} diff --git a/src/plugins/platforms/kms/kms.pro b/src/plugins/platforms/kms/kms.pro deleted file mode 100644 index baa8778153..0000000000 --- a/src/plugins/platforms/kms/kms.pro +++ /dev/null @@ -1,37 +0,0 @@ -TARGET = qkms - -PLUGIN_TYPE = platforms -PLUGIN_CLASS_NAME = QKmsIntegrationPlugin -!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - -load(qt_plugin) - -QT += core-private gui-private platformsupport-private -qtHaveModule(opengl):QT += opengl-private - -DEFINES += MESA_EGL_NO_X11_HEADERS __GBM__ - -CONFIG += link_pkgconfig egl qpa/genericunixfontdatabase - -PKGCONFIG += libdrm libudev egl gbm glesv2 - -SOURCES = main.cpp \ - qkmsintegration.cpp \ - qkmsscreen.cpp \ - qkmscontext.cpp \ - qkmswindow.cpp \ - qkmscursor.cpp \ - qkmsdevice.cpp \ - qkmsbackingstore.cpp \ - qkmsnativeinterface.cpp - -HEADERS = qkmsintegration.h \ - qkmsscreen.h \ - qkmscontext.h \ - qkmswindow.h \ - qkmscursor.h \ - qkmsdevice.h \ - qkmsbackingstore.h \ - qkmsnativeinterface.h - -OTHER_FILES += \ - kms.json diff --git a/src/plugins/platforms/kms/main.cpp b/src/plugins/platforms/kms/main.cpp deleted file mode 100644 index 565ac7a7d4..0000000000 --- a/src/plugins/platforms/kms/main.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <qpa/qplatformintegrationplugin.h> -#include "qkmsintegration.h" - -QT_BEGIN_NAMESPACE - -class QKmsIntegrationPlugin : public QPlatformIntegrationPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "kms.json") -public: - QPlatformIntegration *create(const QString&, const QStringList&) Q_DECL_OVERRIDE; -}; - -QPlatformIntegration *QKmsIntegrationPlugin::create(const QString& system, const QStringList& paramList) -{ - Q_UNUSED(paramList); - if (!system.compare(QLatin1String("kms"), Qt::CaseInsensitive)) - return new QKmsIntegration; - - return 0; -} - -QT_END_NAMESPACE - -#include "main.moc" diff --git a/src/plugins/platforms/kms/qkmsbackingstore.cpp b/src/plugins/platforms/kms/qkmsbackingstore.cpp deleted file mode 100644 index 6e5a3f9192..0000000000 --- a/src/plugins/platforms/kms/qkmsbackingstore.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qkmsbackingstore.h" - -#include <QtGui/QOpenGLContext> -#include <QtGui/QOpenGLShaderProgram> -#include <QtGui/QScreen> - -QT_BEGIN_NAMESPACE - -QKmsBackingStore::QKmsBackingStore(QWindow *window) - : QPlatformBackingStore(window) - , m_context(new QOpenGLContext) - , m_texture(0) - , m_program(0) - , m_initialized(false) -{ - m_context->setFormat(window->requestedFormat()); - m_context->setScreen(window->screen()); - m_context->create(); -} - -QKmsBackingStore::~QKmsBackingStore() -{ - delete m_program; - if (m_texture) - glDeleteTextures(1, &m_texture); - - delete m_context; -} - -QPaintDevice *QKmsBackingStore::paintDevice() -{ - return &m_image; -} - -void QKmsBackingStore::beginPaint(const QRegion &rgn) -{ - m_dirty |= rgn; -} - -void QKmsBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) -{ - Q_UNUSED(region) - Q_UNUSED(offset) - - m_context->makeCurrent(window); - - if (!m_initialized) { - initializeOpenGLFunctions(); - m_initialized = true; - } - - if (!m_program) { - static const char *textureVertexProgram = - "attribute highp vec2 vertexCoordEntry;\n" - "attribute highp vec2 textureCoordEntry;\n" - "varying highp vec2 textureCoord;\n" - "void main() {\n" - " textureCoord = textureCoordEntry;\n" - " gl_Position = vec4(vertexCoordEntry, 0.0, 1.0);\n" - "}\n"; - - static const char *textureFragmentProgram = - "uniform sampler2D texture;\n" - "varying highp vec2 textureCoord;\n" - "void main() {\n" - " gl_FragColor = texture2D(texture, textureCoord).bgra;\n" - "}\n"; - - m_program = new QOpenGLShaderProgram; - - m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram); - m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram); - m_program->bindAttributeLocation("vertexCoordEntry", 0); - m_program->bindAttributeLocation("textureCoordEntry", 1); - m_program->link(); - } - - m_program->bind(); - - QRectF r = window->geometry(); - QRectF sr = window->screen()->geometry(); - - GLfloat x1 = (r.left() / sr.width()) * 2 - 1; - GLfloat x2 = (r.right() / sr.width()) * 2 - 1; - GLfloat y1 = -1 * ((r.top() / sr.height()) * 2 - 1); - GLfloat y2 = -1 * ((r.bottom() / sr.height()) * 2 - 1); - - const GLfloat vertexCoordinates[] = { - x1, y1, - x2, y1, - x2, y2, - x1, y2 - }; - - const GLfloat textureCoordinates[] = { - 0, 0, - 1, 0, - 1, 1, - 0, 1 - }; - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinates); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates); - - glBindTexture(GL_TEXTURE_2D, m_texture); - - if (!m_dirty.isNull()) { - QRect imageRect = m_image.rect(); - QRegion fixed; - Q_FOREACH (const QRect &rect, m_dirty.rects()) { - // intersect with image rect to be sure - QRect r = imageRect & rect; - // if the rect is wide enough it's cheaper to just - // extend it instead of doing an image copy - if (r.width() >= imageRect.width() / 2) { - r.setX(0); - r.setWidth(imageRect.width()); - } - fixed |= r; - } - - Q_FOREACH (const QRect &rect, fixed.rects()) { - // if the sub-rect is full-width we can pass the image data directly to - // OpenGL instead of copying, since there's no gap between scanlines - if (rect.width() == imageRect.width()) { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), - rect.width(), rect.height(), - GL_RGBA, GL_UNSIGNED_BYTE, - m_image.constScanLine(rect.y())); - } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), - rect.width(), rect.height(), - GL_RGBA, GL_UNSIGNED_BYTE, - m_image.copy(rect).constBits()); - } - } - - m_dirty = QRegion(); - } - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - m_program->release(); - glBindTexture(GL_TEXTURE_2D, 0); - glDisableVertexAttribArray(0); - glDisableVertexAttribArray(1); - - m_context->swapBuffers(window); - - m_context->doneCurrent(); -} - -void QKmsBackingStore::resize(const QSize &size, const QRegion &staticContents) -{ - Q_UNUSED(staticContents) - - m_image = QImage(size, QImage::Format_RGB32); - - m_context->makeCurrent(window()); - - if (!m_initialized) { - initializeOpenGLFunctions(); - m_initialized = true; - } - - if (m_texture) - glDeleteTextures(1, &m_texture); - - glGenTextures(1, &m_texture); - glBindTexture(GL_TEXTURE_2D, m_texture); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), - 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/kms/qkmsbackingstore.h b/src/plugins/platforms/kms/qkmsbackingstore.h deleted file mode 100644 index a34b10d3d9..0000000000 --- a/src/plugins/platforms/kms/qkmsbackingstore.h +++ /dev/null @@ -1,72 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QBACKINGSTORE_KMS_H -#define QBACKINGSTORE_KMS_H - -#include <qpa/qplatformbackingstore.h> -#include <QtGui/QOpenGLFunctions> -#include <QImage> - -QT_BEGIN_NAMESPACE - -class QOpenGLContext; -class QOpenGLShaderProgram; - -class QKmsBackingStore : public QPlatformBackingStore, public QOpenGLFunctions -{ -public: - QKmsBackingStore(QWindow *window); - ~QKmsBackingStore(); - - QPaintDevice *paintDevice() Q_DECL_OVERRIDE; - - void beginPaint(const QRegion &) Q_DECL_OVERRIDE; - - void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; - void resize(const QSize &size, const QRegion &staticContents) Q_DECL_OVERRIDE; - - QImage toImage() const Q_DECL_OVERRIDE { return m_image; } - -private: - QOpenGLContext *m_context; - QImage m_image; - uint m_texture; - QOpenGLShaderProgram *m_program; - QRegion m_dirty; - bool m_initialized; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/plugins/platforms/kms/qkmscontext.cpp b/src/plugins/platforms/kms/qkmscontext.cpp deleted file mode 100644 index e00835fbac..0000000000 --- a/src/plugins/platforms/kms/qkmscontext.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qkmsscreen.h" -#include "qkmsdevice.h" -#include "qkmscontext.h" -#include "qkmswindow.h" -#include "qkmsintegration.h" - -#include <QtGui/QOpenGLContext> -#include <QtPlatformSupport/private/qeglconvenience_p.h> - -QT_BEGIN_NAMESPACE - -QKmsContext::QKmsContext(QOpenGLContext *context, QKmsDevice *device) - : m_device(device) -{ - EGLDisplay display = m_device->eglDisplay(); - EGLConfig config = q_configFromGLFormat(display, QKmsScreen::tweakFormat(context->format())); - m_format = q_glFormatFromConfig(display, config); - - //Initialize EGLContext - static EGLint contextAttribs[] = { - EGL_CONTEXT_CLIENT_VERSION, context->format().majorVersion(), - EGL_NONE - }; - - eglBindAPI(EGL_OPENGL_ES_API); - - EGLContext share = EGL_NO_CONTEXT; - if (context->shareContext()) - share = static_cast<QKmsContext *>(context->shareContext()->handle())->eglContext(); - - m_eglContext = eglCreateContext(display, config, share, contextAttribs); - if (m_eglContext == EGL_NO_CONTEXT) { - qWarning("QKmsContext::QKmsContext(): eglError: %x, this: %p", - eglGetError(), this); - m_eglContext = 0; - } -} - -bool QKmsContext::isValid() const -{ - return m_eglContext != EGL_NO_CONTEXT; -} - -bool QKmsContext::makeCurrent(QPlatformSurface *surface) -{ - Q_ASSERT(surface->surface()->supportsOpenGL()); - - EGLDisplay display = m_device->eglDisplay(); - EGLSurface eglSurface; - - if (surface->surface()->surfaceClass() == QSurface::Window) { - QPlatformWindow *window = static_cast<QPlatformWindow *>(surface); - QKmsScreen *screen = static_cast<QKmsScreen *>(QPlatformScreen::platformScreenForWindow(window->window())); - eglSurface = screen->eglSurface(); - screen->waitForPageFlipComplete(); - } else { - eglSurface = static_cast<QKmsOffscreenWindow *>(surface)->surface(); - } - - bool ok = eglMakeCurrent(display, eglSurface, eglSurface, m_eglContext); - if (!ok) - qWarning("QKmsContext::makeCurrent(): eglError: %x, this: %p", - eglGetError(), this); - - return true; -} - -void QKmsContext::doneCurrent() -{ - bool ok = eglMakeCurrent(m_device->eglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, - EGL_NO_CONTEXT); - if (!ok) - qWarning("QKmsContext::doneCurrent(): eglError: %x, this: %p", - eglGetError(), this); - -} - -void QKmsContext::swapBuffers(QPlatformSurface *surface) -{ - //Cast context to a window surface and get the screen the context - //is on and call swapBuffers on that screen. - QPlatformWindow *window = static_cast<QPlatformWindow *>(surface); - QKmsScreen *screen = static_cast<QKmsScreen *> (QPlatformScreen::platformScreenForWindow(window->window())); - screen->swapBuffers(); -} - -void (*QKmsContext::getProcAddress(const QByteArray &procName)) () -{ - return eglGetProcAddress(procName.data()); -} - - -EGLContext QKmsContext::eglContext() const -{ - return m_eglContext; -} - -QSurfaceFormat QKmsContext::format() const -{ - return m_format; -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/kms/qkmscontext.h b/src/plugins/platforms/kms/qkmscontext.h deleted file mode 100644 index 59cf9b1e34..0000000000 --- a/src/plugins/platforms/kms/qkmscontext.h +++ /dev/null @@ -1,71 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QKMSCONTEXT_H -#define QKMSCONTEXT_H - -#include <qpa/qplatformopenglcontext.h> - -#define EGL_EGLEXT_PROTOTYPES 1 -#include <EGL/egl.h> - -QT_BEGIN_NAMESPACE - -class QKmsDevice; - -class QKmsContext : public QPlatformOpenGLContext -{ -public: - QKmsContext(QOpenGLContext *context, QKmsDevice *device); - - bool makeCurrent(QPlatformSurface *surface) Q_DECL_OVERRIDE; - void doneCurrent() Q_DECL_OVERRIDE; - void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; - void (*getProcAddress(const QByteArray &procName)) () Q_DECL_OVERRIDE; - - bool isValid() const Q_DECL_OVERRIDE; - - QSurfaceFormat format() const Q_DECL_OVERRIDE; - - EGLContext eglContext() const; - -private: - EGLContext m_eglContext; - QSurfaceFormat m_format; - - QKmsDevice *m_device; -}; - -QT_END_NAMESPACE - -#endif // QKMSCONTEXT_H diff --git a/src/plugins/platforms/kms/qkmscursor.cpp b/src/plugins/platforms/kms/qkmscursor.cpp deleted file mode 100644 index 44212cd3c8..0000000000 --- a/src/plugins/platforms/kms/qkmscursor.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -//#include <QDebug> -#include "qkmscursor.h" -#include "qkmsscreen.h" -#include "qkmsdevice.h" - -QT_BEGIN_NAMESPACE - -#ifndef DRM_CAP_CURSOR_WIDTH -#define DRM_CAP_CURSOR_WIDTH 0x8 -#endif - -#ifndef DRM_CAP_CURSOR_HEIGHT -#define DRM_CAP_CURSOR_HEIGHT 0x9 -#endif - -QKmsCursor::QKmsCursor(QKmsScreen *screen) - : m_screen(screen), - m_graphicsBufferManager(screen->device()->gbmDevice()), - m_cursorImage(new QPlatformCursorImage(0, 0, 0, 0, 0, 0)), - m_moved(false), - m_cursorSize(64, 64) -{ - uint64_t value = 0; - if (!drmGetCap(m_screen->device()->fd(), DRM_CAP_CURSOR_WIDTH, &value)) - m_cursorSize.setWidth(value); - if (!drmGetCap(m_screen->device()->fd(), DRM_CAP_CURSOR_HEIGHT, &value)) - m_cursorSize.setHeight(value); - - m_cursorBufferObject = gbm_bo_create(m_graphicsBufferManager, m_cursorSize.width(), m_cursorSize.height(), - GBM_FORMAT_ARGB8888, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE); -} - -QKmsCursor::~QKmsCursor() -{ - drmModeSetCursor(m_screen->device()->fd(), m_screen->crtcId(), 0, 0, 0); - gbm_bo_destroy(m_cursorBufferObject); -} - -void QKmsCursor::pointerEvent(const QMouseEvent &event) -{ - m_moved = true; - int status = drmModeMoveCursor(m_screen->device()->fd(), - m_screen->crtcId(), - event.globalX(), - event.globalY()); - if (status) { - qWarning("failed to move cursor: %d", status); - } -} - -void QKmsCursor::changeCursor(QCursor *windowCursor, QWindow *window) -{ - Q_UNUSED(window) - - if (!m_moved) - drmModeMoveCursor(m_screen->device()->fd(), m_screen->crtcId(), 0, 0); - - const Qt::CursorShape newShape = windowCursor ? windowCursor->shape() : Qt::ArrowCursor; - if (newShape != Qt::BitmapCursor) { - m_cursorImage->set(newShape); - } else { - m_cursorImage->set(windowCursor->pixmap().toImage(), - windowCursor->hotSpot().x(), - windowCursor->hotSpot().y()); - } - - if (m_cursorImage->image()->width() > m_cursorSize.width() || m_cursorImage->image()->width() > m_cursorSize.height()) - qWarning("cursor larger than %dx%d, cursor truncated", m_cursorSize.width(), m_cursorSize.height()); - - QImage cursorImage = m_cursorImage->image()->convertToFormat(QImage::Format_ARGB32) - .copy(0, 0, m_cursorSize.width(), m_cursorSize.height()); - gbm_bo_write(m_cursorBufferObject, cursorImage.constBits(), cursorImage.byteCount()); - - quint32 handle = gbm_bo_get_handle(m_cursorBufferObject).u32; - int status = drmModeSetCursor(m_screen->device()->fd(), - m_screen->crtcId(), handle, - m_cursorSize.width(), m_cursorSize.height()); - - if (status) { - qWarning("failed to set cursor: %d", status); - } -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/kms/qkmscursor.h b/src/plugins/platforms/kms/qkmscursor.h deleted file mode 100644 index 9aadf407c0..0000000000 --- a/src/plugins/platforms/kms/qkmscursor.h +++ /dev/null @@ -1,66 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QKMSCURSOR_H -#define QKMSCURSOR_H - -#include <qpa/qplatformcursor.h> - -struct gbm_device; -struct gbm_bo; - -QT_BEGIN_NAMESPACE - -class QKmsScreen; - -class QKmsCursor : public QPlatformCursor -{ -public: - QKmsCursor(QKmsScreen *screen); - ~QKmsCursor(); - - void pointerEvent(const QMouseEvent &event) Q_DECL_OVERRIDE; - void changeCursor(QCursor *windowCursor, QWindow *window) Q_DECL_OVERRIDE; - -private: - QKmsScreen *m_screen; - gbm_device *m_graphicsBufferManager; - gbm_bo *m_cursorBufferObject; - QPlatformCursorImage *m_cursorImage; - bool m_moved; - QSize m_cursorSize; -}; - -QT_END_NAMESPACE - -#endif // QKMSCURSOR_H diff --git a/src/plugins/platforms/kms/qkmsdevice.cpp b/src/plugins/platforms/kms/qkmsdevice.cpp deleted file mode 100644 index 74fa59c16a..0000000000 --- a/src/plugins/platforms/kms/qkmsdevice.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -//#include <QDebug> -#include "qkmsscreen.h" -#include "qkmsdevice.h" - -#include "qkmsintegration.h" - -#include <QtCore/QSocketNotifier> -#include <QtCore/private/qcore_unix_p.h> - -QT_BEGIN_NAMESPACE - -QKmsDevice::QKmsDevice(const QString &path, QKmsIntegration *parent) : - QObject(0), m_integration(parent) -{ - m_fd = QT_OPEN(path.toLatin1().constData(), O_RDWR); - if (m_fd < 0) { - qWarning("Could not open %s.", path.toLatin1().constData()); - qFatal("No DRM display device"); - } - - m_graphicsBufferManager = gbm_create_device(m_fd); - m_eglDisplay = eglGetDisplay(m_graphicsBufferManager); - - if (m_eglDisplay == EGL_NO_DISPLAY) { - qWarning("Could not open EGL display"); - qFatal("EGL error"); - } - - EGLint major; - EGLint minor; - if (!eglInitialize(m_eglDisplay, &major, &minor)) { - qWarning("Could not initialize EGL display"); - qFatal("EGL error"); - } - - createScreens(); - -// QSocketNotifier *notifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this); -// connect(notifier, SIGNAL(activated(int)), this, SLOT(handlePageFlipCompleted())); -} - -QKmsDevice::~QKmsDevice() -{ -} - -void QKmsDevice::createScreens() -{ - drmModeRes *resources = drmModeGetResources(m_fd); - if (!resources) - qFatal("drmModeGetResources failed"); - - //Iterate connectors and create screens on each one active - for (int i = 0; i < resources->count_connectors; i++) { - drmModeConnector *connector = 0; - connector = drmModeGetConnector(m_fd, resources->connectors[i]); - if (connector && connector->connection == DRM_MODE_CONNECTED) { - m_integration->addScreen(new QKmsScreen(this, resources, connector)); - } - drmModeFreeConnector(connector); - } - drmModeFreeResources(resources); -} - -void QKmsDevice::handlePageFlipCompleted() -{ - drmEventContext eventContext; - - memset(&eventContext, 0, sizeof eventContext); - eventContext.version = DRM_EVENT_CONTEXT_VERSION; - eventContext.page_flip_handler = QKmsDevice::pageFlipHandler; - drmHandleEvent(m_fd, &eventContext); - -} - -void QKmsDevice::pageFlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) -{ - Q_UNUSED(fd) - Q_UNUSED(frame) - Q_UNUSED(sec) - Q_UNUSED(usec) - - QKmsScreen *screen = static_cast<QKmsScreen *>(data); - screen->handlePageFlipped(); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/kms/qkmsdevice.h b/src/plugins/platforms/kms/qkmsdevice.h deleted file mode 100644 index d5e33cb8c7..0000000000 --- a/src/plugins/platforms/kms/qkmsdevice.h +++ /dev/null @@ -1,81 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QKMSDEVICE_H -#define QKMSDEVICE_H - -#include <stddef.h> - -extern "C" { -#include <gbm.h> -} -#include <EGL/egl.h> - -#include <QObject> - -struct gbm_device; - -QT_BEGIN_NAMESPACE - -class QKmsIntegration; - -class QKmsDevice : public QObject -{ - Q_OBJECT -public: - explicit QKmsDevice(const QString &path, QKmsIntegration *parent); - ~QKmsDevice(); - - EGLDisplay eglDisplay() { return m_eglDisplay; } - gbm_device *gbmDevice() { return m_graphicsBufferManager; } - int fd() const { return m_fd; } - - static void pageFlipHandler(int fd, unsigned int frame, unsigned int sec, - unsigned int usec, void *data); - -public slots: - void handlePageFlipCompleted(); -private: - void createScreens(); - - QKmsIntegration *m_integration; - - EGLDisplay m_eglDisplay; - EGLContext m_eglContext; - gbm_device *m_graphicsBufferManager; - int m_fd; -}; - -QT_END_NAMESPACE - -#endif // QKMSDEVICE_H diff --git a/src/plugins/platforms/kms/qkmsintegration.cpp b/src/plugins/platforms/kms/qkmsintegration.cpp deleted file mode 100644 index f48c868ae5..0000000000 --- a/src/plugins/platforms/kms/qkmsintegration.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qkmsintegration.h" -#include "qkmsdevice.h" -#include "qkmsscreen.h" -#include "qkmswindow.h" -#include "qkmsbackingstore.h" -#include "qkmscontext.h" -#include "qkmsnativeinterface.h" - -#if !defined(QT_NO_EVDEV) -#include <QtPlatformSupport/private/qevdevmousemanager_p.h> -#include <QtPlatformSupport/private/qevdevkeyboardmanager_p.h> -#include <QtPlatformSupport/private/qevdevtouch_p.h> -#endif - -#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> -#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> -#include <QtPlatformSupport/private/qfbvthandler_p.h> -#include <QtPlatformSupport/private/qeglconvenience_p.h> - -#include <QtGui/private/qguiapplication_p.h> -#include <QtGui/QOpenGLContext> -#include <QtGui/QScreen> -#include <QtGui/QOffscreenSurface> -#include <qpa/qplatformoffscreensurface.h> - -QT_BEGIN_NAMESPACE - -QKmsIntegration::QKmsIntegration() - : QPlatformIntegration(), - m_fontDatabase(new QGenericUnixFontDatabase()), - m_nativeInterface(new QKmsNativeInterface), - m_vtHandler(0), - m_deviceDiscovery(0) -{ -} - -QKmsIntegration::~QKmsIntegration() -{ - delete m_deviceDiscovery; - foreach (QKmsDevice *device, m_devices) { - delete device; - } - foreach (QPlatformScreen *screen, m_screens) { - destroyScreen(screen); - } - delete m_fontDatabase; - delete m_vtHandler; -} - -void QKmsIntegration::initialize() -{ - qputenv("EGL_PLATFORM", "drm"); - m_vtHandler = new QFbVtHandler; - - m_deviceDiscovery = QDeviceDiscovery::create(QDeviceDiscovery::Device_DRM | QDeviceDiscovery::Device_DRM_PrimaryGPU, 0); - if (m_deviceDiscovery) { - QStringList devices = m_deviceDiscovery->scanConnectedDevices(); - foreach (const QString &device, devices) - addDevice(device); - - connect(m_deviceDiscovery, SIGNAL(deviceDetected(QString)), this, SLOT(addDevice(QString))); - connect(m_deviceDiscovery, SIGNAL(deviceRemoved(QString)), this, SLOT(removeDevice(QString))); - } - -#if !defined(QT_NO_EVDEV) - new QEvdevKeyboardManager(QLatin1String("EvdevKeyboard"), QString() /* spec */, this); - new QEvdevMouseManager(QLatin1String("EvdevMouse"), QString() /* spec */, this); - new QEvdevTouchScreenHandlerThread(QString() /* spec */, this); -#endif -} - -void QKmsIntegration::addDevice(const QString &deviceNode) -{ - m_devices.append(new QKmsDevice(deviceNode, this)); -} - -void QKmsIntegration::removeDevice(const QString &deviceNode) -{ - // TODO: support hot-plugging some day? - Q_UNUSED(deviceNode); -} - -bool QKmsIntegration::hasCapability(QPlatformIntegration::Capability cap) const -{ - switch (cap) { - case ThreadedPixmaps: return true; - case OpenGL: return true; - case ThreadedOpenGL: return false; - case RasterGLSurface: return true; - default: return QPlatformIntegration::hasCapability(cap); - } -} - -QPlatformOpenGLContext *QKmsIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const -{ - QKmsScreen *screen = static_cast<QKmsScreen *>(context->screen()->handle()); - return new QKmsContext(context, screen->device()); -} - -QPlatformWindow *QKmsIntegration::createPlatformWindow(QWindow *window) const -{ - QKmsWindow *w = new QKmsWindow(window); - w->requestActivateWindow(); - return w; -} - -QPlatformBackingStore *QKmsIntegration::createPlatformBackingStore(QWindow *window) const -{ - return new QKmsBackingStore(window); -} - -// Neither a pbuffer nor a hidden QWindow is suitable. Just use an additional, small gbm surface. -QKmsOffscreenWindow::QKmsOffscreenWindow(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface) - : QPlatformOffscreenSurface(offscreenSurface) - , m_format(format) - , m_display(display) - , m_surface(EGL_NO_SURFACE) - , m_window(0) -{ - QKmsScreen *screen = static_cast<QKmsScreen *>(offscreenSurface->screen()->handle()); - m_window = gbm_surface_create(screen->device()->gbmDevice(), - 10, 10, - GBM_FORMAT_XRGB8888, - GBM_BO_USE_RENDERING); - if (!m_window) { - qWarning("QKmsOffscreenWindow: Failed to create native window"); - return; - } - - EGLConfig config = q_configFromGLFormat(m_display, m_format); - m_surface = eglCreateWindowSurface(m_display, config, m_window, 0); - if (m_surface != EGL_NO_SURFACE) - m_format = q_glFormatFromConfig(m_display, config); -} - -QKmsOffscreenWindow::~QKmsOffscreenWindow() -{ - if (m_surface != EGL_NO_SURFACE) - eglDestroySurface(m_display, m_surface); - if (m_window) - gbm_surface_destroy((gbm_surface *) m_window); -} - -QPlatformOffscreenSurface *QKmsIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const -{ - QKmsScreen *screen = static_cast<QKmsScreen *>(surface->screen()->handle()); - return new QKmsOffscreenWindow(screen->device()->eglDisplay(), QKmsScreen::tweakFormat(surface->format()), surface); -} - -QPlatformFontDatabase *QKmsIntegration::fontDatabase() const -{ - return m_fontDatabase; -} - -void QKmsIntegration::addScreen(QKmsScreen *screen) -{ - m_screens.append(screen); - screenAdded(screen); -} - -QAbstractEventDispatcher *QKmsIntegration::createEventDispatcher() const -{ - return createUnixEventDispatcher(); -} - -QPlatformNativeInterface *QKmsIntegration::nativeInterface() const -{ - return m_nativeInterface; -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/kms/qkmsintegration.h b/src/plugins/platforms/kms/qkmsintegration.h deleted file mode 100644 index bcf9ac7296..0000000000 --- a/src/plugins/platforms/kms/qkmsintegration.h +++ /dev/null @@ -1,108 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPLATFORMINTEGRATION_KMS_H -#define QPLATFORMINTEGRATION_KMS_H - -#include <qpa/qplatformintegration.h> -#include <qpa/qplatformnativeinterface.h> -#include <qpa/qplatformoffscreensurface.h> -#include <QtPlatformSupport/private/qdevicediscovery_p.h> -#include <EGL/egl.h> - -QT_BEGIN_NAMESPACE - -class QKmsScreen; -class QKmsDevice; -class QFbVtHandler; - -class QKmsOffscreenWindow : public QPlatformOffscreenSurface -{ -public: - QKmsOffscreenWindow(EGLDisplay display, const QSurfaceFormat &format, QOffscreenSurface *offscreenSurface); - ~QKmsOffscreenWindow(); - - QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; } - bool isValid() const Q_DECL_OVERRIDE { return m_surface != EGL_NO_SURFACE; } - - EGLSurface surface() const { return m_surface; } - -private: - QSurfaceFormat m_format; - EGLDisplay m_display; - EGLSurface m_surface; - EGLNativeWindowType m_window; -}; - -class QKmsIntegration : public QObject, public QPlatformIntegration -{ - Q_OBJECT - -public: - QKmsIntegration(); - ~QKmsIntegration(); - - void initialize() Q_DECL_OVERRIDE; - bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE; - - QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE; - QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE; - QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE; - QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const Q_DECL_OVERRIDE; - - QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE; - QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE; - - QPlatformNativeInterface *nativeInterface() const Q_DECL_OVERRIDE; - - void addScreen(QKmsScreen *screen); - QObject *createDevice(const char *); - -private slots: - void addDevice(const QString &deviceNode); - void removeDevice(const QString &deviceNode); - -private: - QStringList findDrmDevices(); - - QList<QPlatformScreen *> m_screens; - QList<QKmsDevice *> m_devices; - QPlatformFontDatabase *m_fontDatabase; - QPlatformNativeInterface *m_nativeInterface; - QFbVtHandler *m_vtHandler; - QDeviceDiscovery *m_deviceDiscovery; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/plugins/platforms/kms/qkmsnativeinterface.cpp b/src/plugins/platforms/kms/qkmsnativeinterface.cpp deleted file mode 100644 index 1538a7f8c3..0000000000 --- a/src/plugins/platforms/kms/qkmsnativeinterface.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <private/qguiapplication_p.h> -#include "qkmsnativeinterface.h" -#include "qkmsdevice.h" - -#include "qscreen.h" -#include "qkmscontext.h" -#include <QOpenGLContext> - -class QKmsResourceMap : public QMap<QByteArray, QKmsNativeInterface::ResourceType> -{ -public: - QKmsResourceMap() - :QMap<QByteArray, QKmsNativeInterface::ResourceType>() - { - insert("egldisplay", QKmsNativeInterface::EglDisplay); - insert("eglcontext", QKmsNativeInterface::EglContext); - } -}; - -Q_GLOBAL_STATIC(QKmsResourceMap, qKmsResourceMap) - -void *QKmsNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString) -{ - QByteArray lowerCaseResource = resourceString.toLower(); - ResourceType resource = qKmsResourceMap()->value(lowerCaseResource); - void *result = 0; - switch (resource) { - case EglDisplay: - result = eglDisplay(); - break; - default: - result = 0; - } - return result; - -} -void *QKmsNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) -{ - QByteArray lowerCaseResource = resourceString.toLower(); - ResourceType resource = qKmsResourceMap()->value(lowerCaseResource); - void *result = 0; - switch (resource) { - case EglDisplay: - result = eglDisplayForWindow(window); - break; - case EglContext: - result = eglContextForWindow(window); - break; - default: - result = 0; - } - return result; -} - -QPlatformNativeInterface::NativeResourceForContextFunction QKmsNativeInterface::nativeResourceFunctionForContext(const QByteArray &resource) -{ - QByteArray lowerCaseResource = resource.toLower(); - if (lowerCaseResource == "get_egl_context") { - return eglContextForContext; - } - return 0; -} - -void *QKmsNativeInterface::eglDisplay() -{ - //QKmsIntegration *integration = static_cast<QKmsIntegration *>(QGuiApplicationPrivate::platformIntegration()); - QKmsScreen *screen = static_cast<QKmsScreen *>(QGuiApplication::primaryScreen()->handle()); - if (!screen || !screen->device()) - return 0; - return screen->device()->eglDisplay(); -} - -void *QKmsNativeInterface::eglDisplayForWindow(QWindow *window) -{ - QKmsScreen *screen = qPlatformScreenForWindow(window); - if (!screen) - return 0; - QKmsDevice *device = screen->device(); - if (!device) - return 0; - return device->eglDisplay(); -} - -void *QKmsNativeInterface::eglContextForWindow(QWindow *) -{ - return 0; -} - -QKmsScreen *QKmsNativeInterface::qPlatformScreenForWindow(QWindow *window) -{ - QScreen *screen = window ? window->screen() : QGuiApplication::primaryScreen(); - return static_cast<QKmsScreen *>(screen->handle()); -} - -void *QKmsNativeInterface::eglContextForContext(QOpenGLContext *context) -{ - Q_ASSERT(context); - - QKmsContext *eglPlatformContext = static_cast<QKmsContext *>(context->handle()); - - return eglPlatformContext->eglContext(); -} diff --git a/src/plugins/platforms/kms/qkmsnativeinterface.h b/src/plugins/platforms/kms/qkmsnativeinterface.h deleted file mode 100644 index 56879d0a3a..0000000000 --- a/src/plugins/platforms/kms/qkmsnativeinterface.h +++ /dev/null @@ -1,64 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QKMSNATIVEINTERFACE_H -#define QKMSNATIVEINTERFACE_H - -#include "qkmsscreen.h" - -#include <qpa/qplatformnativeinterface.h> - -class QKmsNativeInterface : public QPlatformNativeInterface -{ -public: - enum ResourceType { - EglDisplay, - EglContext - }; - - void *nativeResourceForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE; - void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) Q_DECL_OVERRIDE; - - NativeResourceForContextFunction nativeResourceFunctionForContext(const QByteArray &resource) Q_DECL_OVERRIDE; - - void *eglDisplay(); - void *eglDisplayForWindow(QWindow *window); - void *eglContextForWindow(QWindow *window); - static void *eglContextForContext(QOpenGLContext *context); - -private: - static QKmsScreen *qPlatformScreenForWindow(QWindow *window); -}; - - -#endif // QKMSNATIVEINTERFACE_H diff --git a/src/plugins/platforms/kms/qkmsscreen.cpp b/src/plugins/platforms/kms/qkmsscreen.cpp deleted file mode 100644 index 6392b99cd5..0000000000 --- a/src/plugins/platforms/kms/qkmsscreen.cpp +++ /dev/null @@ -1,275 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qkmsscreen.h" -#include "qkmscursor.h" -#include "qkmsdevice.h" -#include "qkmscontext.h" - -#include <QtPlatformSupport/private/qeglconvenience_p.h> - -#include <QCoreApplication> -#include <QtDebug> - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.kms.screen") - -//Fallback mode (taken from Wayland DRM demo compositor) -static drmModeModeInfo builtin_1024x768 = { - 63500, //clock - 1024, 1072, 1176, 1328, 0, - 768, 771, 775, 798, 0, - 59920, - DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC, - 0, - "1024x768" -}; - -QKmsScreen::QKmsScreen(QKmsDevice *device, const drmModeRes *resources, const drmModeConnector *connector) - : m_device(device), - m_current_bo(0), - m_next_bo(0), - m_connectorId(connector->connector_id), - m_depth(32), - m_format(QImage::Format_Invalid), - m_eglWindowSurface(EGL_NO_SURFACE), - m_modeSet(false) -{ - m_cursor = new QKmsCursor(this); - initializeScreenMode(resources, connector); -} - -QKmsScreen::~QKmsScreen() -{ - delete m_cursor; - drmModeSetCrtc(m_device->fd(), m_oldCrtc->crtc_id, m_oldCrtc->buffer_id, - m_oldCrtc->x, m_oldCrtc->y, - &m_connectorId, 1, &m_oldCrtc->mode); - drmModeFreeCrtc(m_oldCrtc); - if (m_eglWindowSurface != EGL_NO_SURFACE) - eglDestroySurface(m_device->eglDisplay(), m_eglWindowSurface); - gbm_surface_destroy(m_gbmSurface); -} - -QRect QKmsScreen::geometry() const -{ - return m_geometry; -} - -int QKmsScreen::depth() const -{ - return m_depth; -} - -QImage::Format QKmsScreen::format() const -{ - return m_format; -} - -QSizeF QKmsScreen::physicalSize() const -{ - return m_physicalSize; -} - -QPlatformCursor *QKmsScreen::cursor() const -{ - return m_cursor; -} - -void QKmsScreen::initializeScreenMode(const drmModeRes *resources, const drmModeConnector *connector) -{ - //Determine optimal mode for screen - drmModeModeInfo *mode = 0; - for (int i = 0; i < connector->count_modes; ++i) { - if (connector->modes[i].type & DRM_MODE_TYPE_PREFERRED) { - mode = &connector->modes[i]; - break; - } - } - if (!mode) { - if (connector->count_modes > 0) - mode = &connector->modes[0]; - else - mode = &builtin_1024x768; - } - - drmModeEncoder *encoder = drmModeGetEncoder(m_device->fd(), connector->encoders[0]); - if (encoder == 0) - qFatal("No encoder for connector."); - - int i; - for (i = 0; i < resources->count_crtcs; i++) { - if (encoder->possible_crtcs & (1 << i)) - break; - } - if (i == resources->count_crtcs) - qFatal("No usable crtc for encoder."); - - m_oldCrtc = drmModeGetCrtc(m_device->fd(), encoder->crtc_id); - - m_crtcId = resources->crtcs[i]; - m_mode = *mode; - m_geometry = QRect(0, 0, m_mode.hdisplay, m_mode.vdisplay); - qCDebug(lcQpaScreen) << "kms initialized with geometry" << m_geometry; - m_depth = 32; - m_format = QImage::Format_RGB32; - m_physicalSize = QSizeF(connector->mmWidth, connector->mmHeight); - - m_gbmSurface = gbm_surface_create(m_device->gbmDevice(), - m_mode.hdisplay, m_mode.vdisplay, - GBM_BO_FORMAT_XRGB8888, - GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); - - qCDebug(lcQpaScreen) << "created gbm surface" << m_gbmSurface << m_mode.hdisplay << m_mode.vdisplay; - //Cleanup - drmModeFreeEncoder(encoder); -} - -QSurfaceFormat QKmsScreen::tweakFormat(const QSurfaceFormat &format) -{ - QSurfaceFormat fmt = format; - fmt.setRedBufferSize(8); - fmt.setGreenBufferSize(8); - fmt.setBlueBufferSize(8); - if (fmt.alphaBufferSize() != -1) - fmt.setAlphaBufferSize(8); - return fmt; -} - -void QKmsScreen::initializeWithFormat(const QSurfaceFormat &format) -{ - EGLDisplay display = m_device->eglDisplay(); - EGLConfig config = q_configFromGLFormat(display, tweakFormat(format)); - - m_eglWindowSurface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)m_gbmSurface, NULL); - qCDebug(lcQpaScreen) << "created window surface"; - m_surfaceFormat = q_glFormatFromConfig(display, config); -} - -void QKmsScreen::swapBuffers() -{ - eglSwapBuffers(m_device->eglDisplay(), m_eglWindowSurface); - - m_next_bo = gbm_surface_lock_front_buffer(m_gbmSurface); - if (!m_next_bo) - qFatal("kms: Failed to lock front buffer"); - - performPageFlip(); -} - -void QKmsScreen::performPageFlip() -{ - if (!m_next_bo) - return; - - uint32_t width = gbm_bo_get_width(m_next_bo); - uint32_t height = gbm_bo_get_height(m_next_bo); - uint32_t stride = gbm_bo_get_stride(m_next_bo); - uint32_t handle = gbm_bo_get_handle(m_next_bo).u32; - - uint32_t fb_id; - int ret = drmModeAddFB(m_device->fd(), width, height, 24, 32, - stride, handle, &fb_id); - if (ret) { - qFatal("kms: Failed to create fb: fd %d, w %d, h %d, stride %d, handle %d, ret %d", - m_device->fd(), width, height, stride, handle, ret); - } - - if (!m_modeSet) { - //Set the Mode of the screen. - int ret = drmModeSetCrtc(m_device->fd(), m_crtcId, fb_id, - 0, 0, &m_connectorId, 1, &m_mode); - if (ret) - qFatal("failed to set mode"); - m_modeSet = true; - - // Initialize cursor - - static int hideCursor = qEnvironmentVariableIntValue("QT_QPA_KMS_HIDECURSOR"); - if (!hideCursor) { - QCursor cursor(Qt::ArrowCursor); - m_cursor->changeCursor(&cursor, 0); - } - } - - int pageFlipStatus = drmModePageFlip(m_device->fd(), m_crtcId, - fb_id, - DRM_MODE_PAGE_FLIP_EVENT, this); - if (pageFlipStatus) - { - qWarning("Pageflip status: %d", pageFlipStatus); - gbm_surface_release_buffer(m_gbmSurface, m_next_bo); - m_next_bo = 0; - } -} - -void QKmsScreen::handlePageFlipped() -{ - if (m_current_bo) - gbm_surface_release_buffer(m_gbmSurface, m_current_bo); - - m_current_bo = m_next_bo; - m_next_bo = 0; -} - -QKmsDevice * QKmsScreen::device() const -{ - return m_device; -} - -void QKmsScreen::waitForPageFlipComplete() -{ - while (m_next_bo) { -#if 0 - //Check manually if there is something to be read on the device - //as there are senarios where the signal is not received (starvation) - fd_set fdSet; - timeval timeValue; - int returnValue; - - FD_ZERO(&fdSet); - FD_SET(m_device->fd(), &fdSet); - timeValue.tv_sec = 0; - timeValue.tv_usec = 1000; - - returnValue = select(1, &fdSet, 0, 0, &timeValue); - printf("select returns %d\n", returnValue); -#endif - - m_device->handlePageFlipCompleted(); - } -} - - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/kms/qkmsscreen.h b/src/plugins/platforms/kms/qkmsscreen.h deleted file mode 100644 index c52d0211b3..0000000000 --- a/src/plugins/platforms/kms/qkmsscreen.h +++ /dev/null @@ -1,122 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QKMSSCREEN_H -#define QKMSSCREEN_H - -#include <stddef.h> - -#define EGL_EGLEXT_PROTOTYPES 1 -#define GL_GLEXT_PROTOTYPES 1 - -extern "C" { -#include <gbm.h> -#include <xf86drmMode.h> -#include <xf86drm.h> -} - -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <QtGui/qopengl.h> -#include <QtGui/qsurfaceformat.h> -#include <QtCore/qloggingcategory.h> - -#include <qpa/qplatformscreen.h> - -QT_BEGIN_NAMESPACE - -Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen) - -class QKmsCursor; -class QKmsDevice; -class QKmsContext; - -class QKmsScreen : public QPlatformScreen -{ -public: - QKmsScreen(QKmsDevice *device, const drmModeRes *resources, const drmModeConnector *connector); - ~QKmsScreen(); - - QRect geometry() const Q_DECL_OVERRIDE; - int depth() const Q_DECL_OVERRIDE; - QImage::Format format() const Q_DECL_OVERRIDE; - QSizeF physicalSize() const Q_DECL_OVERRIDE; - QPlatformCursor *cursor() const Q_DECL_OVERRIDE; - - quint32 crtcId() const { return m_crtcId; } - QKmsDevice *device() const; - - void initializeWithFormat(const QSurfaceFormat &format); - - //Called by context for each screen - void swapBuffers(); - void handlePageFlipped(); - - EGLSurface eglSurface() const { return m_eglWindowSurface; } - - void waitForPageFlipComplete(); - - static QSurfaceFormat tweakFormat(const QSurfaceFormat &format); - - QSurfaceFormat surfaceFormat() const { return m_surfaceFormat; } - -private: - void performPageFlip(); - void initializeScreenMode(const drmModeRes *resources, const drmModeConnector *connector); - - QKmsDevice *m_device; - gbm_bo *m_current_bo; - gbm_bo *m_next_bo; - quint32 m_connectorId; - - quint32 m_crtcId; - drmModeModeInfo m_mode; - QRect m_geometry; - QSizeF m_physicalSize; - int m_depth; - QImage::Format m_format; - - drmModeCrtcPtr m_oldCrtc; - - QKmsCursor *m_cursor; - - gbm_surface *m_gbmSurface; - EGLSurface m_eglWindowSurface; - - bool m_modeSet; - QSurfaceFormat m_surfaceFormat; -}; - -QT_END_NAMESPACE - -#endif // QKMSSCREEN_H diff --git a/src/plugins/platforms/kms/qkmswindow.cpp b/src/plugins/platforms/kms/qkmswindow.cpp deleted file mode 100644 index 3b01dfedca..0000000000 --- a/src/plugins/platforms/kms/qkmswindow.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qkmswindow.h" -#include "qkmsscreen.h" - -#include <qpa/qwindowsysteminterface.h> -#include <qpa/qplatformwindow_p.h> - -QT_BEGIN_NAMESPACE - -QKmsWindow::QKmsWindow(QWindow *window) - : QPlatformWindow(window) -{ - Q_D(QPlatformWindow); - m_screen = QPlatformScreen::platformScreenForWindow(window); - static_cast<QKmsScreen *>(m_screen)->initializeWithFormat(window->requestedFormat()); - setGeometry(d->rect); // rect is set to window->geometry() in base ctor -} - -void QKmsWindow::setGeometry(const QRect &rect) -{ - // All windows must be fullscreen - QRect fullscreenRect = m_screen->availableGeometry(); - if (rect != fullscreenRect) - QWindowSystemInterface::handleGeometryChange(window(), fullscreenRect); - - QPlatformWindow::setGeometry(fullscreenRect); -} - -QSurfaceFormat QKmsWindow::format() const -{ - return static_cast<QKmsScreen *>(m_screen)->surfaceFormat(); -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/kms/qkmswindow.h b/src/plugins/platforms/kms/qkmswindow.h deleted file mode 100644 index aec6d55b5d..0000000000 --- a/src/plugins/platforms/kms/qkmswindow.h +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QKMSWINDOW_H -#define QKMSWINDOW_H - -#include <qpa/qplatformwindow.h> - -QT_BEGIN_NAMESPACE - -class QKmsWindow : public QPlatformWindow -{ - Q_DECLARE_PRIVATE(QPlatformWindow) - -public: - QKmsWindow(QWindow *window); - - void setGeometry(const QRect &rect) Q_DECL_OVERRIDE; - QSurfaceFormat format() const Q_DECL_OVERRIDE; - -private: - QPlatformScreen *m_screen; -}; - -QT_END_NAMESPACE - -#endif // QKMSWINDOW_H diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp index ccf86dafb2..8c8c8a15ea 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp @@ -46,6 +46,10 @@ #include <QtGui/private/qguiapplication_p.h> #include <qpa/qplatforminputcontextfactory_p.h> +#ifndef QT_NO_LIBINPUT +#include <QtPlatformSupport/private/qlibinputhandler_p.h> +#endif + #if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) #include <QtPlatformSupport/private/qevdevmousemanager_p.h> #include <QtPlatformSupport/private/qevdevkeyboardmanager_p.h> @@ -130,6 +134,13 @@ QPlatformServices *QLinuxFbIntegration::services() const void QLinuxFbIntegration::createInputHandlers() { +#ifndef QT_NO_LIBINPUT + if (!qEnvironmentVariableIntValue("QT_QPA_FB_NO_LIBINPUT")) { + new QLibInputHandler(QLatin1String("libinput"), QString()); + return; + } +#endif + #if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) new QEvdevKeyboardManager(QLatin1String("EvdevKeyboard"), QString(), this); new QEvdevMouseManager(QLatin1String("EvdevMouse"), QString(), this); diff --git a/src/plugins/platforms/windows/qwindowsclipboard.cpp b/src/plugins/platforms/windows/qwindowsclipboard.cpp index 925427ac30..97459a4d97 100644 --- a/src/plugins/platforms/windows/qwindowsclipboard.cpp +++ b/src/plugins/platforms/windows/qwindowsclipboard.cpp @@ -109,8 +109,11 @@ static QDebug operator<<(QDebug d, const QMimeData *mimeData) IDataObject *QWindowsClipboardRetrievalMimeData::retrieveDataObject() const { IDataObject * pDataObj = 0; - if (OleGetClipboard(&pDataObj) == S_OK) + if (OleGetClipboard(&pDataObj) == S_OK) { + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaMime) << __FUNCTION__ << pDataObj; return pDataObj; + } return 0; } diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 717adcc47f..4ec34c05bd 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -33,6 +33,7 @@ ****************************************************************************/ #include "qwindowscontext.h" +#include "qwindowsintegration.h" #include "qwindowswindow.h" #include "qwindowskeymapper.h" #include "qwindowsguieventdispatcher.h" @@ -907,16 +908,30 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, return true; } } + if (et & QtWindows::InputMethodEventFlag) { + QWindowsInputContext *windowsInputContext = + qobject_cast<QWindowsInputContext *>(QWindowsIntegration::instance()->inputContext()); + // Disable IME assuming this is a special implementation hooking into keyboard input. + // "Real" IME implementations should use a native event filter intercepting IME events. + if (!windowsInputContext) { + QWindowsInputContext::setWindowsImeEnabled(platformWindow, false); + return false; + } + switch (et) { + case QtWindows::InputMethodStartCompositionEvent: + return windowsInputContext->startComposition(hwnd); + case QtWindows::InputMethodCompositionEvent: + return windowsInputContext->composition(hwnd, lParam); + case QtWindows::InputMethodEndCompositionEvent: + return windowsInputContext->endComposition(hwnd); + case QtWindows::InputMethodRequest: + return windowsInputContext->handleIME_Request(wParam, lParam, result); + default: + break; + } + } // InputMethodEventFlag switch (et) { - case QtWindows::InputMethodStartCompositionEvent: - return QWindowsInputContext::instance()->startComposition(hwnd); - case QtWindows::InputMethodCompositionEvent: - return QWindowsInputContext::instance()->composition(hwnd, lParam); - case QtWindows::InputMethodEndCompositionEvent: - return QWindowsInputContext::instance()->endComposition(hwnd); - case QtWindows::InputMethodRequest: - return QWindowsInputContext::instance()->handleIME_Request(wParam, lParam, result); case QtWindows::GestureEvent: #if !defined(Q_OS_WINCE) && !defined(QT_NO_SESSIONMANAGER) return platformSessionManager()->isInteractionBlocked() ? true : d->m_mouseHandler.translateGestureEvent(platformWindow->window(), hwnd, et, msg, result); diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index 06c9985cac..e4ec3f3cf8 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -350,16 +350,16 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester: { const HDC dc = QWindowsContext::instance()->displayContext(); if (!dc){ - qWarning("%s: No Display", Q_FUNC_INFO); + qWarning("%s: No Display", __FUNCTION__); return 0; } if (!libEGL.init()) { - qWarning("%s: Failed to load and resolve libEGL functions", Q_FUNC_INFO); + qWarning("%s: Failed to load and resolve libEGL functions", __FUNCTION__); return 0; } if (!libGLESv2.init()) { - qWarning("%s: Failed to load and resolve libGLESv2 functions", Q_FUNC_INFO); + qWarning("%s: Failed to load and resolve libGLESv2 functions", __FUNCTION__); return 0; } @@ -396,15 +396,15 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester: if (display == EGL_NO_DISPLAY) display = libEGL.eglGetDisplay((EGLNativeDisplayType)dc); if (!display) { - qWarning("%s: Could not obtain EGL display", Q_FUNC_INFO); + qWarning("%s: Could not obtain EGL display", __FUNCTION__); return 0; } if (!major && !libEGL.eglInitialize(display, &major, &minor)) { int err = libEGL.eglGetError(); - qWarning("%s: Could not initialize EGL display: error 0x%x\n", Q_FUNC_INFO, err); + qWarning("%s: Could not initialize EGL display: error 0x%x", __FUNCTION__, err); if (err == 0x3001) - qWarning("%s: When using ANGLE, check if d3dcompiler_4x.dll is available", Q_FUNC_INFO); + qWarning("%s: When using ANGLE, check if d3dcompiler_4x.dll is available", __FUNCTION__); return 0; } @@ -430,7 +430,7 @@ void *QWindowsEGLStaticContext::createWindowSurface(void *nativeWindow, void *na (EGLNativeWindowType) nativeWindow, 0); if (surface == EGL_NO_SURFACE) { *err = libEGL.eglGetError(); - qWarning("%s: Could not create the EGL window surface: 0x%x\n", Q_FUNC_INFO, *err); + qWarning("%s: Could not create the EGL window surface: 0x%x", __FUNCTION__, *err); } return surface; @@ -533,7 +533,12 @@ QWindowsEGLContext::QWindowsEGLContext(QWindowsEGLStaticContext *staticContext, } if (m_eglContext == EGL_NO_CONTEXT) { - qWarning("QWindowsEGLContext: eglError: %x, this: %p \n", QWindowsEGLStaticContext::libEGL.eglGetError(), this); + int err = QWindowsEGLStaticContext::libEGL.eglGetError(); + qWarning("QWindowsEGLContext: Failed to create context, eglError: %x, this: %p", err, this); + // ANGLE gives bad alloc when it fails to reset a previously lost D3D device. + // A common cause for this is disabling the graphics adapter used by the app. + if (err == EGL_BAD_ALLOC) + qWarning("QWindowsEGLContext: Graphics device lost. (Did the adapter get disabled?)"); return; } @@ -594,6 +599,12 @@ bool QWindowsEGLContext::makeCurrent(QPlatformSurface *surface) if (err == EGL_CONTEXT_LOST) { m_eglContext = EGL_NO_CONTEXT; qCDebug(lcQpaGl) << "Got EGL context lost in createWindowSurface() for context" << this; + } else if (err == EGL_BAD_ACCESS) { + // With ANGLE this means no (D3D) device and can happen when disabling/changing graphics adapters. + qCDebug(lcQpaGl) << "Bad access (missing device?) in createWindowSurface() for context" << this; + // Simulate context loss as the context is useless. + QWindowsEGLStaticContext::libEGL.eglDestroyContext(m_eglDisplay, m_eglContext); + m_eglContext = EGL_NO_CONTEXT; } return false; } @@ -623,7 +634,7 @@ bool QWindowsEGLContext::makeCurrent(QPlatformSurface *surface) // Drop the surface. Will recreate on the next makeCurrent. window->invalidateSurface(); } else { - qWarning("QWindowsEGLContext::makeCurrent: eglError: %x, this: %p \n", err, this); + qWarning("%s: Failed to make surface current. eglError: %x, this: %p", __FUNCTION__, err, this); } } @@ -635,7 +646,8 @@ void QWindowsEGLContext::doneCurrent() QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); bool ok = QWindowsEGLStaticContext::libEGL.eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (!ok) - qWarning("QWindowsEGLContext::doneCurrent: eglError: %d, this: %p \n", QWindowsEGLStaticContext::libEGL.eglGetError(), this); + qWarning("%s: Failed to make no context/surface current. eglError: %d, this: %p", __FUNCTION__, + QWindowsEGLStaticContext::libEGL.eglGetError(), this); } void QWindowsEGLContext::swapBuffers(QPlatformSurface *surface) @@ -653,8 +665,15 @@ void QWindowsEGLContext::swapBuffers(QPlatformSurface *surface) } bool ok = QWindowsEGLStaticContext::libEGL.eglSwapBuffers(m_eglDisplay, eglSurface); - if (!ok) - qWarning("QWindowsEGLContext::swapBuffers: eglError: %d, this: %p \n", QWindowsEGLStaticContext::libEGL.eglGetError(), this); + if (!ok) { + err = QWindowsEGLStaticContext::libEGL.eglGetError(); + if (err == EGL_CONTEXT_LOST) { + m_eglContext = EGL_NO_CONTEXT; + qCDebug(lcQpaGl) << "Got EGL context lost in eglSwapBuffers()"; + } else { + qWarning("%s: Failed to swap buffers. eglError: %d, this: %p", __FUNCTION__, err, this); + } + } } QFunctionPointer QWindowsEGLContext::getProcAddress(const QByteArray &procName) diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp index 16b9118e81..3685197430 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.cpp +++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp @@ -181,9 +181,8 @@ void QWindowsFontEngine::getCMap() bool symb = false; if (ttf) { cmapTable = getSfntTable(qbswap<quint32>(MAKE_TAG('c', 'm', 'a', 'p'))); - int size = 0; cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()), - cmapTable.size(), &symb, &size); + cmapTable.size(), &symb, &cmapSize); } if (!cmap) { ttf = false; @@ -218,16 +217,16 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa QStringIterator it(str, str + numChars); while (it.hasNext()) { const uint uc = it.next(); - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc); if(!glyphs->glyphs[glyph_pos] && uc < 0x100) - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000); ++glyph_pos; } } else if (ttf) { QStringIterator it(str, str + numChars); while (it.hasNext()) { const uint uc = it.next(); - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc); ++glyph_pos; } } else { @@ -275,6 +274,7 @@ QWindowsFontEngine::QWindowsFontEngine(const QString &name, hasOutline(0), lw(0), cmap(0), + cmapSize(0), lbearing(SHRT_MIN), rbearing(SHRT_MIN), x_height(-1), @@ -346,11 +346,11 @@ glyph_t QWindowsFontEngine::glyphIndex(uint ucs4) const #if !defined(Q_OS_WINCE) if (symbol) { - glyph = getTrueTypeGlyphIndex(cmap, ucs4); + glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4); if (glyph == 0 && ucs4 < 0x100) - glyph = getTrueTypeGlyphIndex(cmap, ucs4 + 0xf000); + glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000); } else if (ttf) { - glyph = getTrueTypeGlyphIndex(cmap, ucs4); + glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4); #else if (tm.tmFirstChar > 60000) { glyph = ucs4; diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h index 6df69c34db..409b44264e 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.h +++ b/src/plugins/platforms/windows/qwindowsfontengine.h @@ -146,6 +146,7 @@ private: TEXTMETRIC tm; int lw; const unsigned char *cmap; + int cmapSize; QByteArray cmapTable; mutable qreal lbearing; mutable qreal rbearing; diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index 485b876fc7..e016b84bba 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -199,32 +199,44 @@ void QWindowsInputContext::reset() doneContext(); } -void QWindowsInputContext::setFocusObject(QObject *object) +void QWindowsInputContext::setFocusObject(QObject *) { // ### fixme: On Windows 8.1, it has been observed that the Input context // remains active when this happens resulting in a lock-up. Consecutive // key events still have VK_PROCESSKEY set and are thus ignored. if (m_compositionContext.isComposing) - imeNotifyCancelComposition(m_compositionContext.hwnd); + reset(); + updateEnabled(); +} +void QWindowsInputContext::updateEnabled() +{ + if (!QGuiApplication::focusObject()) + return; const QWindow *window = QGuiApplication::focusWindow(); - if (object && window && window->handle()) { + if (window && window->handle()) { QWindowsWindow *platformWindow = QWindowsWindow::baseWindowOf(window); - if (inputMethodAccepted()) { - // Re-enable IME by associating default context saved on first disabling. - if (platformWindow->testFlag(QWindowsWindow::InputMethodDisabled)) { - ImmAssociateContext(platformWindow->handle(), QWindowsInputContext::m_defaultContext); - platformWindow->clearFlag(QWindowsWindow::InputMethodDisabled); - } - } else { - // Disable IME by associating 0 context. Store context first time. - if (!platformWindow->testFlag(QWindowsWindow::InputMethodDisabled)) { - const HIMC oldImC = ImmAssociateContext(platformWindow->handle(), 0); - platformWindow->setFlag(QWindowsWindow::InputMethodDisabled); - if (!QWindowsInputContext::m_defaultContext && oldImC) - QWindowsInputContext::m_defaultContext = oldImC; - } - } + const bool accepted = inputMethodAccepted(); + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaInputMethods) << __FUNCTION__ << window << "accepted=" << accepted; + QWindowsInputContext::setWindowsImeEnabled(platformWindow, accepted); + } +} + +void QWindowsInputContext::setWindowsImeEnabled(QWindowsWindow *platformWindow, bool enabled) +{ + if (!platformWindow || platformWindow->testFlag(QWindowsWindow::InputMethodDisabled) == !enabled) + return; + if (enabled) { + // Re-enable Windows IME by associating default context saved on first disabling. + ImmAssociateContext(platformWindow->handle(), QWindowsInputContext::m_defaultContext); + platformWindow->clearFlag(QWindowsWindow::InputMethodDisabled); + } else { + // Disable Windows IME by associating 0 context. Store context first time. + const HIMC oldImC = ImmAssociateContext(platformWindow->handle(), 0); + platformWindow->setFlag(QWindowsWindow::InputMethodDisabled); + if (!QWindowsInputContext::m_defaultContext && oldImC) + QWindowsInputContext::m_defaultContext = oldImC; } } @@ -234,6 +246,8 @@ void QWindowsInputContext::setFocusObject(QObject *object) void QWindowsInputContext::update(Qt::InputMethodQueries queries) { + if (queries & Qt::ImEnabled) + updateEnabled(); QPlatformInputContext::update(queries); } @@ -295,11 +309,6 @@ void QWindowsInputContext::invokeAction(QInputMethod::Action action, int cursorP ImmReleaseContext(m_compositionContext.hwnd, himc); } -QWindowsInputContext *QWindowsInputContext::instance() -{ - return static_cast<QWindowsInputContext *>(QWindowsIntegration::instance()->inputContext()); -} - static inline QString getCompositionString(HIMC himc, DWORD dwIndex) { enum { bufferSize = 256 }; diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.h b/src/plugins/platforms/windows/qwindowsinputcontext.h index 83a39989f6..eb4e3a3faa 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.h +++ b/src/plugins/platforms/windows/qwindowsinputcontext.h @@ -42,6 +42,7 @@ QT_BEGIN_NAMESPACE class QInputMethodEvent; +class QWindowsWindow; class QWindowsInputContext : public QPlatformInputContext { @@ -62,14 +63,14 @@ public: explicit QWindowsInputContext(); ~QWindowsInputContext(); + static void setWindowsImeEnabled(QWindowsWindow *platformWindow, bool enabled); + bool hasCapability(Capability capability) const Q_DECL_OVERRIDE; void reset() Q_DECL_OVERRIDE; void update(Qt::InputMethodQueries) Q_DECL_OVERRIDE; void invokeAction(QInputMethod::Action, int cursorPosition) Q_DECL_OVERRIDE; void setFocusObject(QObject *object) Q_DECL_OVERRIDE; - static QWindowsInputContext *instance(); - bool startComposition(HWND hwnd); bool composition(HWND hwnd, LPARAM lParam); bool endComposition(HWND hwnd); @@ -87,6 +88,7 @@ private: void doneContext(); void startContextComposition(); void endContextComposition(); + void updateEnabled(); const DWORD m_WM_MSIME_MOUSE; static HIMC m_defaultContext; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 081a800913..402ab9ad71 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -266,10 +266,9 @@ QWindowsIntegration::~QWindowsIntegration() void QWindowsIntegration::initialize() { - if (QPlatformInputContext *pluginContext = QPlatformInputContextFactory::create()) - d->m_inputContext.reset(pluginContext); - else - d->m_inputContext.reset(new QWindowsInputContext); + QString icStr = QPlatformInputContextFactory::requested(); + icStr.isNull() ? d->m_inputContext.reset(new QWindowsInputContext) + : d->m_inputContext.reset(QPlatformInputContextFactory::create(icStr)); } bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) const diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index 3636bb7893..f8e2ded228 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -33,6 +33,7 @@ #include "qwindowskeymapper.h" #include "qwindowscontext.h" +#include "qwindowsintegration.h" #include "qwindowswindow.h" #include "qwindowsguieventdispatcher.h" #include "qwindowsinputcontext.h" @@ -1074,7 +1075,9 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms // results, if we map this virtual key-code directly (for eg '?' US layouts). So try // to find the correct key using the current message parameters & keyboard state. if (uch.isNull() && msgType == WM_IME_KEYDOWN) { - if (!QWindowsInputContext::instance()->isComposing()) + const QWindowsInputContext *windowsInputContext = + qobject_cast<const QWindowsInputContext *>(QWindowsIntegration::instance()->inputContext()); + if (!(windowsInputContext && windowsInputContext->isComposing())) vk_key = ImmGetVirtualKey((HWND)window->winId()); BYTE keyState[256]; wchar_t newKey[3] = {0}; diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp index f86ab9fee3..375a7f11db 100644 --- a/src/plugins/platforms/windows/qwindowsmime.cpp +++ b/src/plugins/platforms/windows/qwindowsmime.cpp @@ -299,8 +299,6 @@ static bool qt_read_dibv5(QDataStream &s, QImage &image) return true; } -//#define QMIME_DEBUG - // helpers for using global memory static int getCf(const FORMATETC &formatetc) @@ -380,6 +378,73 @@ static bool canGetData(int cf, IDataObject * pDataObj) return true; } +#ifndef QT_NO_DEBUG_OUTPUT +QDebug operator<<(QDebug d, const FORMATETC &tc) +{ + QDebugStateSaver saver(d); + d.nospace(); + d << "FORMATETC(cfFormat=" << tc.cfFormat << ' '; + switch (tc.cfFormat) { + case CF_TEXT: + d << "CF_TEXT"; + break; + case CF_BITMAP: + d << "CF_BITMAP"; + break; + case CF_TIFF: + d << "CF_TIFF"; + break; + case CF_OEMTEXT: + d << "CF_OEMTEXT"; + break; + case CF_DIB: + d << "CF_DIB"; + break; + case CF_DIBV5: + d << "CF_DIBV5"; + break; + case CF_UNICODETEXT: + d << "CF_UNICODETEXT"; + break; +#ifndef Q_OS_WINCE + case CF_ENHMETAFILE: + d << "CF_ENHMETAFILE"; + break; +#endif // !Q_OS_WINCE + default: + d << QWindowsMimeConverter::clipboardFormatName(tc.cfFormat); + break; + } + d << ", dwAspect=" << tc.dwAspect << ", lindex=" << tc.lindex + << ", tymed=" << tc.tymed << ", ptd=" << tc.ptd << ')'; + return d; +} + +QDebug operator<<(QDebug d, IDataObject *dataObj) +{ + QDebugStateSaver saver(d); + d.nospace(); + d.noquote(); + d << "IDataObject("; + if (dataObj) { // Output formats contained in IDataObject. + IEnumFORMATETC *enumFormatEtc; + if (SUCCEEDED(dataObj->EnumFormatEtc(DATADIR_GET, &enumFormatEtc)) && enumFormatEtc) { + FORMATETC formatEtc[1]; + ULONG fetched; + if (SUCCEEDED(enumFormatEtc->Reset())) { + while (SUCCEEDED(enumFormatEtc->Next(1, formatEtc, &fetched)) && fetched) + d << formatEtc[0] << ','; + enumFormatEtc->Release(); + } + } + } else { + d << '0'; + } + d << ')'; + return d; +} +#endif // !QT_NO_DEBUG_OUTPUT + /*! \class QWindowsMime \brief The QWindowsMime class maps open-standard MIME to Window Clipboard formats. @@ -894,11 +959,7 @@ QVariant QWindowsMimeHtml::convertToMime(const QString &mime, IDataObject *pData QVariant result; if (canConvertToMime(mime, pDataObj)) { QByteArray html = getData(CF_HTML, pDataObj); -#ifdef QMIME_DEBUG - qDebug("QWindowsMimeHtml::convertToMime"); - qDebug("raw :"); - qDebug(html); -#endif + qCDebug(lcQpaMime) << __FUNCTION__ << "raw:" << html; int start = html.indexOf("StartHTML:"); int end = html.indexOf("EndHTML:"); @@ -990,13 +1051,14 @@ QVector<FORMATETC> QWindowsMimeImage::formatsForMime(const QString &mimeType, co { QVector<FORMATETC> formatetcs; if (mimeData->hasImage() && mimeType == QLatin1String("application/x-qt-image")) { - //add DIBV5 if image has alpha channel + //add DIBV5 if image has alpha channel. Do not add CF_PNG here as it will confuse MS Office (QTBUG47656). QImage image = qvariant_cast<QImage>(mimeData->imageData()); if (!image.isNull() && image.hasAlphaChannel()) formatetcs += setCf(CF_DIBV5); formatetcs += setCf(CF_DIB); - formatetcs += setCf(CF_PNG); // QTBUG-86848, Paste into GIMP queries for PNG. } + if (!formatetcs.isEmpty()) + qCDebug(lcQpaMime) << __FUNCTION__ << mimeType << formatetcs; return formatetcs; } @@ -1024,11 +1086,7 @@ bool QWindowsMimeImage::canConvertFromMime(const FORMATETC &formatetc, const QMi const QImage image = qvariant_cast<QImage>(mimeData->imageData()); if (image.isNull()) return false; - // QTBUG-11463, deny CF_DIB support for images with alpha to prevent loss of - // transparency in conversion. - return cf == CF_DIBV5 - || (cf == CF_DIB && !image.hasAlphaChannel()) - || cf == int(CF_PNG); + return cf == CF_DIBV5 || (cf == CF_DIB) || cf == int(CF_PNG); } bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const @@ -1221,9 +1279,7 @@ QVariant QBuiltInMimes::convertToMime(const QString &mimeType, IDataObject *pDat if (canConvertToMime(mimeType, pDataObj)) { QByteArray data = getData(inFormats.key(mimeType), pDataObj); if (!data.isEmpty()) { -#ifdef QMIME_DEBUG - qDebug("QBuiltInMimes::convertToMime()"); -#endif + qCDebug(lcQpaMime) << __FUNCTION__; if (mimeType == QLatin1String("text/html") && preferredType == QVariant::String) { // text/html is in wide chars on windows (compatible with Mozilla) val = QString::fromWCharArray((const wchar_t *)data.data()); @@ -1331,6 +1387,8 @@ QVector<FORMATETC> QLastResortMimes::formatsForMime(const QString &mimeType, con that->formats.insert(cf, mimeType); formatetcs += setCf(cf); } + if (!formatetcs.isEmpty()) + qCDebug(lcQpaMime) << __FUNCTION__ << mimeType << formatetcs; return formatetcs; } static const char x_qt_windows_mime[] = "application/x-qt-windows-mime;value=\""; @@ -1405,11 +1463,8 @@ QString QLastResortMimes::mimeForFormat(const FORMATETC &formatetc) const if (!format.isEmpty()) return format; - wchar_t buffer[256]; - int len = GetClipboardFormatName(getCf(formatetc), buffer, 256); - - if (len) { - QString clipFormat = QString::fromWCharArray(buffer, len); + const QString clipFormat = QWindowsMimeConverter::clipboardFormatName(getCf(formatetc)); + if (!clipFormat.isEmpty()) { #ifndef QT_NO_DRAGANDDROP if (QInternalMimeData::canReadData(clipFormat)) format = clipFormat; @@ -1475,15 +1530,12 @@ QStringList QWindowsMimeConverter::allMimesForFormats(IDataObject *pDataObj) con if (hr == NOERROR) { FORMATETC fmtetc; while (S_OK == fmtenum->Next(1, &fmtetc, 0)) { -#if defined(QMIME_DEBUG) - wchar_t buf[256] = {0}; - GetClipboardFormatName(fmtetc.cfFormat, buf, 255); - qDebug("CF = %d : %s", fmtetc.cfFormat, qPrintable(QString::fromWCharArray(buf))); -#endif for (int i= m_mimes.size() - 1; i >= 0; --i) { QString format = m_mimes.at(i)->mimeForFormat(fmtetc); if (!format.isEmpty() && !formats.contains(format)) { formats += format; + if (QWindowsContext::verbose > 1 && lcQpaMime().isDebugEnabled()) + qCDebug(lcQpaMime) << __FUNCTION__ << fmtetc << format; } } // as documented in MSDN to avoid possible memleak @@ -1499,6 +1551,7 @@ QStringList QWindowsMimeConverter::allMimesForFormats(IDataObject *pDataObj) con QWindowsMime * QWindowsMimeConverter::converterFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const { ensureInitialized(); + qCDebug(lcQpaMime) << __FUNCTION__ << formatetc; for (int i = m_mimes.size()-1; i >= 0; --i) { if (m_mimes.at(i)->canConvertFromMime(formatetc, mimeData)) return m_mimes.at(i); @@ -1533,6 +1586,13 @@ void QWindowsMimeConverter::ensureInitialized() const } } +QString QWindowsMimeConverter::clipboardFormatName(int cf) +{ + wchar_t buf[256] = {0}; + return GetClipboardFormatName(cf, buf, 255) + ? QString::fromWCharArray(buf) : QString(); +} + QVariant QWindowsMimeConverter::convertToMime(const QStringList &mimeTypes, IDataObject *pDataObj, QVariant::Type preferredType, diff --git a/src/plugins/platforms/windows/qwindowsmime.h b/src/plugins/platforms/windows/qwindowsmime.h index 952410e14b..17fddef1bc 100644 --- a/src/plugins/platforms/windows/qwindowsmime.h +++ b/src/plugins/platforms/windows/qwindowsmime.h @@ -42,6 +42,7 @@ QT_BEGIN_NAMESPACE +class QDebug; class QMimeData; class QWindowsMime @@ -83,6 +84,8 @@ public: void registerMime(QWindowsMime *mime); void unregisterMime(QWindowsMime *mime) { m_mimes.removeOne(mime); } + static QString clipboardFormatName(int cf); + private: void ensureInitialized() const; @@ -90,6 +93,11 @@ private: mutable int m_internalMimeCount; }; +#ifndef QT_NO_DEBUG_OUTPUT +QDebug operator<<(QDebug, const FORMATETC &); +QDebug operator<<(QDebug d, IDataObject *); +#endif + QT_END_NAMESPACE #endif // QWINDOWSMIME_H diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index 200eb11855..90cb6fe195 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -368,7 +368,10 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, QWindowsKeyMapper::queryKeyboardModifiers(), source); m_previousCaptureWindow = hasCapture ? window : 0; - return true; + // QTBUG-48117, force synchronous handling for the extra buttons so that WM_APPCOMMAND + // is sent for unhandled WM_XBUTTONDOWN. + return (msg.message != WM_XBUTTONUP && msg.message != WM_XBUTTONDOWN && msg.message != WM_XBUTTONDBLCLK) + || QWindowSystemInterface::flushWindowSystemEvents(); } static bool isValidWheelReceiver(QWindow *candidate) @@ -474,7 +477,12 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND, typedef QList<QWindowSystemInterface::TouchPoint> QTouchPointList; Q_ASSERT(m_touchDevice); - const QRect screenGeometry = window->screen()->geometry(); + const QScreen *screen = window->screen(); + if (!screen) + screen = QGuiApplication::primaryScreen(); + if (!screen) + return true; + const QRect screenGeometry = screen->geometry(); const int winTouchPointCount = msg.wParam; QScopedArrayPointer<TOUCHINPUT> winTouchInputs(new TOUCHINPUT[winTouchPointCount]); @@ -566,7 +574,12 @@ bool QWindowsMouseHandler::translateGestureEvent(QWindow *window, HWND hwnd, if (gi.dwID != GID_DIRECTMANIPULATION) return true; static QPoint lastTouchPos; - const QRect screenGeometry = window->screen()->geometry(); + const QScreen *screen = window->screen(); + if (!screen) + screen = QGuiApplication::primaryScreen(); + if (!screen) + return true; + const QRect screenGeometry = screen->geometry(); QWindowSystemInterface::TouchPoint touchPoint; static QWindowSystemInterface::TouchPoint touchPoint2; touchPoint.id = 0;//gi.dwInstanceID; diff --git a/src/plugins/platforms/windows/qwindowsole.cpp b/src/plugins/platforms/windows/qwindowsole.cpp index 6f5a521af8..e480c1ebcf 100644 --- a/src/plugins/platforms/windows/qwindowsole.cpp +++ b/src/plugins/platforms/windows/qwindowsole.cpp @@ -132,12 +132,6 @@ QWindowsOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium) { HRESULT hr = ResultFromScode(DATA_E_FORMATETC); - if (QWindowsContext::verbose > 1 && lcQpaMime().isDebugEnabled()) { - wchar_t buf[256] = {0}; - GetClipboardFormatName(pformatetc->cfFormat, buf, 255); - qCDebug(lcQpaMime) <<__FUNCTION__ << "CF = " << pformatetc->cfFormat << QString::fromWCharArray(buf); - } - if (data) { const QWindowsMimeConverter &mc = QWindowsContext::instance()->mimeConverter(); if (QWindowsMime *converter = mc.converterFromMime(*pformatetc, data)) @@ -145,11 +139,8 @@ QWindowsOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium) hr = ResultFromScode(S_OK); } - if (QWindowsContext::verbose > 1) { - wchar_t buf[256] = {0}; - GetClipboardFormatName(pformatetc->cfFormat, buf, 255); - qCDebug(lcQpaMime) <<__FUNCTION__ << "CF = " << pformatetc->cfFormat << " returns 0x" << int(hr) << dec; - } + if (QWindowsContext::verbose > 1 && lcQpaMime().isDebugEnabled()) + qCDebug(lcQpaMime) <<__FUNCTION__ << *pformatetc << "returns" << hex << showbase << quint64(hr); return hr; } @@ -211,7 +202,7 @@ STDMETHODIMP QWindowsOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc) { if (QWindowsContext::verbose > 1) - qCDebug(lcQpaMime) << __FUNCTION__; + qCDebug(lcQpaMime) << __FUNCTION__ << "dwDirection=" << dwDirection; if (!data) return ResultFromScode(DATA_E_FORMATETC); @@ -274,7 +265,7 @@ QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs) m_dwRefs(1), m_nIndex(0), m_isNull(false) { if (QWindowsContext::verbose > 1) - qCDebug(lcQpaMime) << __FUNCTION__; + qCDebug(lcQpaMime) << __FUNCTION__ << fmtetcs; m_lpfmtetcs.reserve(fmtetcs.count()); for (int idx = 0; idx < fmtetcs.count(); ++idx) { LPFORMATETC destetc = new FORMATETC(); diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 391735a035..e6abfb2403 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -276,18 +276,6 @@ QWindow *QWindowsScreen::windowAt(const QPoint &screenPoint, unsigned flags) return result; } -QWindowsScreen *QWindowsScreen::screenOf(const QWindow *w) -{ - if (w) - if (const QScreen *s = w->screen()) - if (QPlatformScreen *pscr = s->handle()) - return static_cast<QWindowsScreen *>(pscr); - if (const QScreen *ps = QGuiApplication::primaryScreen()) - if (QPlatformScreen *ppscr = ps->handle()) - return static_cast<QWindowsScreen *>(ppscr); - return 0; -} - qreal QWindowsScreen::pixelDensity() const { const qreal physicalDpi = m_data.geometry.width() / m_data.physicalSizeMM.width() * qreal(25.4); diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index 67e7ff644b..bc8fbf553b 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -79,8 +79,6 @@ public: explicit QWindowsScreen(const QWindowsScreenData &data); - static QWindowsScreen *screenOf(const QWindow *w = 0); - QRect geometry() const Q_DECL_OVERRIDE { return m_data.geometry; } QRect availableGeometry() const Q_DECL_OVERRIDE { return m_data.availableGeometry; } int depth() const Q_DECL_OVERRIDE { return m_data.depth; } diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp index 05bddec530..3951401273 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp +++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp @@ -54,7 +54,7 @@ #include <QtCore/private/qsystemlibrary_p.h> // Note: The definition of the PACKET structure in pktdef.h depends on this define. -#define PACKETDATA (PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION | PK_CURSOR | PK_Z) +#define PACKETDATA (PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION | PK_CURSOR | PK_Z | PK_TIME) #include <pktdef.h> QT_BEGIN_NAMESPACE @@ -342,17 +342,18 @@ QWindowsTabletDeviceData QWindowsTabletSupport::tabletInit(const quint64 uniqueI bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, LPARAM lParam) { + PACKET proximityBuffer[1]; // we are only interested in the first packet in this case + const int totalPacks = QWindowsTabletSupport::m_winTab32DLL.wTPacketsGet(m_context, 1, proximityBuffer); + if (!totalPacks) + return false; if (!LOWORD(lParam)) { qCDebug(lcQpaTablet) << "leave proximity for device #" << m_currentDevice; - QWindowSystemInterface::handleTabletLeaveProximityEvent(m_devices.at(m_currentDevice).currentDevice, + QWindowSystemInterface::handleTabletLeaveProximityEvent(proximityBuffer[0].pkTime, + m_devices.at(m_currentDevice).currentDevice, m_devices.at(m_currentDevice).currentPointerType, m_devices.at(m_currentDevice).uniqueId); return true; } - PACKET proximityBuffer[1]; // we are only interested in the first packet in this case - const int totalPacks = QWindowsTabletSupport::m_winTab32DLL.wTPacketsGet(m_context, 1, proximityBuffer); - if (!totalPacks) - return false; const UINT currentCursor = proximityBuffer[0].pkCursor; UINT physicalCursorId; QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_PHYSID, &physicalCursorId); @@ -370,7 +371,8 @@ bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, L m_devices[m_currentDevice].currentPointerType = pointerType(currentCursor); qCDebug(lcQpaTablet) << "enter proximity for device #" << m_currentDevice << m_devices.at(m_currentDevice); - QWindowSystemInterface::handleTabletEnterProximityEvent(m_devices.at(m_currentDevice).currentDevice, + QWindowSystemInterface::handleTabletEnterProximityEvent(proximityBuffer[0].pkTime, + m_devices.at(m_currentDevice).currentDevice, m_devices.at(m_currentDevice).currentPointerType, m_devices.at(m_currentDevice).uniqueId); return true; @@ -473,7 +475,7 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() << tiltY << "tanP:" << tangentialPressure << "rotation:" << rotation; } - QWindowSystemInterface::handleTabletEvent(target, QPointF(localPos), globalPosF, + QWindowSystemInterface::handleTabletEvent(target, packet.pkTime, QPointF(localPos), globalPosF, currentDevice, currentPointer, static_cast<Qt::MouseButtons>(packet.pkButtons), pressureNew, tiltX, tiltY, diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 1b5d7b87bc..abfddcfed6 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1045,8 +1045,8 @@ void QWindowsWindow::setDropSiteEnabled(bool dropEnabled) RegisterDragDrop(m_data.hwnd, m_dropTarget); CoLockObjectExternal(m_dropTarget, true, true); } else { - m_dropTarget->Release(); CoLockObjectExternal(m_dropTarget, false, true); + m_dropTarget->Release(); RevokeDragDrop(m_data.hwnd); m_dropTarget = 0; } @@ -1637,8 +1637,12 @@ void QWindowsWindow::setWindowState(Qt::WindowState state) bool QWindowsWindow::isFullScreen_sys() const { const QWindow *w = window(); - return w->isTopLevel() - && geometry_sys() == QHighDpi::toNativePixels(w->screen()->geometry(), w); + if (!w->isTopLevel()) + return false; + const QScreen *screen = w->screen(); + if (!screen) + screen = QGuiApplication::primaryScreen(); + return screen && geometry_sys() == QHighDpi::toNativePixels(screen->geometry(), w); } /*! @@ -1708,7 +1712,9 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) // Use geometry of QWindow::screen() within creation or the virtual screen the // window is in (QTBUG-31166, QTBUG-30724). const QScreen *screen = window()->screen(); - const QRect r = QHighDpi::toNativePixels(screen->geometry(), window()); + if (!screen) + screen = QGuiApplication::primaryScreen(); + const QRect r = screen ? QHighDpi::toNativePixels(screen->geometry(), window()) : m_savedFrameGeometry; const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE; const bool wasSync = testFlag(SynchronousGeometryChangeEvent); setFlag(SynchronousGeometryChangeEvent); @@ -1825,7 +1831,7 @@ bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow * const QRect suggestedFrameGeometry(windowPos->x, windowPos->y, windowPos->cx, windowPos->cy); const QRect suggestedGeometry = suggestedFrameGeometry - margins; - const QRectF correctedGeometryF = qWindow->handle()->windowClosestAcceptableGeometry(suggestedGeometry); + const QRectF correctedGeometryF = QPlatformWindow::closestAcceptableGeometry(qWindow, suggestedGeometry); if (!correctedGeometryF.isValid()) return false; const QRect correctedFrameGeometry = correctedGeometryF.toRect() + margins; diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.cpp b/src/plugins/platforms/winrt/qwinrteglcontext.cpp index 44aab266ca..9cb45336d6 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrteglcontext.cpp @@ -56,7 +56,6 @@ public: EGLDisplay eglDisplay; EGLConfig eglConfig; EGLContext eglContext; - QHash<QPlatformSurface *, EGLSurface> surfaceForWindow; }; QWinRTEGLContext::QWinRTEGLContext(QOpenGLContext *context) @@ -70,8 +69,6 @@ QWinRTEGLContext::QWinRTEGLContext(QOpenGLContext *context) QWinRTEGLContext::~QWinRTEGLContext() { Q_D(QWinRTEGLContext); - foreach (const EGLSurface &surface, d->surfaceForWindow) - eglDestroySurface(d->eglDisplay, surface); if (d->eglContext != EGL_NO_CONTEXT) eglDestroyContext(d->eglDisplay, d->eglContext); if (d->eglDisplay != EGL_NO_DISPLAY) @@ -112,23 +109,13 @@ bool QWinRTEGLContext::makeCurrent(QPlatformSurface *windowSurface) Q_D(QWinRTEGLContext); Q_ASSERT(windowSurface->surface()->surfaceType() == QSurface::OpenGLSurface); - EGLSurface surface = d->surfaceForWindow.value(windowSurface); - if (surface == EGL_NO_SURFACE) { - QWinRTWindow *window = static_cast<QWinRTWindow *>(windowSurface); - HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([this, d, window, &surface]() { - surface = eglCreateWindowSurface(d->eglDisplay, d->eglConfig, - reinterpret_cast<EGLNativeWindowType>(window->winId()), - nullptr); - if (surface == EGL_NO_SURFACE) { - qCritical("Failed to create EGL window surface: 0x%x", eglGetError()); - return E_FAIL; - } - return S_OK; - }); - if (FAILED(hr)) - return false; - d->surfaceForWindow.insert(windowSurface, surface); - } + QWinRTWindow *window = static_cast<QWinRTWindow *>(windowSurface); + if (window->eglSurface() == EGL_NO_SURFACE) + window->createEglSurface(d->eglDisplay, d->eglConfig); + + EGLSurface surface = window->eglSurface(); + if (surface == EGL_NO_SURFACE) + return false; const bool ok = eglMakeCurrent(d->eglDisplay, surface, surface, d->eglContext); if (!ok) { @@ -153,7 +140,8 @@ void QWinRTEGLContext::swapBuffers(QPlatformSurface *windowSurface) Q_D(QWinRTEGLContext); Q_ASSERT(windowSurface->surface()->surfaceType() == QSurface::OpenGLSurface); - eglSwapBuffers(d->eglDisplay, d->surfaceForWindow.value(windowSurface)); + const QWinRTWindow *window = static_cast<QWinRTWindow *>(windowSurface); + eglSwapBuffers(d->eglDisplay, window->eglSurface()); } QSurfaceFormat QWinRTEGLContext::format() const diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp index e1b2a07d5f..05b1fd76b1 100644 --- a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp +++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp @@ -37,25 +37,32 @@ #include "qwinrtfiledialoghelper.h" #include "qwinrtfileengine.h" +#include <QtCore/qcoreapplication.h> #include <QtCore/QEventLoop> #include <QtCore/QMap> #include <QtCore/QVector> #include <QtCore/qfunctions_winrt.h> +#include <private/qeventdispatcher_winrt_p.h> +#include <functional> #include <wrl.h> #include <windows.foundation.h> #include <windows.storage.pickers.h> +#include <Windows.ApplicationModel.activation.h> using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::ApplicationModel::Activation; using namespace ABI::Windows::Foundation; using namespace ABI::Windows::Foundation::Collections; using namespace ABI::Windows::Storage; using namespace ABI::Windows::Storage::Pickers; +#ifndef Q_OS_WINPHONE typedef IAsyncOperationCompletedHandler<StorageFile *> SingleFileHandler; typedef IAsyncOperationCompletedHandler<IVectorView<StorageFile *> *> MultipleFileHandler; typedef IAsyncOperationCompletedHandler<StorageFolder *> SingleFolderHandler; +#endif QT_BEGIN_NAMESPACE @@ -142,6 +149,16 @@ private: QVector<HSTRING> impl; }; +#ifdef Q_OS_WINPHONE +class QActivationEvent : public QEvent +{ +public: + IInspectable *args() const { + return reinterpret_cast<IInspectable *>(d); + } +}; +#endif + template<typename T> static bool initializePicker(HSTRING runtimeId, T **picker, const QSharedPointer<QFileDialogOptions> &options) { @@ -200,6 +217,99 @@ static bool initializeOpenPickerOptions(T *picker, const QSharedPointer<QFileDia return true; } +static bool pickFiles(IFileOpenPicker *picker, QWinRTFileDialogHelper *helper, bool singleFile) +{ + Q_ASSERT(picker); + Q_ASSERT(helper); + HRESULT hr; +#ifdef Q_OS_WINPHONE + hr = QEventDispatcherWinRT::runOnXamlThread([picker, singleFile]() { + HRESULT hr; + ComPtr<IFileOpenPicker2> picker2; + hr = picker->QueryInterface(IID_PPV_ARGS(picker2.GetAddressOf())); + RETURN_HR_IF_FAILED("Failed to cast file picker"); + if (singleFile) + return picker2->PickSingleFileAndContinue(); + else + return picker2->PickMultipleFilesAndContinue(); + }); + RETURN_FALSE_IF_FAILED("Failed to open file picker"); + QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher(); + Q_ASSERT(eventDispatcher); + eventDispatcher->installEventFilter(helper); + return true; +#else + if (singleFile) { + ComPtr<IAsyncOperation<StorageFile *>> op; + hr = picker->PickSingleFileAsync(&op); + RETURN_FALSE_IF_FAILED("Failed to open single file picker"); + hr = op->put_Completed(Callback<SingleFileHandler>(helper, &QWinRTFileDialogHelper::onSingleFilePicked).Get()); + RETURN_FALSE_IF_FAILED("Failed to attach file picker callback"); + } else { + ComPtr<IAsyncOperation<IVectorView<StorageFile *> *>> op; + hr = picker->PickMultipleFilesAsync(&op); + RETURN_FALSE_IF_FAILED("Failed to open multi file picker"); + hr = op->put_Completed(Callback<MultipleFileHandler>(helper, &QWinRTFileDialogHelper::onMultipleFilesPicked).Get()); + RETURN_FALSE_IF_FAILED("Failed to attach multi file callback"); + } + return true; +#endif +} + +static bool pickFolder(IFolderPicker *picker, QWinRTFileDialogHelper *helper) +{ + Q_ASSERT(picker); + Q_ASSERT(helper); + HRESULT hr; +#ifdef Q_OS_WINPHONE + hr = QEventDispatcherWinRT::runOnXamlThread([picker]() { + HRESULT hr; + ComPtr<IFolderPicker2> picker2; + hr = picker->QueryInterface(IID_PPV_ARGS(picker2.GetAddressOf())); + RETURN_HR_IF_FAILED("Failed to cast folder picker"); + return picker2->PickFolderAndContinue(); + }); + RETURN_FALSE_IF_FAILED("Failed to open folder picker"); + QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher(); + Q_ASSERT(eventDispatcher); + eventDispatcher->installEventFilter(helper); +#else + ComPtr<IAsyncOperation<StorageFolder *>> op; + hr = picker->PickSingleFolderAsync(&op); + RETURN_FALSE_IF_FAILED("Failed to open folder picker"); + hr = op->put_Completed(Callback<SingleFolderHandler>(helper, &QWinRTFileDialogHelper::onSingleFolderPicked).Get()); + RETURN_FALSE_IF_FAILED("Failed to attach folder picker callback"); +#endif + return true; +} + +static bool pickSaveFile(IFileSavePicker *picker, QWinRTFileDialogHelper *helper) +{ + Q_ASSERT(picker); + Q_ASSERT(helper); + HRESULT hr; +#ifdef Q_OS_WINPHONE + hr = QEventDispatcherWinRT::runOnXamlThread([picker]() { + HRESULT hr; + ComPtr<IFileSavePicker2> picker2; + hr = picker->QueryInterface(IID_PPV_ARGS(picker2.GetAddressOf())); + RETURN_HR_IF_FAILED("Failed to cast save file picker"); + return picker2->PickSaveFileAndContinue(); + }); + RETURN_FALSE_IF_FAILED("Failed to open single file picker"); + QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher(); + Q_ASSERT(eventDispatcher); + eventDispatcher->installEventFilter(helper); +#else + ComPtr<IAsyncOperation<StorageFile *>> op; + hr = picker->PickSaveFileAsync(&op); + RETURN_FALSE_IF_FAILED("Failed to open save file picker"); + hr = op->put_Completed(Callback<SingleFileHandler>(helper, &QWinRTFileDialogHelper::onSingleFilePicked).Get()); + RETURN_FALSE_IF_FAILED("Failed to attach save file picker callback"); +#endif + return true; +} + class QWinRTFileDialogHelperPrivate { public: @@ -260,18 +370,9 @@ bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit if (!initializeOpenPickerOptions(picker.Get(), dialogOptions)) return false; - if (dialogOptions->fileMode() == QFileDialogOptions::ExistingFiles) { - ComPtr<IAsyncOperation<IVectorView<StorageFile *> *>> op; - hr = picker->PickMultipleFilesAsync(&op); - RETURN_FALSE_IF_FAILED("Failed to open multi file picker"); - hr = op->put_Completed(Callback<MultipleFileHandler>(this, &QWinRTFileDialogHelper::onMultipleFilesPicked).Get()); - } else { - ComPtr<IAsyncOperation<StorageFile *>> op; - hr = picker->PickSingleFileAsync(&op); - RETURN_FALSE_IF_FAILED("Failed to open single file picker"); - hr = op->put_Completed(Callback<SingleFileHandler>(this, &QWinRTFileDialogHelper::onSingleFilePicked).Get()); - } - RETURN_FALSE_IF_FAILED("Failed to attach file picker callback"); + if (!pickFiles(picker.Get(), this, dialogOptions->fileMode() == QFileDialogOptions::ExistingFile)) + return false; + break; } case QFileDialogOptions::Directory: @@ -284,11 +385,9 @@ bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit if (!initializeOpenPickerOptions(picker.Get(), dialogOptions)) return false; - ComPtr<IAsyncOperation<StorageFolder *>> op; - hr = picker->PickSingleFolderAsync(&op); - RETURN_FALSE_IF_FAILED("Failed to open folder picker"); - hr = op->put_Completed(Callback<SingleFolderHandler>(this, &QWinRTFileDialogHelper::onSingleFolderPicked).Get()); - RETURN_FALSE_IF_FAILED("Failed to attach folder picker callback"); + if (!pickFolder(picker.Get(), this)) + return false; + break; } } @@ -344,11 +443,9 @@ bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit RETURN_FALSE_IF_FAILED("Failed to set suggested file name"); } - ComPtr<IAsyncOperation<StorageFile *>> op; - hr = picker->PickSaveFileAsync(&op); - RETURN_FALSE_IF_FAILED("Failed to open save file picker"); - hr = op->put_Completed(Callback<SingleFileHandler>(this, &QWinRTFileDialogHelper::onSingleFilePicked).Get()); - RETURN_FALSE_IF_FAILED("Failed to attach file picker callback"); + if (!pickSaveFile(picker.Get(), this)) + return false; + break; } } @@ -367,6 +464,68 @@ void QWinRTFileDialogHelper::hide() d->shown = false; } +#ifdef Q_OS_WINPHONE +bool QWinRTFileDialogHelper::eventFilter(QObject *, QEvent *e) +{ + if (e->type() != QEvent::WinEventAct) + return false; + + HRESULT hr; + QActivationEvent *event = static_cast<QActivationEvent *>(e); + ComPtr<IInspectable> inspectable = event->args(); + ComPtr<IActivatedEventArgs> arguments; + hr = inspectable.As(&arguments); + Q_ASSERT_SUCCEEDED(hr); + + ActivationKind activationKind; + hr = arguments->get_Kind(&activationKind); + Q_ASSERT_SUCCEEDED(hr); + + // Handle only File, Folder and Save file pick continuation here. + if (activationKind != ActivationKind_PickFileContinuation + && activationKind != ActivationKind_PickFolderContinuation + && activationKind != ActivationKind_PickSaveFileContinuation) { + return false; + } + + QAbstractEventDispatcher *eventDispatcher = QCoreApplication::eventDispatcher(); + Q_ASSERT(eventDispatcher); + eventDispatcher->removeEventFilter(this); + e->accept(); + + if (activationKind == ActivationKind_PickFileContinuation) { + ComPtr<IFileOpenPickerContinuationEventArgs> fileContinuationArgs; + hr = arguments.As(&fileContinuationArgs); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IVectorView<StorageFile *>> files; + hr = fileContinuationArgs->get_Files(&files); + Q_ASSERT_SUCCEEDED(hr); + hr = onFilesPicked(files.Get()); + Q_ASSERT_SUCCEEDED(hr); + } else if (activationKind == ActivationKind_PickFolderContinuation) { + ComPtr<IFolderPickerContinuationEventArgs> folderContinuationArgs; + hr = arguments.As(&folderContinuationArgs); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IStorageFolder> folder; + hr = folderContinuationArgs->get_Folder(&folder); + Q_ASSERT_SUCCEEDED(hr); + hr = onFolderPicked(folder.Get()); + Q_ASSERT_SUCCEEDED(hr); + } else { + ComPtr<IFileSavePickerContinuationEventArgs> saveFileContinuationArgs; + hr = arguments.As(&saveFileContinuationArgs); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IStorageFile> file; + hr = saveFileContinuationArgs->get_File(&file); + Q_ASSERT_SUCCEEDED(hr); + hr = onFilePicked(file.Get()); + Q_ASSERT_SUCCEEDED(hr); + } + + return true; +} +#endif + void QWinRTFileDialogHelper::setDirectory(const QUrl &directory) { Q_D(QWinRTFileDialogHelper); @@ -403,6 +562,7 @@ QString QWinRTFileDialogHelper::selectedNameFilter() const return d->selectedNameFilter; } +#ifndef Q_OS_WINPHONE HRESULT QWinRTFileDialogHelper::onSingleFilePicked(IAsyncOperation<StorageFile *> *args, AsyncStatus status) { Q_D(QWinRTFileDialogHelper); @@ -419,14 +579,7 @@ HRESULT QWinRTFileDialogHelper::onSingleFilePicked(IAsyncOperation<StorageFile * ComPtr<IStorageFile> file; hr = args->GetResults(&file); Q_ASSERT_SUCCEEDED(hr); - if (!file) { - emit reject(); - return S_OK; - } - - appendFile(file.Get()); - emit accept(); - return S_OK; + return onFilePicked(file.Get()); } HRESULT QWinRTFileDialogHelper::onMultipleFilesPicked(IAsyncOperation<IVectorView<StorageFile *> *> *args, AsyncStatus status) @@ -445,17 +598,50 @@ HRESULT QWinRTFileDialogHelper::onMultipleFilesPicked(IAsyncOperation<IVectorVie ComPtr<IVectorView<StorageFile *>> fileList; hr = args->GetResults(&fileList); RETURN_HR_IF_FAILED("Failed to get file list"); + return onFilesPicked(fileList.Get()); +} + +HRESULT QWinRTFileDialogHelper::onSingleFolderPicked(IAsyncOperation<StorageFolder *> *args, AsyncStatus status) +{ + Q_D(QWinRTFileDialogHelper); + + QEventLoopLocker locker(&d->loop); + d->shown = false; + d->selectedFiles.clear(); + if (status == Canceled || status == Error) { + emit reject(); + return S_OK; + } + + HRESULT hr; + ComPtr<IStorageFolder> folder; + hr = args->GetResults(&folder); + Q_ASSERT_SUCCEEDED(hr); + return onFolderPicked(folder.Get()); +} +#endif //Q_OS_WINPHONE + +HRESULT QWinRTFileDialogHelper::onFilesPicked(IVectorView<StorageFile *> *files) +{ +#ifdef Q_OS_WINPHONE + Q_D(QWinRTFileDialogHelper); + QEventLoopLocker locker(&d->loop); + d->shown = false; + d->selectedFiles.clear(); +#endif + HRESULT hr; quint32 size; - hr = fileList->get_Size(&size); + hr = files->get_Size(&size); Q_ASSERT_SUCCEEDED(hr); if (!size) { emit reject(); return S_OK; } + for (quint32 i = 0; i < size; ++i) { ComPtr<IStorageFile> file; - hr = fileList->GetAt(i, &file); + hr = files->GetAt(i, &file); Q_ASSERT_SUCCEEDED(hr); appendFile(file.Get()); } @@ -464,28 +650,40 @@ HRESULT QWinRTFileDialogHelper::onMultipleFilesPicked(IAsyncOperation<IVectorVie return S_OK; } -HRESULT QWinRTFileDialogHelper::onSingleFolderPicked(IAsyncOperation<StorageFolder *> *args, AsyncStatus status) +HRESULT QWinRTFileDialogHelper::onFolderPicked(IStorageFolder *folder) { +#ifdef Q_OS_WINPHONE Q_D(QWinRTFileDialogHelper); - QEventLoopLocker locker(&d->loop); d->shown = false; d->selectedFiles.clear(); - if (status == Canceled || status == Error) { +#endif + + if (!folder) { emit reject(); return S_OK; } - HRESULT hr; - ComPtr<IStorageFolder> folder; - hr = args->GetResults(&folder); - Q_ASSERT_SUCCEEDED(hr); - if (!folder) { + appendFile(folder); + emit accept(); + return S_OK; +} + +HRESULT QWinRTFileDialogHelper::onFilePicked(IStorageFile *file) +{ +#ifdef Q_OS_WINPHONE + Q_D(QWinRTFileDialogHelper); + QEventLoopLocker locker(&d->loop); + d->shown = false; + d->selectedFiles.clear(); +#endif + + if (!file) { emit reject(); return S_OK; } - appendFile(folder.Get()); + appendFile(file); emit accept(); return S_OK; } diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h index 51b79c84ef..d6bacd2db9 100644 --- a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h +++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.h @@ -47,6 +47,7 @@ namespace ABI { class StorageFile; class StorageFolder; struct IStorageFile; + struct IStorageFolder; } namespace Foundation { enum class AsyncStatus; @@ -71,6 +72,9 @@ public: void exec() Q_DECL_OVERRIDE; bool show(Qt::WindowFlags, Qt::WindowModality, QWindow *) Q_DECL_OVERRIDE; void hide() Q_DECL_OVERRIDE; +#ifdef Q_OS_WINPHONE + bool eventFilter(QObject *o, QEvent *e) Q_DECL_OVERRIDE; +#endif bool defaultNameFilterDisables() const Q_DECL_OVERRIDE { return false; } void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; @@ -81,13 +85,19 @@ public: void selectNameFilter(const QString &selectedNameFilter) Q_DECL_OVERRIDE; QString selectedNameFilter() const; -private: +#ifndef Q_OS_WINPHONE HRESULT onSingleFilePicked(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::StorageFile *> *, ABI::Windows::Foundation::AsyncStatus); HRESULT onMultipleFilesPicked(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Foundation::Collections::IVectorView<ABI::Windows::Storage::StorageFile *> *> *, ABI::Windows::Foundation::AsyncStatus); HRESULT onSingleFolderPicked(ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::StorageFolder *> *, ABI::Windows::Foundation::AsyncStatus); +#endif + +private: + HRESULT onFilesPicked(ABI::Windows::Foundation::Collections::IVectorView<ABI::Windows::Storage::StorageFile *> *files); + HRESULT onFolderPicked(ABI::Windows::Storage::IStorageFolder *folder); + HRESULT onFilePicked(ABI::Windows::Storage::IStorageFile *file); void appendFile(IInspectable *); QScopedPointer<QWinRTFileDialogHelperPrivate> d_ptr; diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp index 7bd9e87ca6..f3b390b4d6 100644 --- a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp @@ -37,7 +37,9 @@ #include "qwinrtinputcontext.h" #include "qwinrtscreen.h" #include <QtGui/QWindow> +#include <private/qeventdispatcher_winrt_p.h> +#include <functional> #include <wrl.h> #include <roapi.h> #include <windows.ui.viewmanagement.h> @@ -163,10 +165,14 @@ void QWinRTInputContext::showInputPanel() if (FAILED(hr)) return; - boolean success; - hr = inputPane->TryShow(&success); - if (FAILED(hr)) - qErrnoWarning(hr, "Failed to show input panel."); + QEventDispatcherWinRT::runOnXamlThread([&inputPane]() { + HRESULT hr; + boolean success; + hr = inputPane->TryShow(&success); + if (FAILED(hr) || !success) + qErrnoWarning(hr, "Failed to show input panel."); + return hr; + }); } void QWinRTInputContext::hideInputPanel() @@ -176,10 +182,14 @@ void QWinRTInputContext::hideInputPanel() if (FAILED(hr)) return; - boolean success; - hr = inputPane->TryHide(&success); - if (FAILED(hr)) - qErrnoWarning(hr, "Failed to hide input panel."); + QEventDispatcherWinRT::runOnXamlThread([&inputPane]() { + HRESULT hr; + boolean success; + hr = inputPane->TryHide(&success); + if (FAILED(hr) || !success) + qErrnoWarning(hr, "Failed to hide input panel."); + return hr; + }); } #endif // Q_OS_WINPHONE diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index 7079d46523..fce77c56d1 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -188,9 +188,9 @@ bool QWinRTIntegration::hasCapability(QPlatformIntegration::Capability cap) cons case ThreadedPixmaps: case OpenGL: case ApplicationState: - return true; case NonFullScreenWindows: - return false; + case MultipleWindows: + return true; default: return QPlatformIntegration::hasCapability(cap); } diff --git a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp index 4fc1fea626..68bf1fdcac 100644 --- a/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp +++ b/src/plugins/platforms/winrt/qwinrtmessagedialoghelper.cpp @@ -38,7 +38,9 @@ #include "qwinrttheme.h" #include <QtCore/qfunctions_winrt.h> +#include <private/qeventdispatcher_winrt_p.h> +#include <functional> #include <windows.ui.popups.h> #include <windows.foundation.h> #include <windows.foundation.collections.h> @@ -168,16 +170,20 @@ bool QWinRTMessageDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModa } } - ComPtr<IAsyncOperation<IUICommand *>> op; - hr = dialog->ShowAsync(&op); - RETURN_FALSE_IF_FAILED("Failed to show dialog"); - hr = op->put_Completed(Callback<DialogCompletedHandler>(this, &QWinRTMessageDialogHelper::onCompleted).Get()); - RETURN_FALSE_IF_FAILED("Failed to set dialog callback"); - - d->shown = true; - hr = op.As(&d->info); - RETURN_FALSE_IF_FAILED("Failed to acquire AsyncInfo for MessageDialog"); - + hr = QEventDispatcherWinRT::runOnXamlThread([this, d, dialog]() { + HRESULT hr; + ComPtr<IAsyncOperation<IUICommand *>> op; + hr = dialog->ShowAsync(&op); + RETURN_HR_IF_FAILED("Failed to show dialog"); + hr = op->put_Completed(Callback<DialogCompletedHandler>(this, &QWinRTMessageDialogHelper::onCompleted).Get()); + RETURN_HR_IF_FAILED("Failed to set dialog callback"); + d->shown = true; + hr = op.As(&d->info); + RETURN_HR_IF_FAILED("Failed to acquire AsyncInfo for MessageDialog"); + return hr; + }); + + RETURN_FALSE_IF_FAILED("Failed to show dialog") return true; } diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 89ad33657b..563753cfcb 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -83,6 +83,9 @@ typedef ITypedEventHandler<CoreWindow*, PointerEventArgs*> PointerHandler; typedef ITypedEventHandler<CoreWindow*, WindowSizeChangedEventArgs*> SizeChangedHandler; typedef ITypedEventHandler<CoreWindow*, VisibilityChangedEventArgs*> VisibilityChangedHandler; typedef ITypedEventHandler<DisplayInformation*, IInspectable*> DisplayInformationHandler; +#ifdef Q_OS_WINPHONE +typedef ITypedEventHandler<StatusBar*, IInspectable*> StatusBarHandler; +#endif QT_BEGIN_NAMESPACE @@ -405,6 +408,10 @@ typedef HRESULT (__stdcall ICoreWindow::*CoreWindowCallbackRemover)(EventRegistr uint qHash(CoreWindowCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } typedef HRESULT (__stdcall IDisplayInformation::*DisplayCallbackRemover)(EventRegistrationToken); uint qHash(DisplayCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } +#ifdef Q_OS_WINPHONE +typedef HRESULT (__stdcall IStatusBar::*StatusBarCallbackRemover)(EventRegistrationToken); +uint qHash(StatusBarCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } +#endif class QWinRTScreenPrivate { @@ -414,11 +421,12 @@ public: ComPtr<Xaml::IDependencyObject> canvas; ComPtr<IApplicationView> view; ComPtr<IDisplayInformation> displayInformation; +#ifdef Q_OS_WINPHONE + ComPtr<IStatusBar> statusBar; +#endif QScopedPointer<QWinRTCursor> cursor; - QHash<quint32, QWindowSystemInterface::TouchPoint> touchPoints; - QSizeF logicalSize; QSurfaceFormat surfaceFormat; qreal logicalDpi; @@ -433,6 +441,9 @@ public: QHash<CoreWindowCallbackRemover, EventRegistrationToken> windowTokens; QHash<DisplayCallbackRemover, EventRegistrationToken> displayTokens; +#ifdef Q_OS_WINPHONE + QHash<StatusBarCallbackRemover, EventRegistrationToken> statusBarTokens; +#endif }; // To be called from the XAML thread @@ -472,8 +483,10 @@ QWinRTScreen::QWinRTScreen(Xaml::IWindow *xamlWindow) Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->add_PointerWheelChanged(Callback<PointerHandler>(this, &QWinRTScreen::onPointerUpdated).Get(), &d->windowTokens[&ICoreWindow::remove_PointerWheelChanged]); Q_ASSERT_SUCCEEDED(hr); +#ifndef Q_OS_WINPHONE hr = d->coreWindow->add_SizeChanged(Callback<SizeChangedHandler>(this, &QWinRTScreen::onSizeChanged).Get(), &d->windowTokens[&ICoreWindow::remove_SizeChanged]); Q_ASSERT_SUCCEEDED(hr); +#endif hr = d->coreWindow->add_Activated(Callback<ActivatedHandler>(this, &QWinRTScreen::onActivated).Get(), &d->windowTokens[&ICoreWindow::remove_Activated]); Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->add_Closed(Callback<ClosedHandler>(this, &QWinRTScreen::onClosed).Get(), &d->windowTokens[&ICoreWindow::remove_Closed]); @@ -535,6 +548,19 @@ QWinRTScreen::QWinRTScreen(Xaml::IWindow *xamlWindow) Q_ASSERT_SUCCEEDED(hr); d->cursor.reset(new QWinRTCursor); + +#ifdef Q_OS_WINPHONE + ComPtr<IStatusBarStatics> statusBarStatics; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_StatusBar).Get(), + IID_PPV_ARGS(&statusBarStatics)); + Q_ASSERT_SUCCEEDED(hr); + hr = statusBarStatics->GetForCurrentView(&d->statusBar); + Q_ASSERT_SUCCEEDED(hr); + hr = d->statusBar->add_Showing(Callback<StatusBarHandler>(this, &QWinRTScreen::onStatusBarShowing).Get(), &d->statusBarTokens[&IStatusBar::remove_Showing]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->statusBar->add_Hiding(Callback<StatusBarHandler>(this, &QWinRTScreen::onStatusBarHiding).Get(), &d->statusBarTokens[&IStatusBar::remove_Hiding]); + Q_ASSERT_SUCCEEDED(hr); +#endif // Q_OS_WINPHONE } QWinRTScreen::~QWinRTScreen() @@ -553,6 +579,12 @@ QWinRTScreen::~QWinRTScreen() hr = (d->displayInformation.Get()->*i.key())(i.value()); Q_ASSERT_SUCCEEDED(hr); } +#ifdef Q_OS_WINPHONE + for (QHash<StatusBarCallbackRemover, EventRegistrationToken>::const_iterator i = d->statusBarTokens.begin(); i != d->statusBarTokens.end(); ++i) { + hr = (d->statusBar.Get()->*i.key())(i.value()); + Q_ASSERT_SUCCEEDED(hr); + } +#endif //Q_OS_WINPHONE return hr; }); RETURN_VOID_IF_FAILED("Failed to unregister screen event callbacks"); @@ -564,6 +596,31 @@ QRect QWinRTScreen::geometry() const return QRect(QPoint(), (d->logicalSize * d->scaleFactor).toSize()); } +#ifdef Q_OS_WINPHONE +QRect QWinRTScreen::availableGeometry() const +{ + Q_D(const QWinRTScreen); + QRect statusBar; + QEventDispatcherWinRT::runOnXamlThread([d, &statusBar]() { + HRESULT hr; + Rect rect; + hr = d->statusBar->get_OccludedRect(&rect); + Q_ASSERT_SUCCEEDED(hr); + statusBar.setRect(qRound(rect.X * d->scaleFactor), + qRound(rect.Y * d->scaleFactor), + qRound(rect.Width * d->scaleFactor), + qRound(rect.Height * d->scaleFactor)); + return S_OK; + }); + + return geometry().adjusted( + d->orientation == Qt::LandscapeOrientation ? statusBar.width() : 0, + d->orientation == Qt::PortraitOrientation ? statusBar.height() : 0, + d->orientation == Qt::InvertedLandscapeOrientation ? -statusBar.width() : 0, + 0); +} +#endif //Q_OS_WINPHONE + int QWinRTScreen::depth() const { return 32; @@ -649,6 +706,26 @@ Xaml::IDependencyObject *QWinRTScreen::canvas() const return d->canvas.Get(); } +#ifdef Q_OS_WINPHONE +void QWinRTScreen::setStatusBarVisibility(bool visible, QWindow *window) +{ + Q_D(QWinRTScreen); + if (!window || (window->flags() & Qt::WindowType_Mask) != Qt::Window) + return; + + QEventDispatcherWinRT::runOnXamlThread([d, visible]() { + HRESULT hr; + ComPtr<IAsyncAction> op; + if (visible) + hr = d->statusBar->ShowAsync(&op); + else + hr = d->statusBar->HideAsync(&op); + Q_ASSERT_SUCCEEDED(hr); + return S_OK; + }); +} +#endif //Q_OS_WINPHONE + QWindow *QWinRTScreen::topWindow() const { Q_D(const QWinRTScreen); @@ -660,6 +737,12 @@ void QWinRTScreen::addWindow(QWindow *window) Q_D(QWinRTScreen); if (window == topWindow()) return; + +#ifdef Q_OS_WINPHONE + if (window->visibility() != QWindow::Maximized && window->visibility() != QWindow::Windowed) + setStatusBarVisibility(false, window); +#endif + d->visibleWindows.prepend(window); QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); handleExpose(); @@ -668,6 +751,12 @@ void QWinRTScreen::addWindow(QWindow *window) void QWinRTScreen::removeWindow(QWindow *window) { Q_D(QWinRTScreen); + +#ifdef Q_OS_WINPHONE + if (window->visibility() == QWindow::Minimized) + setStatusBarVisibility(false, window); +#endif + const bool wasTopWindow = window == topWindow(); if (!d->visibleWindows.removeAll(window)) return; @@ -964,13 +1053,8 @@ HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs * HRESULT hr; hr = d->coreWindow->get_Bounds(&size); RETURN_OK_IF_FAILED("Failed to get window bounds"); - QSizeF logicalSize = QSizeF(size.Width, size.Height); - if (d->logicalSize == logicalSize) - return S_OK; - - d->logicalSize = logicalSize; - const QRect newGeometry = geometry(); - QWindowSystemInterface::handleScreenGeometryChange(screen(), newGeometry, newGeometry); + d->logicalSize = QSizeF(size.Width, size.Height); + QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry()); QPlatformScreen::resizeMaximizedWindows(); handleExpose(); return S_OK; @@ -1024,7 +1108,11 @@ HRESULT QWinRTScreen::onOrientationChanged(IDisplayInformation *, IInspectable * Qt::ScreenOrientation newOrientation = static_cast<Qt::ScreenOrientation>(static_cast<int>(qtOrientationsFromNative(displayOrientation))); if (d->orientation != newOrientation) { d->orientation = newOrientation; +#ifdef Q_OS_WINPHONE + onSizeChanged(nullptr, nullptr); +#endif QWindowSystemInterface::handleScreenOrientationChange(screen(), d->orientation); + handleExpose(); // Clean broken frames caused by race between Qt and ANGLE } return S_OK; } @@ -1062,4 +1150,18 @@ HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *) return S_OK; } +#ifdef Q_OS_WINPHONE +HRESULT QWinRTScreen::onStatusBarShowing(IStatusBar *, IInspectable *) +{ + onSizeChanged(nullptr, nullptr); + return S_OK; +} + +HRESULT QWinRTScreen::onStatusBarHiding(IStatusBar *, IInspectable *) +{ + onSizeChanged(nullptr, nullptr); + return S_OK; +} +#endif //Q_OS_WINPHONE + QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtscreen.h b/src/plugins/platforms/winrt/qwinrtscreen.h index 796e6abb80..3297617740 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -61,6 +61,9 @@ namespace ABI { struct IDependencyObject; struct IWindow; } + namespace ViewManagement { + struct IStatusBar; + } } namespace Graphics { namespace Display { @@ -82,17 +85,20 @@ class QWinRTScreen : public QPlatformScreen public: explicit QWinRTScreen(ABI::Windows::UI::Xaml::IWindow *xamlWindow); ~QWinRTScreen(); - QRect geometry() const; - int depth() const; - QImage::Format format() const; + QRect geometry() const Q_DECL_OVERRIDE; +#ifdef Q_OS_WINPHONE + QRect availableGeometry() const Q_DECL_OVERRIDE; +#endif + int depth() const Q_DECL_OVERRIDE; + QImage::Format format() const Q_DECL_OVERRIDE; QSizeF physicalSize() const Q_DECL_OVERRIDE; QDpi logicalDpi() const Q_DECL_OVERRIDE; qreal scaleFactor() const; - QPlatformCursor *cursor() const; + QPlatformCursor *cursor() const Q_DECL_OVERRIDE; Qt::KeyboardModifiers keyboardModifiers() const; - Qt::ScreenOrientation nativeOrientation() const; - Qt::ScreenOrientation orientation() const; + Qt::ScreenOrientation nativeOrientation() const Q_DECL_OVERRIDE; + Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE; QWindow *topWindow() const; void addWindow(QWindow *window); @@ -105,6 +111,10 @@ public: ABI::Windows::UI::Core::ICoreWindow *coreWindow() const; ABI::Windows::UI::Xaml::IDependencyObject *canvas() const; +#ifdef Q_OS_WINPHONE + void setStatusBarVisibility(bool visible, QWindow *window); +#endif + private: void handleExpose(); @@ -124,6 +134,11 @@ private: HRESULT onOrientationChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); HRESULT onDpiChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); +#ifdef Q_OS_WINPHONE + HRESULT onStatusBarShowing(ABI::Windows::UI::ViewManagement::IStatusBar *, IInspectable *); + HRESULT onStatusBarHiding(ABI::Windows::UI::ViewManagement::IStatusBar *, IInspectable *); +#endif + QScopedPointer<QWinRTScreenPrivate> d_ptr; Q_DECLARE_PRIVATE(QWinRTScreen) }; diff --git a/src/plugins/platforms/winrt/qwinrtwindow.cpp b/src/plugins/platforms/winrt/qwinrtwindow.cpp index 634d62ef24..c5b06a5d8a 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.cpp +++ b/src/plugins/platforms/winrt/qwinrtwindow.cpp @@ -64,9 +64,22 @@ using namespace Microsoft::WRL::Wrappers; using namespace ABI::Windows::Foundation; using namespace ABI::Windows::Foundation::Collections; using namespace ABI::Windows::UI; +using namespace ABI::Windows::UI::Xaml; +using namespace ABI::Windows::UI::Xaml::Controls; QT_BEGIN_NAMESPACE +static void setUIElementVisibility(IUIElement *uiElement, bool visibility) +{ + Q_ASSERT(uiElement); + QEventDispatcherWinRT::runOnXamlThread([uiElement, visibility]() { + HRESULT hr; + hr = uiElement->put_Visibility(visibility ? Visibility_Visible : Visibility_Collapsed); + Q_ASSERT_SUCCEEDED(hr); + return S_OK; + }); +} + class QWinRTWindowPrivate { public: @@ -74,8 +87,13 @@ public: QSurfaceFormat surfaceFormat; QString windowTitle; + Qt::WindowState state; + EGLDisplay display; + EGLSurface surface; - ComPtr<Xaml::Controls::ISwapChainPanel> swapChainPanel; + ComPtr<ISwapChainPanel> swapChainPanel; + ComPtr<ICanvasStatics> canvas; + ComPtr<IUIElement> uiElement; }; QWinRTWindow::QWinRTWindow(QWindow *window) @@ -84,6 +102,8 @@ QWinRTWindow::QWinRTWindow(QWindow *window) { Q_D(QWinRTWindow); + d->surface = EGL_NO_SURFACE; + d->display = EGL_NO_DISPLAY; d->screen = static_cast<QWinRTScreen *>(screen()); setWindowFlags(window->flags()); setWindowState(window->windowState()); @@ -101,24 +121,26 @@ QWinRTWindow::QWinRTWindow(QWindow *window) d->surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); HRESULT hr; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_Canvas).Get(), + IID_PPV_ARGS(&d->canvas)); + Q_ASSERT_SUCCEEDED(hr); hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { // Create a new swapchain and place it inside the canvas HRESULT hr; hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_SwapChainPanel).Get(), &d->swapChainPanel); Q_ASSERT_SUCCEEDED(hr); - ComPtr<Xaml::IUIElement> uiElement; - hr = d->swapChainPanel.As(&uiElement); + hr = d->swapChainPanel.As(&d->uiElement); Q_ASSERT_SUCCEEDED(hr); - ComPtr<Xaml::IDependencyObject> canvas = d->screen->canvas(); - ComPtr<Xaml::Controls::IPanel> panel; + ComPtr<IDependencyObject> canvas = d->screen->canvas(); + ComPtr<IPanel> panel; hr = canvas.As(&panel); Q_ASSERT_SUCCEEDED(hr); - ComPtr<IVector<Xaml::UIElement *>> children; + ComPtr<IVector<UIElement *>> children; hr = panel->get_Children(&children); Q_ASSERT_SUCCEEDED(hr); - hr = children->Append(uiElement.Get()); + hr = children->Append(d->uiElement.Get()); Q_ASSERT_SUCCEEDED(hr); return S_OK; }); @@ -134,20 +156,16 @@ QWinRTWindow::~QWinRTWindow() HRESULT hr; hr = QEventDispatcherWinRT::runOnXamlThread([d]() { HRESULT hr; - ComPtr<Xaml::IDependencyObject> canvas = d->screen->canvas(); - ComPtr<Xaml::Controls::IPanel> panel; + ComPtr<IDependencyObject> canvas = d->screen->canvas(); + ComPtr<IPanel> panel; hr = canvas.As(&panel); Q_ASSERT_SUCCEEDED(hr); - ComPtr<IVector<Xaml::UIElement *>> children; + ComPtr<IVector<UIElement *>> children; hr = panel->get_Children(&children); Q_ASSERT_SUCCEEDED(hr); - - ComPtr<Xaml::IUIElement> uiElement; - hr = d->swapChainPanel.As(&uiElement); - Q_ASSERT_SUCCEEDED(hr); quint32 index; boolean found; - hr = children->IndexOf(uiElement.Get(), &index, &found); + hr = children->IndexOf(d->uiElement.Get(), &index, &found); Q_ASSERT_SUCCEEDED(hr); if (found) { hr = children->RemoveAt(index); @@ -156,6 +174,11 @@ QWinRTWindow::~QWinRTWindow() return S_OK; }); RETURN_VOID_IF_FAILED("Failed to completely destroy window resources, likely because the application is shutting down"); + + EGLBoolean value = eglDestroySurface(d->display, d->surface); + d->surface = EGL_NO_SURFACE; + if (value == EGL_FALSE) + qCritical("Failed to destroy EGL window surface: 0x%x", eglGetError()); } QSurfaceFormat QWinRTWindow::format() const @@ -180,8 +203,10 @@ void QWinRTWindow::setGeometry(const QRect &rect) { Q_D(QWinRTWindow); - if (window()->isTopLevel()) { - QPlatformWindow::setGeometry(d->screen->geometry()); + const Qt::WindowFlags windowFlags = window()->flags(); + if (window()->isTopLevel() && (windowFlags & Qt::WindowType_Mask) == Qt::Window) { + QPlatformWindow::setGeometry(windowFlags & Qt::MaximizeUsingFullscreenGeometryHint + ? d->screen->geometry() : d->screen->availableGeometry()); QWindowSystemInterface::handleGeometryChange(window(), geometry()); } else { QPlatformWindow::setGeometry(rect); @@ -191,10 +216,16 @@ void QWinRTWindow::setGeometry(const QRect &rect) HRESULT hr; hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { HRESULT hr; + const QRect windowGeometry = geometry(); + const QPointF topLeft= QPointF(windowGeometry.topLeft()) / d->screen->scaleFactor(); + hr = d->canvas->SetTop(d->uiElement.Get(), topLeft.y()); + Q_ASSERT_SUCCEEDED(hr); + hr = d->canvas->SetLeft(d->uiElement.Get(), topLeft.x()); + Q_ASSERT_SUCCEEDED(hr); ComPtr<Xaml::IFrameworkElement> frameworkElement; hr = d->swapChainPanel.As(&frameworkElement); Q_ASSERT_SUCCEEDED(hr); - const QSizeF size = QSizeF(geometry().size()) / d->screen->scaleFactor(); + const QSizeF size = QSizeF(windowGeometry.size()) / d->screen->scaleFactor(); hr = frameworkElement->put_Width(size.width()); Q_ASSERT_SUCCEEDED(hr); hr = frameworkElement->put_Height(size.height()); @@ -209,10 +240,13 @@ void QWinRTWindow::setVisible(bool visible) Q_D(QWinRTWindow); if (!window()->isTopLevel()) return; - if (visible) + if (visible) { d->screen->addWindow(window()); - else + setUIElementVisibility(d->uiElement.Get(), d->state != Qt::WindowMinimized); + } else { d->screen->removeWindow(window()); + setUIElementVisibility(d->uiElement.Get(), false); + } } void QWinRTWindow::setWindowTitle(const QString &title) @@ -249,4 +283,45 @@ qreal QWinRTWindow::devicePixelRatio() const return screen()->devicePixelRatio(); } +void QWinRTWindow::setWindowState(Qt::WindowState state) +{ + Q_D(QWinRTWindow); + if (d->state == state) + return; + +#ifdef Q_OS_WINPHONE + d->screen->setStatusBarVisibility(state == Qt::WindowMaximized || state == Qt::WindowNoState, window()); +#endif + + if (state == Qt::WindowMinimized) + setUIElementVisibility(d->uiElement.Get(), false); + + if (d->state == Qt::WindowMinimized) + setUIElementVisibility(d->uiElement.Get(), true); + + d->state = state; +} + +EGLSurface QWinRTWindow::eglSurface() const +{ + Q_D(const QWinRTWindow); + return d->surface; +} + +void QWinRTWindow::createEglSurface(EGLDisplay display, EGLConfig config) +{ + Q_D(QWinRTWindow); + if (d->surface == EGL_NO_SURFACE) { + d->display = display; + QEventDispatcherWinRT::runOnXamlThread([this, d, display, config]() { + d->surface = eglCreateWindowSurface(display, config, + reinterpret_cast<EGLNativeWindowType>(winId()), + nullptr); + if (d->surface == EGL_NO_SURFACE) + qCritical("Failed to create EGL window surface: 0x%x", eglGetError()); + return S_OK; + }); + } +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtwindow.h b/src/plugins/platforms/winrt/qwinrtwindow.h index 88c149b080..9ac7adbf4d 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.h +++ b/src/plugins/platforms/winrt/qwinrtwindow.h @@ -39,6 +39,7 @@ #include <qpa/qplatformwindow.h> #include <qpa/qwindowsysteminterface.h> +#include <EGL/egl.h> QT_BEGIN_NAMESPACE @@ -61,6 +62,10 @@ public: WId winId() const Q_DECL_OVERRIDE; qreal devicePixelRatio() const Q_DECL_OVERRIDE; + void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE; + + EGLSurface eglSurface() const; + void createEglSurface(EGLDisplay display, EGLConfig config); private: QScopedPointer<QWinRTWindowPrivate> d_ptr; diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 15d3575e60..c35b019f7e 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -107,6 +107,24 @@ Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen") #define XCB_GE_GENERIC 35 #endif +// Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed: +// - "pad0" became "extension" +// - "pad1" and "pad" became "pad0" +// New and old version of this struct share the following fields: +typedef struct qt_xcb_ge_event_t { + uint8_t response_type; + uint8_t extension; + uint16_t sequence; + uint32_t length; + uint16_t event_type; +} qt_xcb_ge_event_t; + +static inline bool isXIEvent(xcb_generic_event_t *event, int opCode) +{ + qt_xcb_ge_event_t *e = (qt_xcb_ge_event_t *)event; + return e->extension == opCode; +} + #ifdef XCB_USE_XLIB static const char * const xcbConnectionErrors[] = { "No error", /* Error 0 */ @@ -305,13 +323,10 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event) screen->updateRefreshRate(output.mode); // If the screen became primary, reshuffle the order in QGuiApplicationPrivate - // TODO: add a proper mechanism for updating primary screen if (!wasPrimary && screen->isPrimary()) { - QScreen *realScreen = static_cast<QPlatformScreen*>(screen)->screen(); - QGuiApplicationPrivate::screen_list.removeOne(realScreen); - QGuiApplicationPrivate::screen_list.prepend(realScreen); - m_screens.removeOne(screen); - m_screens.prepend(screen); + const int idx = m_screens.indexOf(screen); + m_screens.swap(0, idx); + QXcbIntegration::instance()->setPrimaryScreen(screen); } qCDebug(lcQpaScreen) << "output has changed" << screen; } @@ -590,9 +605,6 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra qCDebug(QT_XCB_GLINTEGRATION) << "Failed to create xcb gl-integration"; sync(); - - if (qEnvironmentVariableIsEmpty("QT_IM_MODULE")) - qputenv("QT_IM_MODULE", QByteArray("compose")); } QXcbConnection::~QXcbConnection() @@ -1115,7 +1127,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) #if defined(XCB_USE_XINPUT2) case XCB_GE_GENERIC: // Here the windowEventListener is invoked from xi2HandleEvent() - if (m_xi2Enabled) + if (m_xi2Enabled && isXIEvent(event, m_xiOpCode)) xi2HandleEvent(reinterpret_cast<xcb_ge_event_t *>(event)); break; #endif @@ -1288,10 +1300,12 @@ void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom a, uint id) memset(&event, 0, sizeof(event)); const xcb_window_t eventListener = xcb_generate_id(m_connection); + xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup); + xcb_screen_t *screen = it.data; Q_XCB_CALL(xcb_create_window(m_connection, XCB_COPY_FROM_PARENT, - eventListener, m_screens.at(0)->root(), + eventListener, screen->root, 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY, - m_screens.at(0)->screen()->root_visual, 0, 0)); + screen->root_visual, 0, 0)); event.response_type = XCB_CLIENT_MESSAGE; event.format = 32; @@ -1437,6 +1451,105 @@ void *QXcbConnection::createVisualInfoForDefaultVisualId() const #endif +#if defined(XCB_USE_XINPUT2) +// it is safe to cast XI_* events here as long as we are only touching the first 32 bytes, +// after that position event needs memmove, see xi2PrepareXIGenericDeviceEvent +static inline bool isXIType(xcb_generic_event_t *event, int opCode, uint16_t type) +{ + if (!isXIEvent(event, opCode)) + return false; + + xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event); + return xiEvent->evtype == type; +} +#endif +static inline bool isValid(xcb_generic_event_t *event) +{ + return event && (event->response_type & ~0x80); +} + +/*! \internal + + Compresses events of the same type to avoid swamping the event queue. + If event compression is not desired there are several options what developers can do: + + 1) Write responsive applications. We drop events that have been buffered in the event + queue while waiting on unresponsive GUI thread. + 2) Use QAbstractNativeEventFilter to get all events from X connection. This is not optimal + because it requires working with native event types. + 3) Or add public API to Qt for disabling event compression QTBUG-44964 + +*/ +bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex, QXcbEventArray *eventqueue) const +{ + uint responseType = event->response_type & ~0x80; + int nextIndex = currentIndex + 1; + + if (responseType == XCB_MOTION_NOTIFY) { + // compress XCB_MOTION_NOTIFY notify events + for (int j = nextIndex; j < eventqueue->size(); ++j) { + xcb_generic_event_t *next = eventqueue->at(j); + if (!isValid(next)) + continue; + if (next->response_type == XCB_MOTION_NOTIFY) + return true; + } + return false; + } +#if defined(XCB_USE_XINPUT2) + // compress XI_* events + if (responseType == XCB_GE_GENERIC) { + if (!m_xi2Enabled) + return false; + + // compress XI_Motion + if (isXIType(event, m_xiOpCode, XI_Motion)) { + for (int j = nextIndex; j < eventqueue->size(); ++j) { + xcb_generic_event_t *next = eventqueue->at(j); + if (!isValid(next)) + continue; + if (isXIType(next, m_xiOpCode, XI_Motion)) + return true; + } + return false; + } +#ifdef XCB_USE_XINPUT22 + // compress XI_TouchUpdate for the same touch point id + if (isXIType(event, m_xiOpCode, XI_TouchUpdate)) { + xXIDeviceEvent *xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event); + uint32_t id = xiDeviceEvent->detail % INT_MAX; + for (int j = nextIndex; j < eventqueue->size(); ++j) { + xcb_generic_event_t *next = eventqueue->at(j); + if (!isValid(next)) + continue; + if (isXIType(next, m_xiOpCode, XI_TouchUpdate)) { + xXIDeviceEvent *xiDeviceNextEvent = reinterpret_cast<xXIDeviceEvent *>(next); + if (id == xiDeviceNextEvent->detail % INT_MAX) + return true; + } + } + return false; + } +#endif + return false; + } +#endif + if (responseType == XCB_CONFIGURE_NOTIFY) { + // compress multiple configure notify events for the same window + for (int j = nextIndex; j < eventqueue->size(); ++j) { + xcb_generic_event_t *next = eventqueue->at(j); + if (isValid(next) && next->response_type == XCB_CONFIGURE_NOTIFY + && ((xcb_configure_notify_event_t *)next)->event == ((xcb_configure_notify_event_t*)event)->event) + { + return true; + } + } + return false; + } + + return false; +} + void QXcbConnection::processXcbEvents() { int connection_error = xcb_connection_has_error(xcb_connection()); @@ -1447,61 +1560,39 @@ void QXcbConnection::processXcbEvents() QXcbEventArray *eventqueue = m_reader->lock(); - for(int i = 0; i < eventqueue->size(); ++i) { + for (int i = 0; i < eventqueue->size(); ++i) { xcb_generic_event_t *event = eventqueue->at(i); if (!event) continue; QScopedPointer<xcb_generic_event_t, QScopedPointerPodDeleter> eventGuard(event); (*eventqueue)[i] = 0; - uint response_type = event->response_type & ~0x80; - - if (!response_type) { + if (!(event->response_type & ~0x80)) { handleXcbError((xcb_generic_error_t *)event); - } else { - if (response_type == XCB_MOTION_NOTIFY) { - // compress multiple motion notify events in a row - // to avoid swamping the event queue - xcb_generic_event_t *next = eventqueue->value(i+1, 0); - if (next && (next->response_type & ~0x80) == XCB_MOTION_NOTIFY) - continue; - } + continue; + } - if (response_type == XCB_CONFIGURE_NOTIFY) { - // compress multiple configure notify events for the same window - bool found = false; - for (int j = i; j < eventqueue->size(); ++j) { - xcb_generic_event_t *other = eventqueue->at(j); - if (other && (other->response_type & ~0x80) == XCB_CONFIGURE_NOTIFY - && ((xcb_configure_notify_event_t *)other)->event == ((xcb_configure_notify_event_t *)event)->event) - { - found = true; - break; - } - } - if (found) - continue; - } + if (compressEvent(event, i, eventqueue)) + continue; - bool accepted = false; - if (clipboard()->processIncr()) - clipboard()->incrTransactionPeeker(event, accepted); - if (accepted) - continue; + bool accepted = false; + if (clipboard()->processIncr()) + clipboard()->incrTransactionPeeker(event, accepted); + if (accepted) + continue; - 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)(this, event)) - it = m_peekFuncs.erase(it); - else - ++it; - } - m_reader->unlock(); - handleXcbEvent(event); - m_reader->lock(); + 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)(this, event)) + it = m_peekFuncs.erase(it); + else + ++it; } + m_reader->unlock(); + handleXcbEvent(event); + m_reader->lock(); } eventqueue->clear(); @@ -1746,7 +1837,8 @@ static const char * xcb_atomnames = { "_XSETTINGS_SETTINGS\0" "_COMPIZ_DECOR_PENDING\0" "_COMPIZ_DECOR_REQUEST\0" - "_COMPIZ_DECOR_DELETE_PIXMAP\0" // \0\0 terminates loop. + "_COMPIZ_DECOR_DELETE_PIXMAP\0" + "_COMPIZ_TOOLKIT_ACTION\0" // \0\0 terminates loop. }; QXcbAtom::Atom QXcbConnection::qatom(xcb_atom_t xatom) const @@ -2043,34 +2135,13 @@ bool QXcbConnection::xi2GetValuatorValueIfSet(void *event, int valuatorNum, doub return true; } -// Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed: -// - "pad0" became "extension" -// - "pad1" and "pad" became "pad0" -// New and old version of this struct share the following fields: -// NOTE: API might change again in the next release of xcb in which case this comment will -// need to be updated to reflect the reality. -typedef struct qt_xcb_ge_event_t { - uint8_t response_type; - uint8_t extension; - uint16_t sequence; - uint32_t length; - uint16_t event_type; -} qt_xcb_ge_event_t; - -bool QXcbConnection::xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *ev, int opCode) -{ - qt_xcb_ge_event_t *event = (qt_xcb_ge_event_t *)ev; - // xGenericEvent has "extension" on the second byte, the same is true for xcb_ge_event_t starting from - // the xcb version 1.9.3, prior to that it was called "pad0". - if (event->extension == opCode) { - // xcb event structs contain stuff that wasn't on the wire, the full_sequence field - // adds an extra 4 bytes and generic events cookie data is on the wire right after the standard 32 bytes. - // Move this data back to have the same layout in memory as it was on the wire - // and allow casting, overwriting the full_sequence field. - memmove((char*) event + 32, (char*) event + 36, event->length * 4); - return true; - } - return false; +void QXcbConnection::xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event) +{ + // xcb event structs contain stuff that wasn't on the wire, the full_sequence field + // adds an extra 4 bytes and generic events cookie data is on the wire right after the standard 32 bytes. + // Move this data back to have the same layout in memory as it was on the wire + // and allow casting, overwriting the full_sequence field. + memmove((char*) event + 32, (char*) event + 36, event->length * 4); } #endif // defined(XCB_USE_XINPUT2) diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 4a0348aa0c..6ee32bf600 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -286,6 +286,7 @@ namespace QXcbAtom { _COMPIZ_DECOR_PENDING, _COMPIZ_DECOR_REQUEST, _COMPIZ_DECOR_DELETE_PIXMAP, + _COMPIZ_TOOLKIT_ACTION, NPredefinedAtoms, @@ -522,6 +523,7 @@ private: bool checkOutputIsPrimary(xcb_window_t rootWindow, xcb_randr_output_t output); void initializeScreens(); void updateScreens(const xcb_randr_notify_event_t *event); + bool compressEvent(xcb_generic_event_t *event, int currentIndex, QXcbEventArray *eventqueue) const; bool m_xi2Enabled; int m_xi2Minor; @@ -574,7 +576,7 @@ private: QHash<int, ScrollingDevice> m_scrollingDevices; static bool xi2GetValuatorValueIfSet(void *event, int valuatorNum, double *value); - static bool xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event, int opCode); + static void xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event); #endif xcb_connection_t *m_connection; diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 5a2ea74258..8097cce709 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -216,6 +216,12 @@ void QXcbConnection::xi2SetupDevices() isTablet = true; tabletData.pointerType = QTabletEvent::Pen; dbgType = QLatin1String("pen"); + } else if (name.contains("waltop") && name.contains("tablet")) { + // other "Genius" tablets + // WALTOP International Corp. Slim Tablet + isTablet = true; + tabletData.pointerType = QTabletEvent::Pen; + dbgType = QLatin1String("pen"); } else { isTablet = false; } @@ -413,8 +419,10 @@ XInput2TouchDeviceData *QXcbConnection::touchDeviceForId(int id) hasRelativeCoords = true; dev->size.setHeight((vci->max - vci->min) * 1000.0 / vci->resolution); } else if (vci->label == atom(QXcbAtom::AbsX)) { + caps |= QTouchDevice::Position; dev->size.setHeight((vci->max - vci->min) * 1000.0 / vci->resolution); } else if (vci->label == atom(QXcbAtom::AbsY)) { + caps |= QTouchDevice::Position; dev->size.setWidth((vci->max - vci->min) * 1000.0 / vci->resolution); } break; @@ -459,82 +467,81 @@ static inline qreal fixed1616ToReal(FP1616 val) void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) { - if (xi2PrepareXIGenericDeviceEvent(event, m_xiOpCode)) { - xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event); - int sourceDeviceId = xiEvent->deviceid; // may be the master id - xXIDeviceEvent *xiDeviceEvent = 0; - QXcbWindowEventListener *eventListener = 0; + xi2PrepareXIGenericDeviceEvent(event); + xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event); + int sourceDeviceId = xiEvent->deviceid; // may be the master id + xXIDeviceEvent *xiDeviceEvent = 0; + QXcbWindowEventListener *eventListener = 0; - switch (xiEvent->evtype) { - case XI_ButtonPress: - case XI_ButtonRelease: - case XI_Motion: + switch (xiEvent->evtype) { + case XI_ButtonPress: + case XI_ButtonRelease: + case XI_Motion: #ifdef XCB_USE_XINPUT22 - case XI_TouchBegin: - case XI_TouchUpdate: - case XI_TouchEnd: + case XI_TouchBegin: + case XI_TouchUpdate: + case XI_TouchEnd: #endif - { - xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event); - eventListener = windowEventListenerFromId(xiDeviceEvent->event); - if (eventListener) { - long result = 0; - if (eventListener->handleGenericEvent(reinterpret_cast<xcb_generic_event_t *>(event), &result)) - return; - } - sourceDeviceId = xiDeviceEvent->sourceid; // use the actual device id instead of the master - break; - } - case XI_HierarchyChanged: - xi2HandleHierachyEvent(xiEvent); - return; - case XI_DeviceChanged: - xi2HandleDeviceChangedEvent(xiEvent); - return; - default: - break; + { + xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event); + eventListener = windowEventListenerFromId(xiDeviceEvent->event); + if (eventListener) { + long result = 0; + if (eventListener->handleGenericEvent(reinterpret_cast<xcb_generic_event_t *>(event), &result)) + return; } + sourceDeviceId = xiDeviceEvent->sourceid; // use the actual device id instead of the master + break; + } + case XI_HierarchyChanged: + xi2HandleHierachyEvent(xiEvent); + return; + case XI_DeviceChanged: + xi2HandleDeviceChangedEvent(xiEvent); + return; + default: + break; + } #ifndef QT_NO_TABLETEVENT - for (int i = 0; i < m_tabletData.count(); ++i) { - if (m_tabletData.at(i).deviceId == sourceDeviceId) { - if (xi2HandleTabletEvent(xiEvent, &m_tabletData[i], eventListener)) - return; - } + for (int i = 0; i < m_tabletData.count(); ++i) { + if (m_tabletData.at(i).deviceId == sourceDeviceId) { + if (xi2HandleTabletEvent(xiEvent, &m_tabletData[i], eventListener)) + return; } + } #endif // QT_NO_TABLETEVENT #ifdef XCB_USE_XINPUT21 - QHash<int, ScrollingDevice>::iterator device = m_scrollingDevices.find(sourceDeviceId); - if (device != m_scrollingDevices.end()) - xi2HandleScrollEvent(xiEvent, device.value()); + QHash<int, ScrollingDevice>::iterator device = m_scrollingDevices.find(sourceDeviceId); + if (device != m_scrollingDevices.end()) + xi2HandleScrollEvent(xiEvent, device.value()); #endif // XCB_USE_XINPUT21 #ifdef XCB_USE_XINPUT22 - if (xiDeviceEvent) { - switch (xiDeviceEvent->evtype) { - case XI_ButtonPress: - case XI_ButtonRelease: - case XI_Motion: - if (xi2MouseEvents() && eventListener && !(xiDeviceEvent->flags & XIPointerEmulated)) - eventListener->handleXIMouseEvent(event); - break; + if (xiDeviceEvent) { + switch (xiDeviceEvent->evtype) { + case XI_ButtonPress: + case XI_ButtonRelease: + case XI_Motion: + if (xi2MouseEvents() && eventListener && !(xiDeviceEvent->flags & XIPointerEmulated)) + eventListener->handleXIMouseEvent(event); + break; - case XI_TouchBegin: - case XI_TouchUpdate: - case XI_TouchEnd: - if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) - qCDebug(lcQpaXInput, "XI2 touch event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f on window %x", - event->event_type, xiDeviceEvent->sequenceNumber, xiDeviceEvent->detail, - fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y), - fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y),xiDeviceEvent->event); - if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) - xi2ProcessTouch(xiDeviceEvent, platformWindow); - break; - } + case XI_TouchBegin: + case XI_TouchUpdate: + case XI_TouchEnd: + if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) + qCDebug(lcQpaXInput, "XI2 touch event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f on window %x", + event->event_type, xiDeviceEvent->sequenceNumber, xiDeviceEvent->detail, + fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y), + fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y),xiDeviceEvent->event); + if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) + xi2ProcessTouch(xiDeviceEvent, platformWindow); + break; } -#endif // XCB_USE_XINPUT22 } +#endif // XCB_USE_XINPUT22 } #ifdef XCB_USE_XINPUT22 @@ -967,15 +974,6 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData, Q xXIGenericDeviceEvent *xiEvent = static_cast<xXIGenericDeviceEvent *>(event); xXIDeviceEvent *xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(xiEvent); -#ifdef XCB_USE_XINPUT22 - // Synthesize mouse events since otherwise there are no mouse events from - // the pen on the XI 2.2+ path. - if (xi2MouseEvents() && eventListener) - eventListener->handleXIMouseEvent(reinterpret_cast<xcb_ge_event_t *>(event)); -#else - Q_UNUSED(eventListener); -#endif - switch (xiEvent->evtype) { case XI_ButtonPress: { Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail); @@ -1029,9 +1027,8 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData, Q tabletData->inProximity = true; tabletData->tool = toolIdToTabletDevice(tool); tabletData->serialId = qint64(ptr[_WACSER_USB_ID]) << 32 | qint64(ptr[_WACSER_TOOL_SERIAL]); - QWindowSystemInterface::handleTabletEnterProximityEvent(tabletData->tool, - tabletData->pointerType, - tabletData->serialId); + QWindowSystemInterface::handleTabletEnterProximityEvent(ev->time, + tabletData->tool, tabletData->pointerType, tabletData->serialId); } else { tabletData->inProximity = false; tabletData->tool = toolIdToTabletDevice(ptr[_WACSER_LAST_TOOL_ID]); @@ -1040,9 +1037,8 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData, Q if (!tabletData->tool) tabletData->tool = toolIdToTabletDevice(ptr[_WACSER_LAST_TOOL_SERIAL]); tabletData->serialId = qint64(ptr[_WACSER_USB_ID]) << 32 | qint64(ptr[_WACSER_LAST_TOOL_SERIAL]); - QWindowSystemInterface::handleTabletLeaveProximityEvent(tabletData->tool, - tabletData->pointerType, - tabletData->serialId); + QWindowSystemInterface::handleTabletLeaveProximityEvent(ev->time, + tabletData->tool, tabletData->pointerType, tabletData->serialId); } // TODO maybe have a hash of tabletData->deviceId to device data so we can // look up the tablet name here, and distinguish multiple tablets @@ -1060,6 +1056,16 @@ bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData, Q handled = false; break; } + +#ifdef XCB_USE_XINPUT22 + // Synthesize mouse events since otherwise there are no mouse events from + // the pen on the XI 2.2+ path. + if (xi2MouseEvents() && eventListener) + eventListener->handleXIMouseEvent(reinterpret_cast<xcb_ge_event_t *>(event)); +#else + Q_UNUSED(eventListener); +#endif + return handled; } @@ -1110,13 +1116,14 @@ void QXcbConnection::xi2ReportTabletEvent(TabletData &tabletData, void *event) } if (Q_UNLIKELY(lcQpaXInput().isDebugEnabled())) - qCDebug(lcQpaXInput, "XI2 event on tablet %d with tool %d type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf", - tabletData.deviceId, tabletData.tool, ev->evtype, ev->sequenceNumber, ev->detail, + qCDebug(lcQpaXInput, "XI2 event on tablet %d with tool %d type %d seq %d detail %d time %d " + "pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf", + tabletData.deviceId, tabletData.tool, ev->evtype, ev->sequenceNumber, ev->detail, ev->time, fixed1616ToReal(ev->event_x), fixed1616ToReal(ev->event_y), fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y), (int)tabletData.buttons, pressure, xTilt, yTilt, rotation); - QWindowSystemInterface::handleTabletEvent(window, local, global, + QWindowSystemInterface::handleTabletEvent(window, ev->time, local, global, tabletData.tool, tabletData.pointerType, tabletData.buttons, pressure, xTilt, yTilt, tangentialPressure, diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index a3e646ed7a..de23c59a63 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -444,7 +444,7 @@ void QXcbDrag::move(const QPoint &globalPos) DEBUG() << "sending Xdnd enter source=" << enter.data.data32[0]; if (w) - handleEnter(w, &enter); + handleEnter(w, &enter, current_proxy_target); else if (target) xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&enter); waiting_for_status = false; @@ -665,7 +665,7 @@ static bool checkEmbedded(QWidget* w, const XEvent* xe) #endif -void QXcbDrag::handleEnter(QPlatformWindow *window, const xcb_client_message_event_t *event) +void QXcbDrag::handleEnter(QPlatformWindow *window, const xcb_client_message_event_t *event, xcb_window_t proxy) { Q_UNUSED(window); DEBUG() << "handleEnter" << window; @@ -677,6 +677,9 @@ void QXcbDrag::handleEnter(QPlatformWindow *window, const xcb_client_message_eve return; xdnd_dragsource = event->data.data32[0]; + if (!proxy) + proxy = xdndProxy(connection(), xdnd_dragsource); + current_proxy_target = proxy ? proxy : xdnd_dragsource; if (event->data.data32[1] & 1) { // get the types from XdndTypeList @@ -775,7 +778,7 @@ void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message if (xdnd_dragsource == connection()->clipboard()->owner()) handle_xdnd_status(&response); else - Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xdnd_dragsource, + Q_XCB_CALL(xcb_send_event(xcb_connection(), false, current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&response)); } @@ -967,7 +970,7 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e finished.data.data32[0] = currentWindow ? xcb_window(currentWindow.data()) : XCB_NONE; finished.data.data32[1] = response.isAccepted(); // flags finished.data.data32[2] = toXdndAction(response.acceptedAction()); - Q_XCB_CALL(xcb_send_event(xcb_connection(), false, xdnd_dragsource, + Q_XCB_CALL(xcb_send_event(xcb_connection(), false, current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (char *)&finished)); xdnd_dragsource = 0; @@ -1132,7 +1135,11 @@ void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event } } - xcb_send_event(xcb_connection(), false, event->requestor, XCB_EVENT_MASK_NO_EVENT, (const char *)¬ify); + xcb_window_t proxy_target = xdndProxy(connection(), event->requestor); + if (!proxy_target) + proxy_target = event->requestor; + + xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)¬ify); } diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h index 699d402ea6..9584c04238 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.h +++ b/src/plugins/platforms/xcb/qxcbdrag.h @@ -76,7 +76,7 @@ public: void drop(const QPoint &globalPos) Q_DECL_OVERRIDE; void endDrag() Q_DECL_OVERRIDE; - void handleEnter(QPlatformWindow *window, const xcb_client_message_event_t *event); + void handleEnter(QPlatformWindow *window, const xcb_client_message_event_t *event, xcb_window_t proxy = 0); void handlePosition(QPlatformWindow *w, const xcb_client_message_event_t *event); void handleLeave(QPlatformWindow *w, const xcb_client_message_event_t *event); void handleDrop(QPlatformWindow *, const xcb_client_message_event_t *event); diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index fc06f1a7b0..9cedfa77ad 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -268,7 +268,10 @@ void QXcbIntegration::initialize() { // Perform everything that may potentially need the event dispatcher (timers, socket // notifiers) here instead of the constructor. - m_inputContext.reset(QPlatformInputContextFactory::create()); + QString icStr = QPlatformInputContextFactory::requested(); + if (icStr.isNull()) + icStr = QLatin1String("compose"); + m_inputContext.reset(QPlatformInputContextFactory::create(icStr)); } void QXcbIntegration::moveToScreen(QWindow *window, int screen) diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index f9a85cdf44..d751c6d48a 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -1971,7 +1971,8 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even // and other messages. } else if (event->type == atom(QXcbAtom::_COMPIZ_DECOR_PENDING) || event->type == atom(QXcbAtom::_COMPIZ_DECOR_REQUEST) - || event->type == atom(QXcbAtom::_COMPIZ_DECOR_DELETE_PIXMAP)) { + || event->type == atom(QXcbAtom::_COMPIZ_DECOR_DELETE_PIXMAP) + || event->type == atom(QXcbAtom::_COMPIZ_TOOLKIT_ACTION)) { //silence the _COMPIZ messages for now } else { qWarning() << "QXcbWindow: Unhandled client message:" << connection()->atomName(event->type); @@ -2208,17 +2209,17 @@ void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event) switch (ev->evtype) { case XI_ButtonPress: - qCDebug(lcQpaXInput, "XI2 mouse press, button %d", button); + qCDebug(lcQpaXInput, "XI2 mouse press, button %d, time %d", button, ev->time); conn->setButton(button, true); handleButtonPressEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time); break; case XI_ButtonRelease: - qCDebug(lcQpaXInput, "XI2 mouse release, button %d", button); + qCDebug(lcQpaXInput, "XI2 mouse release, button %d, time %d", button, ev->time); conn->setButton(button, false); handleButtonReleaseEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time); break; case XI_Motion: - qCDebug(lcQpaXInput, "XI2 mouse motion %d,%d", event_x, event_y); + qCDebug(lcQpaXInput, "XI2 mouse motion %d,%d, time %d", event_x, event_y, ev->time); handleMotionNotifyEvent(event_x, event_y, root_x, root_y, modifiers, ev->time); break; default: diff --git a/src/plugins/platforms/xcb/qxcbwmsupport.cpp b/src/plugins/platforms/xcb/qxcbwmsupport.cpp index 7d31ac7118..82c1c1de77 100644 --- a/src/plugins/platforms/xcb/qxcbwmsupport.cpp +++ b/src/plugins/platforms/xcb/qxcbwmsupport.cpp @@ -94,14 +94,14 @@ void QXcbWMSupport::updateVirtualRoots() int offset = 0; int remaining = 0; do { - 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_cookie_t cookie = xcb_get_property(xcb_connection(), false, root, atom(QXcbAtom::_NET_VIRTUAL_ROOTS), XCB_ATOM_WINDOW, offset, 1024); xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), cookie, NULL); if (!reply) break; remaining = 0; - if (reply->type == XCB_ATOM_ATOM && reply->format == 32) { + if (reply->type == XCB_ATOM_WINDOW && reply->format == 32) { int len = xcb_get_property_value_length(reply)/sizeof(xcb_window_t); xcb_window_t *roots = (xcb_window_t *)xcb_get_property_value(reply); int s = net_virtual_roots.size(); |