diff options
Diffstat (limited to 'src/plugins/platforms')
196 files changed, 6449 insertions, 4053 deletions
diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp index 8ee3ff88d1..b410e5f68e 100644 --- a/src/plugins/platforms/android/androidjniinput.cpp +++ b/src/plugins/platforms/android/androidjniinput.cpp @@ -70,18 +70,20 @@ namespace QtAndroidInput candidatesEnd); } - void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints) + void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints, int enterKeyType) { QJNIObjectPrivate::callStaticMethod<void>(applicationClass(), "showSoftwareKeyboard", - "(IIIII)V", + "(IIIIII)V", left, top, width, height, - inputHints); + inputHints, + enterKeyType + ); #ifdef QT_DEBUG_ANDROID_IM_PROTOCOL - qDebug() << "@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints; + qDebug() << "@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints << enterKeyType; #endif } @@ -238,6 +240,52 @@ namespace QtAndroidInput QWindowSystemInterface::handleTouchEvent(window, touchDevice, m_touchPoints); } + static void tabletEvent(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint deviceId, jlong time, jint action, + jint pointerType, jint buttonState, jfloat x, jfloat y, jfloat pressure) + { + QPointF globalPosF(x, y); + QPoint globalPos((int)x, (int)y); + QWindow *tlw = topLevelWindowAt(globalPos); + QPointF localPos = tlw ? (globalPosF - tlw->position()) : globalPosF; + + // Galaxy Note with plain Android: + // 0 1 0 stylus press + // 2 1 0 stylus drag + // 1 1 0 stylus release + // 0 1 2 stylus press with side-button held + // 2 1 2 stylus drag with side-button held + // 1 1 2 stylus release with side-button held + // Galaxy Note 4 with Samsung firmware: + // 0 1 0 stylus press + // 2 1 0 stylus drag + // 1 1 0 stylus release + // 211 1 2 stylus press with side-button held + // 213 1 2 stylus drag with side-button held + // 212 1 2 stylus release with side-button held + // when action == ACTION_UP (1) it's a release; otherwise we say which button is pressed + Qt::MouseButtons buttons = Qt::NoButton; + switch (action) { + case 1: // ACTION_UP + case 212: // stylus release while side-button held on Galaxy Note 4 + buttons = Qt::NoButton; + break; + default: // action is press or drag + if (buttonState == 0) + buttons = Qt::LeftButton; + else // 2 means RightButton + buttons = Qt::MouseButtons(buttonState); + break; + } + +#ifdef QT_DEBUG_ANDROID_STYLUS + qDebug() << action << pointerType << buttonState << "@" << x << y << "pressure" << pressure << ": buttons" << buttons; +#endif + + QWindowSystemInterface::handleTabletEvent(tlw, ulong(time), + localPos, globalPosF, QTabletEvent::Stylus, pointerType, + buttons, pressure, 0, 0, 0., 0., 0, deviceId, Qt::NoModifier); + } + static int mapAndroidKey(int key) { // 0--9 0x00000007 -- 0x00000010 @@ -702,6 +750,7 @@ namespace QtAndroidInput {"mouseUp", "(III)V", (void *)mouseUp}, {"mouseMove", "(III)V", (void *)mouseMove}, {"longPress", "(III)V", (void *)longPress}, + {"tabletEvent", "(IIJIIIFFF)V", (void *)tabletEvent}, {"keyDown", "(IIIZ)V", (void *)keyDown}, {"keyUp", "(IIIZ)V", (void *)keyUp}, {"keyboardVisibilityChanged", "(Z)V", (void *)keyboardVisibilityChanged} diff --git a/src/plugins/platforms/android/androidjniinput.h b/src/plugins/platforms/android/androidjniinput.h index b5a2ef06e4..d737dc9c98 100644 --- a/src/plugins/platforms/android/androidjniinput.h +++ b/src/plugins/platforms/android/androidjniinput.h @@ -41,7 +41,7 @@ QT_BEGIN_NAMESPACE namespace QtAndroidInput { // Software keyboard support - void showSoftwareKeyboard(int top, int left, int width, int height, int inputHints); + void showSoftwareKeyboard(int top, int left, int width, int height, int inputHints, int enterKeyType); void resetSoftwareKeyboard(); void hideSoftwareKeyboard(); bool isSoftwareKeyboardVisible(); diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index a04bf1eccb..cd40b7eec2 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -600,6 +600,11 @@ static void updateApplicationState(JNIEnv */*env*/, jobject /*thiz*/, jint state return; } + if (state == Qt::ApplicationActive) + QtAndroidPrivate::handleResume(); + else if (state == Qt::ApplicationInactive) + QtAndroidPrivate::handlePause(); + if (state <= Qt::ApplicationInactive) { // NOTE: sometimes we will receive two consecutive suspended notifications, // In the second suspended notification, QWindowSystemInterface::flushWindowSystemEvents() diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index d264f74d66..b44340106d 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -545,7 +545,9 @@ void QAndroidInputContext::showInputPanel() rect.top(), rect.width(), rect.height(), - query->value(Qt::ImHints).toUInt()); + query->value(Qt::ImHints).toUInt(), + query->value(Qt::ImEnterKeyType).toUInt() + ); } void QAndroidInputContext::showInputPanelLater(Qt::ApplicationState state) diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index ad6cb3a1fc..ba0e6b001a 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -12,7 +12,6 @@ OBJECTIVE_SOURCES += main.mm \ qcocoawindow.mm \ qnsview.mm \ qnsviewaccessibility.mm \ - qcocoaautoreleasepool.mm \ qnswindowdelegate.mm \ qcocoanativeinterface.mm \ qcocoaeventdispatcher.mm \ @@ -48,7 +47,6 @@ HEADERS += qcocoaintegration.h \ qcocoabackingstore.h \ qcocoawindow.h \ qnsview.h \ - qcocoaautoreleasepool.h \ qnswindowdelegate.h \ qcocoanativeinterface.h \ qcocoaeventdispatcher.h \ diff --git a/src/plugins/platforms/cocoa/main.mm b/src/plugins/platforms/cocoa/main.mm index b7e8fa1fca..43ff715161 100644 --- a/src/plugins/platforms/cocoa/main.mm +++ b/src/plugins/platforms/cocoa/main.mm @@ -50,11 +50,9 @@ public: QPlatformIntegration * QCocoaIntegrationPlugin::create(const QString& system, const QStringList& paramList) { - Q_UNUSED(paramList); - - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; if (system.compare(QLatin1String("cocoa"), Qt::CaseInsensitive) == 0) - return new QCocoaIntegration; + return new QCocoaIntegration(paramList); return 0; } diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.h b/src/plugins/platforms/cocoa/qcocoaaccessibility.h index 061dfac156..18ff9aeb29 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.h +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.h @@ -45,10 +45,10 @@ class QCocoaAccessibility : public QPlatformAccessibility public: QCocoaAccessibility(); ~QCocoaAccessibility(); - void notifyAccessibilityUpdate(QAccessibleEvent *event); - void setRootObject(QObject *o); - void initialize(); - void cleanup(); + void notifyAccessibilityUpdate(QAccessibleEvent *event) Q_DECL_OVERRIDE; + void setRootObject(QObject *o) Q_DECL_OVERRIDE; + void initialize() Q_DECL_OVERRIDE; + void cleanup() Q_DECL_OVERRIDE; }; namespace QCocoaAccessible { diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h index 04e51d5392..abaaba91a5 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h @@ -100,6 +100,7 @@ - (void)setReflectionDelegate:(NSObject <NSApplicationDelegate> *)oldDelegate; - (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent; - (void) removeAppleEventHandlers; +- (bool) inLaunch; @end QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaApplicationDelegate); diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index 6c673a4f5d..cac50825af 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -284,6 +284,11 @@ QT_END_NAMESPACE [eventManager removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL]; } +- (bool) inLaunch +{ + return inLaunch; +} + - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { Q_UNUSED(aNotification); diff --git a/src/plugins/platforms/cocoa/qcocoaautoreleasepool.h b/src/plugins/platforms/cocoa/qcocoaautoreleasepool.h deleted file mode 100644 index 8b2a9f3788..0000000000 --- a/src/plugins/platforms/cocoa/qcocoaautoreleasepool.h +++ /dev/null @@ -1,53 +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 QCOCOAAUTORELEASEPOOL_H -#define QCOCOAAUTORELEASEPOOL_H - -#undef slots -#include <qglobal.h> -#include <Cocoa/Cocoa.h> - -QT_BEGIN_NAMESPACE -class QCocoaAutoReleasePool -{ -public: - QCocoaAutoReleasePool(); - ~QCocoaAutoReleasePool(); - -private: - NSAutoreleasePool *pool; -}; -QT_END_NAMESPACE - -#endif // QCOCOAAUTORELEASEPOOL_H diff --git a/src/plugins/platforms/cocoa/qcocoaautoreleasepool.mm b/src/plugins/platforms/cocoa/qcocoaautoreleasepool.mm deleted file mode 100644 index 8f30365186..0000000000 --- a/src/plugins/platforms/cocoa/qcocoaautoreleasepool.mm +++ /dev/null @@ -1,48 +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 "qcocoaautoreleasepool.h" - -QT_BEGIN_NAMESPACE - -QCocoaAutoReleasePool::QCocoaAutoReleasePool() -{ - pool = [[NSAutoreleasePool alloc] init]; -} - -QCocoaAutoReleasePool::~QCocoaAutoReleasePool() -{ - [pool release]; -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index 3737584c4c..5a199de4a5 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -49,12 +49,12 @@ public: QCocoaBackingStore(QWindow *window); ~QCocoaBackingStore(); - QPaintDevice *paintDevice(); - void flush(QWindow *widget, const QRegion ®ion, const QPoint &offset); - QImage toImage() const; - void resize (const QSize &size, const QRegion &); - bool scroll(const QRegion &area, int dx, int dy); - void beginPaint(const QRegion ®ion); + QPaintDevice *paintDevice() Q_DECL_OVERRIDE; + void flush(QWindow *widget, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; + QImage toImage() const Q_DECL_OVERRIDE; + void resize (const QSize &size, const QRegion &) Q_DECL_OVERRIDE; + bool scroll(const QRegion &area, int dx, int dy) Q_DECL_OVERRIDE; + void beginPaint(const QRegion ®ion) Q_DECL_OVERRIDE; qreal getBackingStoreDevicePixelRatio(); private: diff --git a/src/plugins/platforms/cocoa/qcocoaclipboard.h b/src/plugins/platforms/cocoa/qcocoaclipboard.h index e3df9a99b1..e53942b068 100644 --- a/src/plugins/platforms/cocoa/qcocoaclipboard.h +++ b/src/plugins/platforms/cocoa/qcocoaclipboard.h @@ -47,10 +47,10 @@ class QCocoaClipboard : public QObject, public QPlatformClipboard public: QCocoaClipboard(); - QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard); - void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard); - bool supportsMode(QClipboard::Mode mode) const; - bool ownsMode(QClipboard::Mode mode) const; + QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) Q_DECL_OVERRIDE; + void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard) Q_DECL_OVERRIDE; + bool supportsMode(QClipboard::Mode mode) const Q_DECL_OVERRIDE; + bool ownsMode(QClipboard::Mode mode) const Q_DECL_OVERRIDE; private Q_SLOTS: void handleApplicationStateChanged(Qt::ApplicationState state); diff --git a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h index 3183705330..705f97cd2a 100644 --- a/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h +++ b/src/plugins/platforms/cocoa/qcocoacolordialoghelper.h @@ -43,14 +43,14 @@ class QCocoaColorDialogHelper : public QPlatformColorDialogHelper { public: QCocoaColorDialogHelper(); - virtual ~QCocoaColorDialogHelper(); + ~QCocoaColorDialogHelper(); - void exec(); - bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent); - void hide(); + void exec() Q_DECL_OVERRIDE; + bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) Q_DECL_OVERRIDE; + void hide() Q_DECL_OVERRIDE; - void setCurrentColor(const QColor&); - QColor currentColor() const; + void setCurrentColor(const QColor&) Q_DECL_OVERRIDE; + QColor currentColor() const Q_DECL_OVERRIDE; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoacursor.h b/src/plugins/platforms/cocoa/qcocoacursor.h index cc6cbaf59e..d104939f0c 100644 --- a/src/plugins/platforms/cocoa/qcocoacursor.h +++ b/src/plugins/platforms/cocoa/qcocoacursor.h @@ -47,9 +47,9 @@ public: QCocoaCursor(); ~QCocoaCursor(); - virtual void changeCursor(QCursor *cursor, QWindow *window); - virtual QPoint pos() const; - virtual void setPos(const QPoint &position); + void changeCursor(QCursor *cursor, QWindow *window) Q_DECL_OVERRIDE; + QPoint pos() const Q_DECL_OVERRIDE; + void setPos(const QPoint &position) Q_DECL_OVERRIDE; private: QHash<Qt::CursorShape, NSCursor *> m_cursors; NSCursor *convertCursor(QCursor *cursor); diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm index 922809f90d..2098f0dc8c 100644 --- a/src/plugins/platforms/cocoa/qcocoacursor.mm +++ b/src/plugins/platforms/cocoa/qcocoacursor.mm @@ -34,7 +34,6 @@ #include "qcocoacursor.h" #include "qcocoawindow.h" #include "qcocoahelpers.h" -#include "qcocoaautoreleasepool.h" #include <QtGui/QBitmap> diff --git a/src/plugins/platforms/cocoa/qcocoadrag.h b/src/plugins/platforms/cocoa/qcocoadrag.h index e087fcee26..c1eeb34679 100644 --- a/src/plugins/platforms/cocoa/qcocoadrag.h +++ b/src/plugins/platforms/cocoa/qcocoadrag.h @@ -47,13 +47,13 @@ class QCocoaDrag : public QPlatformDrag { public: QCocoaDrag(); - virtual ~QCocoaDrag(); + ~QCocoaDrag(); - virtual QMimeData *platformDropData(); - virtual Qt::DropAction drag(QDrag *m_drag); + QMimeData *platformDropData() Q_DECL_OVERRIDE; + Qt::DropAction drag(QDrag *m_drag) Q_DECL_OVERRIDE; - virtual Qt::DropAction defaultAction(Qt::DropActions possibleActions, - Qt::KeyboardModifiers modifiers) const; + Qt::DropAction defaultAction(Qt::DropActions possibleActions, + Qt::KeyboardModifiers modifiers) const Q_DECL_OVERRIDE; /** * to meet NSView dragImage:at guarantees, we need to record the original diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h index 13a8c89dbb..4a2cb42f87 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h @@ -80,7 +80,6 @@ // #include <QtCore/qabstracteventdispatcher.h> -#include <QtCore/qhash.h> #include <QtCore/qstack.h> #include <QtGui/qwindowdefs.h> #include <QtCore/private/qabstracteventdispatcher_p.h> diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm index 52b2e23345..1865624d57 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm @@ -66,13 +66,11 @@ ****************************************************************************/ #include "qcocoaeventdispatcher.h" -#include "qcocoaautoreleasepool.h" #include "qcocoawindow.h" #include "qcocoahelpers.h" #include "qguiapplication.h" #include "qevent.h" -#include "qhash.h" #include "qmutex.h" #include "qsocketnotifier.h" #include <qpa/qplatformwindow.h> @@ -365,7 +363,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) if (d->interrupt) break; - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; NSEvent* event = 0; // First, send all previously excluded input events, if any: @@ -623,7 +621,7 @@ NSModalSession QCocoaEventDispatcherPrivate::currentModalSession() continue; if (!info.session) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(info.window->handle()); NSWindow *nswindow = cocoaWindow->nativeWindow(); if (!nswindow) @@ -671,7 +669,7 @@ void QCocoaEventDispatcherPrivate::updateChildrenWorksWhenModal() // Make the dialog children of the window // active. And make the dialog children of // the previous modal dialog unactive again: - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; int size = cocoaModalSessionStack.size(); if (size > 0){ if (QWindow *prevModal = cocoaModalSessionStack[size-1].window) @@ -692,7 +690,7 @@ void QCocoaEventDispatcherPrivate::cleanupModalSessions() // point they were marked as stopped), is that ending a session // when no other session runs below it on the stack will make cocoa // drop some events on the floor. - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; int stackSize = cocoaModalSessionStack.size(); for (int i=stackSize-1; i>=0; --i) { @@ -927,7 +925,7 @@ void QCocoaEventDispatcherPrivate::cancelWaitForMoreEvents() { // In case the event dispatcher is waiting for more // events somewhere, we post a dummy event to wake it up: - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined location:NSZeroPoint modifierFlags:0 timestamp:0. windowNumber:0 context:0 subtype:QtCocoaEventSubTypeWakeup data1:0 data2:0] atStart:NO]; diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 4ece1b5a22..93ee4e8624 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -53,7 +53,6 @@ #include <qvarlengtharray.h> #include <stdlib.h> #include <qabstracteventdispatcher.h> -#include "qcocoaautoreleasepool.h" #include <QDir> #include <qpa/qplatformnativeinterface.h> @@ -557,7 +556,7 @@ QCocoaFileDialogHelper::~QCocoaFileDialogHelper() { if (!mDelegate) return; - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; [mDelegate release]; mDelegate = 0; } @@ -687,7 +686,7 @@ bool QCocoaFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit void QCocoaFileDialogHelper::createNSOpenSavePanelDelegate() { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; const SharedPointerFileDialogOptions &opts = options(); const QList<QUrl> selectedFiles = opts->initiallySelectedFiles(); @@ -737,7 +736,7 @@ void QCocoaFileDialogHelper::exec() // QEventLoop has been interrupted, and the second-most event loop has not // yet been reactivated (regardless if [NSApp run] is still on the stack)), // showing a native modal dialog will fail. - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; if ([mDelegate runApplicationModalPanel]) emit accept(); else diff --git a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h index 5a241bc242..23266cfa79 100644 --- a/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h +++ b/src/plugins/platforms/cocoa/qcocoafontdialoghelper.h @@ -45,13 +45,13 @@ public: QCocoaFontDialogHelper(); ~QCocoaFontDialogHelper(); - void exec(); + void exec() Q_DECL_OVERRIDE; - bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent); - void hide(); + bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) Q_DECL_OVERRIDE; + void hide() Q_DECL_OVERRIDE; - void setCurrentFont(const QFont &); - QFont currentFont() const; + void setCurrentFont(const QFont &) Q_DECL_OVERRIDE; + QFont currentFont() const Q_DECL_OVERRIDE; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h index 2c8a3e39f3..fa6db018a7 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.h +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h @@ -50,22 +50,22 @@ public: QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, const QVariant &nativeHandle); ~QCocoaGLContext(); - QSurfaceFormat format() const; + QSurfaceFormat format() const Q_DECL_OVERRIDE; - void swapBuffers(QPlatformSurface *surface); + void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; - bool makeCurrent(QPlatformSurface *surface); - void doneCurrent(); + bool makeCurrent(QPlatformSurface *surface) Q_DECL_OVERRIDE; + void doneCurrent() Q_DECL_OVERRIDE; - void (*getProcAddress(const QByteArray &procName)) (); + void (*getProcAddress(const QByteArray &procName)) () Q_DECL_OVERRIDE; void update(); static NSOpenGLPixelFormat *createNSOpenGLPixelFormat(const QSurfaceFormat &format); NSOpenGLContext *nsOpenGLContext() const; - bool isSharing() const; - bool isValid() const; + bool isSharing() const Q_DECL_OVERRIDE; + bool isValid() const Q_DECL_OVERRIDE; void windowWasHidden(); diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index a3c72c58b9..1d8a1c5e70 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -33,7 +33,6 @@ #include "qcocoaglcontext.h" #include "qcocoawindow.h" -#include "qcocoaautoreleasepool.h" #include "qcocoahelpers.h" #include <qdebug.h> #include <QtCore/private/qcore_mac_p.h> @@ -145,7 +144,7 @@ QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLCo if (m_format.renderableType() != QSurfaceFormat::OpenGL) return; - QCocoaAutoReleasePool pool; // For the SG Canvas render thread + QMacAutoReleasePool pool; // For the SG Canvas render thread NSOpenGLPixelFormat *pixelFormat = static_cast <NSOpenGLPixelFormat *>(qcgl_createNSOpenGLPixelFormat(m_format)); m_shareContext = share ? static_cast<QCocoaGLContext *>(share)->nsOpenGLContext() : nil; @@ -218,7 +217,7 @@ bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface) { Q_ASSERT(surface->surface()->supportsOpenGL()); - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; QWindow *window = static_cast<QCocoaWindow *>(surface)->window(); setActiveWindow(window); diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 5f97e2996c..bb493ef2be 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -33,7 +33,6 @@ #include "qcocoahelpers.h" -#include "qcocoaautoreleasepool.h" #include <QtCore> #include <QtGui> @@ -270,10 +269,14 @@ bool operator<(const KeyPair &entry, const Qt::Key &key) return entry.qtKey < key; } -static bool qtKey2CocoaKeySortLessThan(const KeyPair &entry1, const KeyPair &entry2) +struct qtKey2CocoaKeySortLessThan { - return entry1.qtKey < entry2.qtKey; -} + typedef bool result_type; + Q_DECL_CONSTEXPR result_type operator()(const KeyPair &entry1, const KeyPair &entry2) const Q_DECL_NOTHROW + { + return entry1.qtKey < entry2.qtKey; + } +}; static const int NumEntries = 59; static const KeyPair entries[NumEntries] = { @@ -353,7 +356,7 @@ QChar qt_mac_qtKey2CocoaKey(Qt::Key key) mustInit = false; for (int i=0; i<NumEntries; ++i) rev_entries[i] = entries[i]; - std::sort(rev_entries.begin(), rev_entries.end(), qtKey2CocoaKeySortLessThan); + std::sort(rev_entries.begin(), rev_entries.end(), qtKey2CocoaKeySortLessThan()); } const QVector<KeyPair>::iterator i = std::lower_bound(rev_entries.begin(), rev_entries.end(), key); @@ -630,7 +633,7 @@ QString qt_mac_applicationName() int qt_mac_mainScreenHeight() { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; // The first screen in the screens array is documented // to have the (0,0) origin. NSRect screenFrame = [[[NSScreen screens] firstObject] frame]; diff --git a/src/plugins/platforms/cocoa/qcocoainputcontext.h b/src/plugins/platforms/cocoa/qcocoainputcontext.h index abe45344a9..c7df823dc4 100644 --- a/src/plugins/platforms/cocoa/qcocoainputcontext.h +++ b/src/plugins/platforms/cocoa/qcocoainputcontext.h @@ -46,9 +46,9 @@ public: explicit QCocoaInputContext(); ~QCocoaInputContext(); - virtual bool isValid() const { return true; } + bool isValid() const Q_DECL_OVERRIDE { return true; } - virtual void reset(); + void reset() Q_DECL_OVERRIDE; private Q_SLOTS: void connectSignals(); diff --git a/src/plugins/platforms/cocoa/qcocoainputcontext.mm b/src/plugins/platforms/cocoa/qcocoainputcontext.mm index c22fe8774b..f072991bdd 100644 --- a/src/plugins/platforms/cocoa/qcocoainputcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoainputcontext.mm @@ -34,7 +34,6 @@ #include "qnsview.h" #include "qcocoainputcontext.h" #include "qcocoanativeinterface.h" -#include "qcocoaautoreleasepool.h" #include "qcocoawindow.h" #include <QtCore/QRect> @@ -98,7 +97,7 @@ void QCocoaInputContext::reset() if (!view) return; - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; if (NSTextInputContext *ctxt = [NSTextInputContext currentInputContext]) { [ctxt discardMarkedText]; [view unmarkText]; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index 8b5d78826c..32a08dbb0d 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -36,7 +36,6 @@ #include <Cocoa/Cocoa.h> -#include "qcocoaautoreleasepool.h" #include "qcocoacursor.h" #include "qcocoawindow.h" #include "qcocoanativeinterface.h" @@ -74,6 +73,7 @@ public: QPlatformCursor *cursor() const Q_DECL_OVERRIDE { return m_cursor; } QWindow *topLevelAt(const QPoint &point) const Q_DECL_OVERRIDE; QList<QPlatformScreen *> virtualSiblings() const Q_DECL_OVERRIDE { return m_siblings; } + QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const Q_DECL_OVERRIDE; // ---------------------------------------------------- // Additional methods @@ -98,34 +98,40 @@ public: class QCocoaIntegration : public QPlatformIntegration { public: - QCocoaIntegration(); + enum Option { + UseFreeTypeFontEngine = 0x1 + }; + Q_DECLARE_FLAGS(Options, Option) + + QCocoaIntegration(const QStringList ¶mList); ~QCocoaIntegration(); static QCocoaIntegration *instance(); + Options options() const; - bool hasCapability(QPlatformIntegration::Capability cap) const; - QPlatformWindow *createPlatformWindow(QWindow *window) const; + bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE; + QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE; #ifndef QT_NO_OPENGL - QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE; #endif - QPlatformBackingStore *createPlatformBackingStore(QWindow *widget) const; + QPlatformBackingStore *createPlatformBackingStore(QWindow *widget) const Q_DECL_OVERRIDE; - QAbstractEventDispatcher *createEventDispatcher() const; + QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE; - QCoreTextFontDatabase *fontDatabase() const; - QCocoaNativeInterface *nativeInterface() const; - QCocoaInputContext *inputContext() const; - QCocoaAccessibility *accessibility() const; - QCocoaClipboard *clipboard() const; - QCocoaDrag *drag() const; + QCoreTextFontDatabase *fontDatabase() const Q_DECL_OVERRIDE; + QCocoaNativeInterface *nativeInterface() const Q_DECL_OVERRIDE; + QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE; + QCocoaAccessibility *accessibility() const Q_DECL_OVERRIDE; + QCocoaClipboard *clipboard() const Q_DECL_OVERRIDE; + QCocoaDrag *drag() const Q_DECL_OVERRIDE; - QStringList themeNames() const; - QPlatformTheme *createPlatformTheme(const QString &name) const; - QCocoaServices *services() const; - QVariant styleHint(StyleHint hint) const; + QStringList themeNames() const Q_DECL_OVERRIDE; + QPlatformTheme *createPlatformTheme(const QString &name) const Q_DECL_OVERRIDE; + QCocoaServices *services() const Q_DECL_OVERRIDE; + QVariant styleHint(StyleHint hint) const Q_DECL_OVERRIDE; - Qt::KeyboardModifiers queryKeyboardModifiers() const; - QList<int> possibleKeys(const QKeyEvent *event) const; + Qt::KeyboardModifiers queryKeyboardModifiers() const Q_DECL_OVERRIDE; + QList<int> possibleKeys(const QKeyEvent *event) const Q_DECL_OVERRIDE; void updateScreens(); QCocoaScreen *screenAtIndex(int index); @@ -139,13 +145,14 @@ public: QCocoaWindow *activePopupWindow() const; QList<QCocoaWindow *> *popupWindowStack(); - void setApplicationIcon(const QIcon &icon) const; + void setApplicationIcon(const QIcon &icon) const Q_DECL_OVERRIDE; private: static QCocoaIntegration *mInstance; + Options mOptions; QScopedPointer<QCoreTextFontDatabase> mFontDb; - QScopedPointer<QCocoaInputContext> mInputContext; + QScopedPointer<QPlatformInputContext> mInputContext; #ifndef QT_NO_ACCESSIBILITY QScopedPointer<QCocoaAccessibility> mAccessibility; #endif @@ -161,6 +168,8 @@ private: QList<QCocoaWindow *> m_popupWindowStack; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QCocoaIntegration::Options) + QT_END_NAMESPACE #endif diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index c8f6dd05db..051a1c8710 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -33,7 +33,6 @@ #include "qcocoaintegration.h" -#include "qcocoaautoreleasepool.h" #include "qcocoawindow.h" #include "qcocoabackingstore.h" #include "qcocoanativeinterface.h" @@ -48,7 +47,9 @@ #include "qcocoamimetypes.h" #include "qcocoaaccessibility.h" +#include <qpa/qplatforminputcontextfactory_p.h> #include <qpa/qplatformaccessibility.h> +#include <qpa/qplatforminputcontextfactory_p.h> #include <QtCore/qcoreapplication.h> #include <IOKit/graphics/IOGraphicsLib.h> @@ -137,11 +138,21 @@ void QCocoaScreen::updateGeometry() qreal QCocoaScreen::devicePixelRatio() const { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; NSScreen * screen = osScreen(); return qreal(screen ? [screen backingScaleFactor] : 1.0); } +QPlatformScreen::SubpixelAntialiasingType QCocoaScreen::subpixelAntialiasingTypeHint() const +{ + QPlatformScreen::SubpixelAntialiasingType type = QPlatformScreen::subpixelAntialiasingTypeHint(); + if (type == QPlatformScreen::Subpixel_None) { + // Every OSX machine has RGB pixels unless a peculiar or rotated non-Apple screen is attached + type = QPlatformScreen::Subpixel_RGB; + } + return type; +} + QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const { NSPoint screenPoint = qt_mac_flipPoint(point); @@ -244,11 +255,25 @@ QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height return windowPixmap; } +static QCocoaIntegration::Options parseOptions(const QStringList ¶mList) +{ + QCocoaIntegration::Options options; + foreach (const QString ¶m, paramList) { +#ifndef QT_NO_FREETYPE + if (param == QLatin1String("fontengine=freetype")) + options |= QCocoaIntegration::UseFreeTypeFontEngine; + else +#endif + qWarning() << "Unknown option" << param; + } + return options; +} + QCocoaIntegration *QCocoaIntegration::mInstance = 0; -QCocoaIntegration::QCocoaIntegration() - : mFontDb(new QCoreTextFontDatabase()) - , mInputContext(new QCocoaInputContext) +QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) + : mOptions(parseOptions(paramList)) + , mFontDb(new QCoreTextFontDatabase(mOptions.testFlag(UseFreeTypeFontEngine))) #ifndef QT_NO_ACCESSIBILITY , mAccessibility(new QCocoaAccessibility) #endif @@ -262,8 +287,12 @@ QCocoaIntegration::QCocoaIntegration() qWarning("Creating multiple Cocoa platform integrations is not supported"); mInstance = this; + QString icStr = QPlatformInputContextFactory::requested(); + icStr.isNull() ? mInputContext.reset(new QCocoaInputContext) + : mInputContext.reset(QPlatformInputContextFactory::create(icStr)); + initResources(); - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; qApp->setAttribute(Qt::AA_DontUseNativeMenuBar, false); @@ -314,7 +343,7 @@ QCocoaIntegration::~QCocoaIntegration() qt_resetNSApplicationSendEvent(); - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; if (!QCoreApplication::testAttribute(Qt::AA_MacPluginApplication)) { // remove the apple event handlers installed by QCocoaApplicationDelegate QCocoaApplicationDelegate *delegate = [QCocoaApplicationDelegate sharedDelegate]; @@ -342,6 +371,11 @@ QCocoaIntegration *QCocoaIntegration::instance() return mInstance; } +QCocoaIntegration::Options QCocoaIntegration::options() const +{ + return mOptions; +} + /*! \brief Synchronizes the screen list, adds new screens, removes deleted ones */ @@ -463,7 +497,7 @@ QCocoaNativeInterface *QCocoaIntegration::nativeInterface() const return mNativeInterface.data(); } -QCocoaInputContext *QCocoaIntegration::inputContext() const +QPlatformInputContext *QCocoaIntegration::inputContext() const { return mInputContext.data(); } diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h index 59807deb5a..eccc5230b5 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.h +++ b/src/plugins/platforms/cocoa/qcocoamenu.h @@ -49,29 +49,29 @@ public: QCocoaMenu(); ~QCocoaMenu(); - inline virtual void setTag(quintptr tag) - { m_tag = tag; } - inline virtual quintptr tag() const - { return m_tag; } - - void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before); - void removeMenuItem(QPlatformMenuItem *menuItem); - void syncMenuItem(QPlatformMenuItem *menuItem); - void setEnabled(bool enabled); - bool isEnabled() const; - void setVisible(bool visible); - void showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item); - void dismiss(); - - void syncSeparatorsCollapsible(bool enable); + void setTag(quintptr tag) Q_DECL_OVERRIDE + { m_tag = tag; } + quintptr tag() const Q_DECL_OVERRIDE + { return m_tag; } + + void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) Q_DECL_OVERRIDE; + void removeMenuItem(QPlatformMenuItem *menuItem) Q_DECL_OVERRIDE; + void syncMenuItem(QPlatformMenuItem *menuItem) Q_DECL_OVERRIDE; + void setEnabled(bool enabled) Q_DECL_OVERRIDE; + bool isEnabled() const Q_DECL_OVERRIDE; + void setVisible(bool visible) Q_DECL_OVERRIDE; + void showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item) Q_DECL_OVERRIDE; + void dismiss() Q_DECL_OVERRIDE; + + void syncSeparatorsCollapsible(bool enable) Q_DECL_OVERRIDE; void syncModalState(bool modal); - virtual void setIcon(const QIcon &icon) { Q_UNUSED(icon) } + void setIcon(const QIcon &icon) Q_DECL_OVERRIDE { Q_UNUSED(icon) } - void setText(const QString &text); - void setMinimumWidth(int width); - void setFont(const QFont &font); + void setText(const QString &text) Q_DECL_OVERRIDE; + void setMinimumWidth(int width) Q_DECL_OVERRIDE; + void setFont(const QFont &font) Q_DECL_OVERRIDE; inline NSMenu *nsMenu() const { return m_nativeMenu; } @@ -80,8 +80,8 @@ public: inline bool isVisible() const { return m_visible; } - virtual QPlatformMenuItem *menuItemAt(int position) const; - virtual QPlatformMenuItem *menuItemForTag(quintptr tag) const; + QPlatformMenuItem *menuItemAt(int position) const Q_DECL_OVERRIDE; + QPlatformMenuItem *menuItemForTag(quintptr tag) const Q_DECL_OVERRIDE; QList<QCocoaMenuItem *> items() const; QList<QCocoaMenuItem *> merged() const; diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 6668080725..57739f3a58 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -34,7 +34,6 @@ #include "qcocoamenu.h" #include "qcocoahelpers.h" -#include "qcocoaautoreleasepool.h" #include <QtCore/QtDebug> #include <QtCore/qmetaobject.h> @@ -235,7 +234,7 @@ QCocoaMenu::QCocoaMenu() : m_menuBar(0), m_containingMenuItem(0) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; m_delegate = [[QCocoaMenuDelegate alloc] initWithMenu:this]; m_nativeItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; @@ -255,7 +254,7 @@ QCocoaMenu::~QCocoaMenu() if (m_containingMenuItem) m_containingMenuItem->clearMenu(this); - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; [m_nativeItem setSubmenu:nil]; [m_nativeMenu release]; [m_delegate release]; @@ -264,7 +263,7 @@ QCocoaMenu::~QCocoaMenu() void QCocoaMenu::setText(const QString &text) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; QString stripped = qt_mac_removeAmpersandEscapes(text); [m_nativeMenu setTitle:QCFString::toNSString(stripped)]; [m_nativeItem setTitle:QCFString::toNSString(stripped)]; @@ -286,7 +285,7 @@ void QCocoaMenu::setFont(const QFont &font) void QCocoaMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; QCocoaMenuItem *cocoaItem = static_cast<QCocoaMenuItem *>(menuItem); QCocoaMenuItem *beforeItem = static_cast<QCocoaMenuItem *>(before); @@ -340,7 +339,7 @@ void QCocoaMenu::insertNative(QCocoaMenuItem *item, QCocoaMenuItem *beforeItem) void QCocoaMenu::removeMenuItem(QPlatformMenuItem *menuItem) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; QCocoaMenuItem *cocoaItem = static_cast<QCocoaMenuItem *>(menuItem); if (!m_menuItems.contains(cocoaItem)) { qWarning() << Q_FUNC_INFO << "Menu does not contain the item to be removed"; @@ -370,7 +369,7 @@ QCocoaMenuItem *QCocoaMenu::itemOrNull(int index) const void QCocoaMenu::syncMenuItem(QPlatformMenuItem *menuItem) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; QCocoaMenuItem *cocoaItem = static_cast<QCocoaMenuItem *>(menuItem); if (!m_menuItems.contains(cocoaItem)) { qWarning() << Q_FUNC_INFO << "Item does not belong to this menu"; @@ -399,7 +398,7 @@ void QCocoaMenu::syncMenuItem(QPlatformMenuItem *menuItem) void QCocoaMenu::syncSeparatorsCollapsible(bool enable) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; if (enable) { bool previousIsSeparator = true; // setting to true kills all the separators placed at the top. NSMenuItem *previousItem = nil; @@ -457,7 +456,7 @@ void QCocoaMenu::setVisible(bool visible) void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; QPoint pos = QPoint(targetRect.left(), targetRect.top() + targetRect.height()); QCocoaWindow *cocoaWindow = parentWindow ? static_cast<QCocoaWindow *>(parentWindow->handle()) : 0; @@ -562,7 +561,7 @@ QList<QCocoaMenuItem *> QCocoaMenu::merged() const void QCocoaMenu::syncModalState(bool modal) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; if (!m_enabled) modal = true; diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.h b/src/plugins/platforms/cocoa/qcocoamenubar.h index b5ee21ca52..d5f75abf34 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.h +++ b/src/plugins/platforms/cocoa/qcocoamenubar.h @@ -48,13 +48,13 @@ class QCocoaMenuBar : public QPlatformMenuBar Q_OBJECT public: QCocoaMenuBar(); - virtual ~QCocoaMenuBar(); + ~QCocoaMenuBar(); - virtual void insertMenu(QPlatformMenu *menu, QPlatformMenu* before); - virtual void removeMenu(QPlatformMenu *menu); - virtual void syncMenu(QPlatformMenu *menuItem); - virtual void handleReparent(QWindow *newParentWindow); - virtual QPlatformMenu *menuForTag(quintptr tag) const; + void insertMenu(QPlatformMenu *menu, QPlatformMenu* before) Q_DECL_OVERRIDE; + void removeMenu(QPlatformMenu *menu) Q_DECL_OVERRIDE; + void syncMenu(QPlatformMenu *menuItem) Q_DECL_OVERRIDE; + void handleReparent(QWindow *newParentWindow) Q_DECL_OVERRIDE; + QPlatformMenu *menuForTag(quintptr tag) const Q_DECL_OVERRIDE; inline NSMenu *nsMenu() const { return m_nativeMenu; } diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm index 764a01370d..7775cdbde6 100644 --- a/src/plugins/platforms/cocoa/qcocoamenubar.mm +++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm @@ -37,7 +37,7 @@ #include "qcocoawindow.h" #include "qcocoamenuloader.h" #include "qcocoaapplication.h" // for custom application category -#include "qcocoaautoreleasepool.h" +#include "qcocoaapplicationdelegate.h" #include <QtGui/QGuiApplication> #include <QtCore/QDebug> @@ -83,7 +83,7 @@ QCocoaMenuBar::~QCocoaMenuBar() void QCocoaMenuBar::insertNativeMenu(QCocoaMenu *menu, QCocoaMenu *beforeMenu) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; if (beforeMenu) { NSUInteger nativeIndex = [m_nativeMenu indexOfItem:beforeMenu->nsMenuItem()]; @@ -126,7 +126,7 @@ void QCocoaMenuBar::insertMenu(QPlatformMenu *platformMenu, QPlatformMenu *befor void QCocoaMenuBar::removeNativeMenu(QCocoaMenu *menu) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; if (menu->menuBar() == this) menu->setMenuBar(0); @@ -147,7 +147,7 @@ void QCocoaMenuBar::removeMenu(QPlatformMenu *platformMenu) void QCocoaMenuBar::syncMenu(QPlatformMenu *menu) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; QCocoaMenu *cocoaMenu = static_cast<QCocoaMenu *>(menu); Q_FOREACH (QCocoaMenuItem *item, cocoaMenu->items()) @@ -260,13 +260,26 @@ void QCocoaMenuBar::resetKnownMenuItemsToQt() void QCocoaMenuBar::updateMenuBarImmediately() { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; QCocoaMenuBar *mb = findGlobalMenubar(); QCocoaWindow *cw = findWindowForMenubar(); QWindow *win = cw ? cw->window() : 0; - if (win && (win->flags() & Qt::Popup) == Qt::Popup) - return; // context menus, comboboxes, etc. don't need to update the menubar + if (win && (win->flags() & Qt::Popup) == Qt::Popup) { + // context menus, comboboxes, etc. don't need to update the menubar, + // but if an application has only Qt::Tool window(s) on start, + // we still have to update the menubar. + if ((win->flags() & Qt::WindowType_Mask) != Qt::Tool) + return; + typedef QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) AppDelegate; + NSApplication *app = [NSApplication sharedApplication]; + if (![app.delegate isKindOfClass:[AppDelegate class]]) + return; + // We apply this logic _only_ during the startup. + AppDelegate *appDelegate = app.delegate; + if (!appDelegate.inLaunch) + return; + } if (cw && cw->menubar()) mb = cw->menubar(); diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h index 5c85824ab8..289f38fd18 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.h +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h @@ -60,27 +60,27 @@ class QCocoaMenuItem : public QPlatformMenuItem { public: QCocoaMenuItem(); - virtual ~QCocoaMenuItem(); + ~QCocoaMenuItem(); - inline virtual void setTag(quintptr tag) + void setTag(quintptr tag) Q_DECL_OVERRIDE { m_tag = tag; } - inline virtual quintptr tag() const + quintptr tag() const Q_DECL_OVERRIDE { return m_tag; } - void setText(const QString &text); - void setIcon(const QIcon &icon); - void setMenu(QPlatformMenu *menu); - void setVisible(bool isVisible); - void setIsSeparator(bool isSeparator); - void setFont(const QFont &font); - void setRole(MenuRole role); - void setShortcut(const QKeySequence& shortcut); - void setCheckable(bool checkable) { Q_UNUSED(checkable) } - void setChecked(bool isChecked); - void setEnabled(bool isEnabled); - void setIconSize(int size); - - void setNativeContents(WId item); + void setText(const QString &text) Q_DECL_OVERRIDE; + void setIcon(const QIcon &icon) Q_DECL_OVERRIDE; + void setMenu(QPlatformMenu *menu) Q_DECL_OVERRIDE; + void setVisible(bool isVisible) Q_DECL_OVERRIDE; + void setIsSeparator(bool isSeparator) Q_DECL_OVERRIDE; + void setFont(const QFont &font) Q_DECL_OVERRIDE; + void setRole(MenuRole role) Q_DECL_OVERRIDE; + void setShortcut(const QKeySequence& shortcut) Q_DECL_OVERRIDE; + void setCheckable(bool checkable) Q_DECL_OVERRIDE { Q_UNUSED(checkable) } + void setChecked(bool isChecked) Q_DECL_OVERRIDE; + void setEnabled(bool isEnabled) Q_DECL_OVERRIDE; + void setIconSize(int size) Q_DECL_OVERRIDE; + + void setNativeContents(WId item) Q_DECL_OVERRIDE; inline QString text() const { return m_text; } inline NSMenuItem * nsItem() { return m_native; } diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index f288ab85c0..942fc8db21 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -37,7 +37,6 @@ #include "qcocoamenubar.h" #include "messages.h" #include "qcocoahelpers.h" -#include "qcocoaautoreleasepool.h" #include "qt_mac_p.h" #include "qcocoaapplication.h" // for custom application category #include "qcocoamenuloader.h" @@ -104,7 +103,7 @@ QCocoaMenuItem::QCocoaMenuItem() : QCocoaMenuItem::~QCocoaMenuItem() { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; if (m_menu && COCOA_MENU_ANCESTOR(m_menu) == this) SET_COCOA_MENU_ANCESTOR(m_menu, 0); @@ -139,7 +138,7 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu) m_menu->setContainingMenuItem(0); } - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; m_menu = static_cast<QCocoaMenu *>(menu); if (m_menu) { SET_COCOA_MENU_ANCESTOR(m_menu, this); diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.h b/src/plugins/platforms/cocoa/qcocoanativeinterface.h index 2250f7c084..d018c05635 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.h +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.h @@ -67,6 +67,8 @@ public: static void *nsOpenGLContextForContext(QOpenGLContext* context); #endif + QFunctionPointer platformFunction(const QByteArray &function) const Q_DECL_OVERRIDE; + public Q_SLOTS: void onAppFocusWindowChanged(QWindow *window); diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm index 205a49d25a..41ea1fa49c 100644 --- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm +++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm @@ -58,6 +58,8 @@ #include <qpa/qplatformprintersupport.h> #endif +#include <QtPlatformHeaders/qcocoawindowfunctions.h> + #include <Cocoa/Cocoa.h> QT_BEGIN_NAMESPACE @@ -217,6 +219,14 @@ void *QCocoaNativeInterface::nsOpenGLContextForContext(QOpenGLContext* context) } #endif +QFunctionPointer QCocoaNativeInterface::platformFunction(const QByteArray &function) const +{ + if (function == QCocoaWindowFunctions::bottomLeftClippedByNSWindowOffsetIdentifier()) + return QFunctionPointer(QCocoaWindowFunctions::BottomLeftClippedByNSWindowOffset(QCocoaWindow::bottomLeftClippedByNSWindowOffsetStatic)); + + return Q_NULLPTR; +} + void QCocoaNativeInterface::addToMimeList(void *macPasteboardMime) { qt_mac_addToGlobalMimeList(reinterpret_cast<QMacInternalPasteboardMime *>(macPasteboardMime)); @@ -234,7 +244,7 @@ void QCocoaNativeInterface::registerDraggedTypes(const QStringList &types) void QCocoaNativeInterface::setDockMenu(QPlatformMenu *platformMenu) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; QCocoaMenu *cocoaPlatformMenu = static_cast<QCocoaMenu *>(platformMenu); NSMenu *menu = cocoaPlatformMenu->nsMenu(); [NSApp QT_MANGLE_NAMESPACE(qt_setDockMenu): menu]; diff --git a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm index 4d319e149b..b0d04f6f82 100644 --- a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm +++ b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm @@ -100,7 +100,7 @@ QCocoaPrintDevice::~QCocoaPrintDevice() { if (m_ppd) ppdClose(m_ppd); - foreach (PMPaper paper, m_macPapers.values()) + foreach (PMPaper paper, m_macPapers) PMRelease(paper); // Releasing the session appears to also release the printer if (m_session) @@ -154,7 +154,7 @@ QPageSize QCocoaPrintDevice::createPageSize(const PMPaper &paper) const void QCocoaPrintDevice::loadPageSizes() const { m_pageSizes.clear(); - foreach (PMPaper paper, m_macPapers.values()) + foreach (PMPaper paper, m_macPapers) PMRelease(paper); m_macPapers.clear(); m_printableMargins.clear(); diff --git a/src/plugins/platforms/cocoa/qcocoaservices.h b/src/plugins/platforms/cocoa/qcocoaservices.h index 331fe810fa..1a447c6242 100644 --- a/src/plugins/platforms/cocoa/qcocoaservices.h +++ b/src/plugins/platforms/cocoa/qcocoaservices.h @@ -41,8 +41,8 @@ QT_BEGIN_NAMESPACE class QCocoaServices : public QPlatformServices { public: - bool openUrl(const QUrl &url); - bool openDocument(const QUrl &url); + bool openUrl(const QUrl &url) Q_DECL_OVERRIDE; + bool openDocument(const QUrl &url) Q_DECL_OVERRIDE; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm index 65cc9bc38b..93f8b2ba6f 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm @@ -33,7 +33,6 @@ #include "qcocoasystemsettings.h" -#include "qcocoaautoreleasepool.h" #include "qcocoahelpers.h" #include <QtCore/private/qcore_mac_p.h> @@ -45,7 +44,7 @@ QT_BEGIN_NAMESPACE QColor qt_mac_colorForTheme(ThemeBrush brush) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; QCFType<CGColorRef> cgClr = 0; HIThemeBrushCreateCGColor(brush, &cgClr); diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h index b5f038094f..cdfd92c0aa 100755..100644 --- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h +++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h @@ -51,17 +51,17 @@ class Q_GUI_EXPORT QCocoaSystemTrayIcon : public QPlatformSystemTrayIcon public: QCocoaSystemTrayIcon() : m_sys(0) {} - virtual void init(); - virtual void cleanup(); - virtual void updateIcon(const QIcon &icon); - virtual void updateToolTip(const QString &toolTip); - virtual void updateMenu(QPlatformMenu *menu); - virtual QRect geometry() const; - virtual void showMessage(const QString &title, const QString &msg, - const QIcon& icon, MessageIcon iconType, int secs); + void init() Q_DECL_OVERRIDE; + void cleanup() Q_DECL_OVERRIDE; + void updateIcon(const QIcon &icon) Q_DECL_OVERRIDE; + void updateToolTip(const QString &toolTip) Q_DECL_OVERRIDE; + void updateMenu(QPlatformMenu *menu) Q_DECL_OVERRIDE; + QRect geometry() const Q_DECL_OVERRIDE; + void showMessage(const QString &title, const QString &msg, + const QIcon& icon, MessageIcon iconType, int secs) Q_DECL_OVERRIDE; - virtual bool isSystemTrayAvailable() const; - virtual bool supportsMessages() const; + bool isSystemTrayAvailable() const Q_DECL_OVERRIDE; + bool supportsMessages() const Q_DECL_OVERRIDE; private: QSystemTrayIconSys *m_sys; diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm index 713758cc7e..a3ffb5be66 100755..100644 --- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm @@ -252,6 +252,7 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon) } NSImage *nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(fullHeightPixmap)); + [nsimage setTemplate:icon.isMask()]; [(NSImageView*)[[m_sys->item item] view] setImage: nsimage]; [nsimage release]; } diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index 11749e14de..4b73d0af08 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -47,7 +47,6 @@ #include "qcocoamenu.h" #include "qcocoamenubar.h" #include "qcocoahelpers.h" -#include "qcocoaautoreleasepool.h" #include <QtCore/qfileinfo.h> #include <QtGui/private/qguiapplication_p.h> @@ -253,7 +252,7 @@ QPixmap QCocoaTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &siz QPlatformTheme::IconOptions iconOptions) const { Q_UNUSED(iconOptions); - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; NSImage *iconImage = [[NSWorkspace sharedWorkspace] iconForFile:QCFString::toNSString(fileInfo.canonicalFilePath())]; if (!iconImage) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 455d4a8580..51679116b5 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -227,6 +227,9 @@ public: void updateExposedGeometry(); QWindow *childWindowAt(QPoint windowPoint); bool shouldRefuseKeyWindowAndFirstResponder(); + + static QPoint bottomLeftClippedByNSWindowOffsetStatic(QWindow *window); + QPoint bottomLeftClippedByNSWindowOffset() const; protected: void recreateWindow(const QPlatformWindow *parentWindow); QCocoaNSWindow *createNSWindow(); @@ -234,7 +237,7 @@ protected: bool shouldUseNSPanel(); - QRect windowGeometry() const; + QRect nativeWindowGeometry() const; QCocoaWindow *parentCocoaWindow() const; void syncWindowState(Qt::WindowState newState); void reinsertChildWindow(QCocoaWindow *child); @@ -245,6 +248,8 @@ public: // for QNSView friend class QCocoaBackingStore; friend class QCocoaNativeInterface; + void removeMonitor(); + NSView *m_contentView; QNSView *m_qtView; QCocoaNSWindow *m_nsWindow; @@ -269,6 +274,7 @@ public: // for QNSView bool m_inConstructor; bool m_inSetVisible; bool m_inSetGeometry; + bool m_inSetStyleMask; #ifndef QT_NO_OPENGL QCocoaGLContext *m_glContext; #endif diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 3188463dbe..5606f050a3 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -33,7 +33,6 @@ #include "qcocoawindow.h" #include "qcocoaintegration.h" #include "qnswindowdelegate.h" -#include "qcocoaautoreleasepool.h" #include "qcocoaeventdispatcher.h" #ifndef QT_NO_OPENGL #include "qcocoaglcontext.h" @@ -350,6 +349,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) , m_inConstructor(true) , m_inSetVisible(false) , m_inSetGeometry(false) + , m_inSetStyleMask(false) #ifndef QT_NO_OPENGL , m_glContext(0) #endif @@ -373,7 +373,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) #ifdef QT_COCOA_ENABLE_WINDOW_DEBUG qDebug() << "QCocoaWindow::QCocoaWindow" << this; #endif - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; if (tlw->type() == Qt::ForeignWindow) { NSView *foreignView = (NSView *)WId(tlw->property("_q_foreignWinId").value<WId>()); @@ -409,7 +409,7 @@ QCocoaWindow::~QCocoaWindow() qDebug() << "QCocoaWindow::~QCocoaWindow" << this; #endif - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; [m_nsWindow setContentView:nil]; [m_nsWindow.helper detachFromPlatformWindow]; if (m_isNSWindowChild) { @@ -419,6 +419,8 @@ QCocoaWindow::~QCocoaWindow() [m_contentView removeFromSuperview]; } + removeMonitor(); + // Make sure to disconnect observer in all case if view is valid // to avoid notifications received when deleting when using Qt::AA_NativeWindows attribute if (m_qtView) { @@ -499,7 +501,7 @@ QRect QCocoaWindow::geometry() const void QCocoaWindow::setCocoaGeometry(const QRect &rect) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; if (m_contentViewIsEmbedded) { QPlatformWindow::setGeometry(rect); @@ -604,7 +606,7 @@ void QCocoaWindow::show(bool becauseOfAncestor) && !m_hiddenByClipping) { // ... NOR clipped if (m_isNSWindowChild) { m_hiddenByAncestor = false; - setCocoaGeometry(window()->geometry()); + setCocoaGeometry(windowGeometry()); } if (!m_hiddenByClipping) { // setCocoaGeometry() can change the clipping status [m_nsWindow orderFront:nil]; @@ -623,7 +625,7 @@ void QCocoaWindow::setVisible(bool visible) m_inSetVisible = true; - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; QCocoaWindow *parentCocoaWindow = 0; if (window()->transientParent()) parentCocoaWindow = static_cast<QCocoaWindow *>(window()->transientParent()->handle()); @@ -643,7 +645,7 @@ void QCocoaWindow::setVisible(bool visible) if (parentCocoaWindow) { // The parent window might have moved while this window was hidden, // update the window geometry if there is a parent. - setGeometry(window()->geometry()); + setGeometry(windowGeometry()); if (window()->type() == Qt::Popup) { // QTBUG-30266: a window should not be resizable while a transient popup is open @@ -696,6 +698,7 @@ void QCocoaWindow::setVisible(bool visible) && [m_nsWindow isKindOfClass:[NSPanel class]]) { [(NSPanel *)m_nsWindow setWorksWhenModal:YES]; if (!(parentCocoaWindow && window()->transientParent()->isActive()) && window()->type() == Qt::Popup) { + removeMonitor(); monitor = [NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDownMask|NSRightMouseDownMask|NSOtherMouseDownMask|NSMouseMovedMask handler:^(NSEvent *e) { QPointF localPoint = qt_mac_flipPoint([NSEvent mouseLocation]); QWindowSystemInterface::handleMouseEvent(window(), window()->mapFromGlobal(localPoint.toPoint()), localPoint, @@ -744,10 +747,7 @@ void QCocoaWindow::setVisible(bool visible) } else { [m_contentView setHidden:YES]; } - if (monitor && window()->type() == Qt::Popup) { - [NSEvent removeMonitor:monitor]; - monitor = nil; - } + removeMonitor(); if (window()->type() == Qt::Popup || window()->type() == Qt::ToolTip) QCocoaIntegration::instance()->popupWindowStack()->removeAll(this); @@ -864,8 +864,8 @@ void QCocoaWindow::setWindowZoomButton(Qt::WindowFlags flags) // no-WindowMaximizeButtonHint windows. From a Qt perspective it migth be expected // that the button would be removed in the latter case, but disabling it is more // in line with the platform style guidelines. - bool fixedSizeNoZoom = (window()->minimumSize().isValid() && window()->maximumSize().isValid() - && window()->minimumSize() == window()->maximumSize()); + bool fixedSizeNoZoom = (windowMinimumSize().isValid() && windowMaximumSize().isValid() + && windowMinimumSize() == windowMaximumSize()); bool customizeNoZoom = ((flags & Qt::CustomizeWindowHint) && !(flags & Qt::WindowMaximizeButtonHint)); [[m_nsWindow standardWindowButton:NSWindowZoomButton] setEnabled:!(fixedSizeNoZoom || customizeNoZoom)]; } @@ -875,10 +875,14 @@ void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags) if (m_nsWindow && !m_isNSWindowChild) { NSUInteger styleMask = windowStyleMask(flags); NSInteger level = this->windowLevel(flags); + // While setting style mask we can have -updateGeometry calls on a content + // view with null geometry, reporting an invalid coordinates as a result. + m_inSetStyleMask = true; [m_nsWindow setStyleMask:styleMask]; + m_inSetStyleMask = false; [m_nsWindow setLevel:level]; setWindowShadow(flags); - if (!(styleMask & NSBorderlessWindowMask)) { + if (!(flags & Qt::FramelessWindowHint)) { setWindowTitle(window()->title()); } @@ -905,7 +909,7 @@ void QCocoaWindow::setWindowState(Qt::WindowState state) void QCocoaWindow::setWindowTitle(const QString &title) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; if (!m_nsWindow) return; @@ -916,7 +920,7 @@ void QCocoaWindow::setWindowTitle(const QString &title) void QCocoaWindow::setWindowFilePath(const QString &filePath) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; if (!m_nsWindow) return; @@ -926,7 +930,7 @@ void QCocoaWindow::setWindowFilePath(const QString &filePath) void QCocoaWindow::setWindowIcon(const QIcon &icon) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; NSButton *iconButton = [m_nsWindow standardWindowButton:NSWindowDocumentIconButton]; if (iconButton == nil) { @@ -1044,26 +1048,26 @@ bool QCocoaWindow::isOpaque() const void QCocoaWindow::propagateSizeHints() { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; if (!m_nsWindow) return; #ifdef QT_COCOA_ENABLE_WINDOW_DEBUG qDebug() << "QCocoaWindow::propagateSizeHints" << this; - qDebug() << " min/max " << window()->minimumSize() << window()->maximumSize(); - qDebug() << "size increment" << window()->sizeIncrement(); - qDebug() << " basesize" << window()->baseSize(); - qDebug() << " geometry" << geometry(); + qDebug() << " min/max" << windowMinimumSize() << windowMaximumSize(); + qDebug() << "size increment" << windowSizeIncrement(); + qDebug() << " basesize" << windowBaseSize(); + qDebug() << " geometry" << windowGeometry(); #endif // Set the minimum content size. - const QSize minimumSize = window()->minimumSize(); + const QSize minimumSize = windowMinimumSize(); if (!minimumSize.isValid()) // minimumSize is (-1, -1) when not set. Make that (0, 0) for Cocoa. [m_nsWindow setContentMinSize : NSMakeSize(0.0, 0.0)]; [m_nsWindow setContentMinSize : NSMakeSize(minimumSize.width(), minimumSize.height())]; // Set the maximum content size. - const QSize maximumSize = window()->maximumSize(); + const QSize maximumSize = windowMaximumSize(); [m_nsWindow setContentMaxSize : NSMakeSize(maximumSize.width(), maximumSize.height())]; // The window may end up with a fixed size; in this case the zoom button should be disabled. @@ -1071,13 +1075,14 @@ void QCocoaWindow::propagateSizeHints() // sizeIncrement is observed to take values of (-1, -1) and (0, 0) for windows that should be // resizable and that have no specific size increment set. Cocoa expects (1.0, 1.0) in this case. - if (!window()->sizeIncrement().isEmpty()) - [m_nsWindow setResizeIncrements : qt_mac_toNSSize(window()->sizeIncrement())]; + const QSize sizeIncrement = windowSizeIncrement(); + if (!sizeIncrement.isEmpty()) + [m_nsWindow setResizeIncrements : qt_mac_toNSSize(sizeIncrement)]; else [m_nsWindow setResizeIncrements : NSMakeSize(1.0, 1.0)]; QRect rect = geometry(); - QSize baseSize = window()->baseSize(); + QSize baseSize = windowBaseSize(); if (!baseSize.isNull() && baseSize.isValid()) { [m_nsWindow setFrame:NSMakeRect(rect.x(), rect.y(), baseSize.width(), baseSize.height()) display:YES]; } @@ -1323,7 +1328,7 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) | NSWindowCollectionBehaviorFullScreenAuxiliary; m_nsWindow.animationBehavior = NSWindowAnimationBehaviorNone; m_nsWindow.collectionBehavior = collectionBehavior; - setCocoaGeometry(window()->geometry()); + setCocoaGeometry(windowGeometry()); QList<QCocoaWindow *> &siblings = m_parentCocoaWindow->m_childWindows; if (siblings.contains(this)) { @@ -1337,7 +1342,7 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) } else { // Child windows have no NSWindow, link the NSViews instead. [m_parentCocoaWindow->m_contentView addSubview : m_contentView]; - QRect rect = window()->geometry(); + QRect rect = windowGeometry(); // Prevent setting a (0,0) window size; causes opengl context // "Invalid Drawable" warnings. if (rect.isNull()) @@ -1387,9 +1392,9 @@ bool QCocoaWindow::shouldUseNSPanel() QCocoaNSWindow * QCocoaWindow::createNSWindow() { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; - QRect rect = initialGeometry(window(), window()->geometry(), defaultWindowWidth, defaultWindowHeight); + QRect rect = initialGeometry(window(), windowGeometry(), defaultWindowWidth, defaultWindowHeight); NSRect frame = qt_mac_flipRect(rect); Qt::WindowType type = window()->type(); @@ -1476,8 +1481,16 @@ void QCocoaWindow::removeChildWindow(QCocoaWindow *child) [m_nsWindow removeChildWindow:child->m_nsWindow]; } +void QCocoaWindow::removeMonitor() +{ + if (!monitor) + return; + [NSEvent removeMonitor:monitor]; + monitor = nil; +} + // Returns the current global screen geometry for the nswindow associated with this window. -QRect QCocoaWindow::windowGeometry() const +QRect QCocoaWindow::nativeWindowGeometry() const { if (!m_nsWindow || m_isNSWindowChild) return geometry(); @@ -1560,7 +1573,7 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState) if (m_normalGeometry.width() < 0) { m_oldWindowFlags = m_windowFlags; window()->setFlags(window()->flags() | Qt::FramelessWindowHint); - m_normalGeometry = windowGeometry(); + m_normalGeometry = nativeWindowGeometry(); setGeometry(screen->geometry()); m_presentationOptions = [NSApp presentationOptions]; [NSApp setPresentationOptions : m_presentationOptions | NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationAutoHideDock]; @@ -1827,6 +1840,24 @@ bool QCocoaWindow::shouldRefuseKeyWindowAndFirstResponder() return false; } +QPoint QCocoaWindow::bottomLeftClippedByNSWindowOffsetStatic(QWindow *window) +{ + if (window->handle()) + return static_cast<QCocoaWindow *>(window->handle())->bottomLeftClippedByNSWindowOffset(); + return QPoint(); +} + +QPoint QCocoaWindow::bottomLeftClippedByNSWindowOffset() const +{ + if (!m_contentView) + return QPoint(); + const NSPoint origin = [m_contentView isFlipped] ? NSMakePoint(0, [m_contentView frame].size.height) + : NSMakePoint(0, 0); + const NSRect visibleRect = [m_contentView visibleRect]; + + return QPoint(visibleRect.origin.x, -visibleRect.origin.y + (origin.y - visibleRect.size.height)); +} + QMargins QCocoaWindow::frameMargins() const { NSRect frameW = [m_nsWindow frame]; diff --git a/src/plugins/platforms/cocoa/qmacclipboard.mm b/src/plugins/platforms/cocoa/qmacclipboard.mm index 3d88a8d5df..f4fd32ffd1 100644 --- a/src/plugins/platforms/cocoa/qmacclipboard.mm +++ b/src/plugins/platforms/cocoa/qmacclipboard.mm @@ -43,7 +43,6 @@ #include <stdlib.h> #include <string.h> #include "qcocoahelpers.h" -#include "qcocoaautoreleasepool.h" QT_BEGIN_NAMESPACE @@ -555,7 +554,7 @@ QMacPasteboard::sync() const QString qt_mac_get_pasteboardString(PasteboardRef paste) { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; NSPasteboard *pb = nil; CFStringRef pbname; if (PasteboardCopyName(paste, &pbname) == noErr) { diff --git a/src/plugins/platforms/cocoa/qmultitouch_mac.mm b/src/plugins/platforms/cocoa/qmultitouch_mac.mm index 6e7ebcc37c..6099add6bb 100644 --- a/src/plugins/platforms/cocoa/qmultitouch_mac.mm +++ b/src/plugins/platforms/cocoa/qmultitouch_mac.mm @@ -173,7 +173,7 @@ QCocoaTouch::getCurrentTouchPointList(NSEvent *event, bool acceptSingleTouch) if (_touchCount != _currentTouches.size()) { // Remove all instances, and basically start from scratch: touchPoints.clear(); - foreach (QCocoaTouch *qcocoaTouch, _currentTouches.values()) { + foreach (QCocoaTouch *qcocoaTouch, _currentTouches) { if (!_updateInternalStateOnly) { qcocoaTouch->_touchPoint.state = Qt::TouchPointReleased; touchPoints.insert(qcocoaTouch->_touchPoint.id, qcocoaTouch->_touchPoint); @@ -190,7 +190,7 @@ QCocoaTouch::getCurrentTouchPointList(NSEvent *event, bool acceptSingleTouch) // touch now (and refake a begin for it later, if needed). if (_updateInternalStateOnly && !wasUpdateInternalStateOnly && !_currentTouches.isEmpty()) { - QCocoaTouch *qcocoaTouch = _currentTouches.values().first(); + QCocoaTouch *qcocoaTouch = _currentTouches.cbegin().value(); qcocoaTouch->_touchPoint.state = Qt::TouchPointReleased; touchPoints.insert(qcocoaTouch->_touchPoint.id, qcocoaTouch->_touchPoint); // Since this last touch also will end up being the first diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index f27335d752..4db55c1b73 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -39,7 +39,6 @@ #include "qnsview.h" #include "qcocoawindow.h" #include "qcocoahelpers.h" -#include "qcocoaautoreleasepool.h" #include "qmultitouch_mac_p.h" #include "qcocoadrag.h" #include <qpa/qplatformintegration.h> @@ -347,6 +346,12 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; if (m_platformWindow->m_nsWindow && geometry == m_platformWindow->geometry()) return; + // It can happen that self.window is nil (if we are changing + // styleMask from/to borderless and content view is being re-parented) + // - this results in an invalid coordinates. + if (m_platformWindow->m_inSetStyleMask && !self.window) + return; + #ifdef QT_COCOA_ENABLE_WINDOW_DEBUG qDebug() << "QNSView::udpateGeometry" << m_platformWindow << geometry; #endif @@ -848,7 +853,7 @@ QT_WARNING_POP { [super updateTrackingAreas]; - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; // NSTrackingInVisibleRect keeps care of updating once the tracking is set up, so bail out early if (m_trackingArea && [[self trackingAreas] containsObject:m_trackingArea]) @@ -1789,7 +1794,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) -(void)registerDragTypes { - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; QStringList customTypes = qt_mac_enabledDraggedTypes(); if (currentCustomDragTypes == 0 || *currentCustomDragTypes != customTypes) { if (currentCustomDragTypes == 0) diff --git a/src/plugins/platforms/cocoa/qprintengine_mac.mm b/src/plugins/platforms/cocoa/qprintengine_mac.mm index 9e8fe8f1c8..edd1d656f0 100644 --- a/src/plugins/platforms/cocoa/qprintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qprintengine_mac.mm @@ -38,7 +38,6 @@ #include <QtCore/qcoreapplication.h> #include <QtCore/qdebug.h> -#include "qcocoaautoreleasepool.h" #ifndef QT_NO_PRINTER @@ -212,6 +211,9 @@ int QMacPrintEngine::metric(QPaintDevice::PaintDeviceMetric m) const case QPaintDevice::PdmDevicePixelRatio: val = 1; break; + case QPaintDevice::PdmDevicePixelRatioScaled: + val = 1 * QPaintDevice::devicePixelRatioFScale(); + break; default: val = 0; qWarning("QPrinter::metric: Invalid metric command"); @@ -230,7 +232,7 @@ void QMacPrintEnginePrivate::initialize() q->gccaps = paintEngine->gccaps; - QCocoaAutoReleasePool pool; + QMacAutoReleasePool pool; printInfo = [[NSPrintInfo alloc] initWithDictionary:[NSDictionary dictionary]]; QList<int> resolutions = m_printDevice->supportedResolutions(); diff --git a/src/plugins/platforms/cocoa/qt_mac_p.h b/src/plugins/platforms/cocoa/qt_mac_p.h index e210f0221f..576e0f9729 100644 --- a/src/plugins/platforms/cocoa/qt_mac_p.h +++ b/src/plugins/platforms/cocoa/qt_mac_p.h @@ -103,17 +103,6 @@ public: } }; -class Q_WIDGETS_EXPORT QMacCocoaAutoReleasePool -{ -private: - void *pool; -public: - QMacCocoaAutoReleasePool(); - ~QMacCocoaAutoReleasePool(); - - inline void *handle() const { return pool; } -}; - QString qt_mac_removeMnemonics(const QString &original); //implemented in qmacstyle_mac.cpp class Q_WIDGETS_EXPORT QMacWindowChangeEvent diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp index fee9ad88fa..40709fc3d0 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintdevice.cpp @@ -113,6 +113,9 @@ int QWindowsDirect2DPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) case QPaintDevice::PdmDevicePixelRatio: return 1; break; + case QPaintDevice::PdmDevicePixelRatioScaled: + return 1 * devicePixelRatioFScale(); + break; case QPaintDevice::PdmWidthMM: case QPaintDevice::PdmHeightMM: return -1; diff --git a/src/plugins/platforms/directfb/qdirectfbconvenience.cpp b/src/plugins/platforms/directfb/qdirectfbconvenience.cpp index e635d4fd22..e1d97d9628 100644 --- a/src/plugins/platforms/directfb/qdirectfbconvenience.cpp +++ b/src/plugins/platforms/directfb/qdirectfbconvenience.cpp @@ -217,7 +217,7 @@ Qt::KeyboardModifiers QDirectFbConvenience::keyboardModifiers(DFBInputDeviceModi modifiers |= Qt::ControlModifier; } if (mask & DIMM_META) { - modifiers | Qt::MetaModifier; + modifiers |= Qt::MetaModifier; } return modifiers; } diff --git a/src/plugins/platforms/eglfs/cursor-atlas.png b/src/plugins/platforms/eglfs/cursor-atlas.png Binary files differindex 40c5b6ef4f..40c5b6ef4f 100755..100644 --- a/src/plugins/platforms/eglfs/cursor-atlas.png +++ b/src/plugins/platforms/eglfs/cursor-atlas.png diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.cpp index 18a66e34f5..f3df1f8445 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.cpp @@ -208,6 +208,7 @@ QEglFSKmsScreen *QEglFSKmsDevice::screenForConnector(drmModeResPtr resources, dr } QList<drmModeModeInfo> modes; + modes.reserve(connector->count_modes); qCDebug(qLcEglfsKmsDebug) << connectorName << "mode count:" << connector->count_modes; for (int i = 0; i < connector->count_modes; i++) { const drmModeModeInfo &mode = connector->modes[i]; @@ -282,7 +283,8 @@ QEglFSKmsScreen *QEglFSKmsDevice::screenForConnector(drmModeResPtr resources, dr selected_mode, false, drmModeGetCrtc(m_dri_fd, crtc_id), - modes + modes, + connectorProperty(connector, QByteArrayLiteral("DPMS")) }; m_crtc_allocator |= (1 << output.crtc_id); @@ -291,6 +293,22 @@ QEglFSKmsScreen *QEglFSKmsDevice::screenForConnector(drmModeResPtr resources, dr return new QEglFSKmsScreen(m_integration, this, output, pos); } +drmModePropertyPtr QEglFSKmsDevice::connectorProperty(drmModeConnectorPtr connector, const QByteArray &name) +{ + drmModePropertyPtr prop; + + for (int i = 0; i < connector->count_props; i++) { + prop = drmModeGetProperty(m_dri_fd, connector->props[i]); + if (!prop) + continue; + if (strcmp(prop->name, name.constData()) == 0) + return prop; + drmModeFreeProperty(prop); + } + + return Q_NULLPTR; +} + void QEglFSKmsDevice::pageFlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data) { Q_UNUSED(fd); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.h index 23fca934e5..411f9a7200 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsdevice.h @@ -78,6 +78,7 @@ private: int crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector); QEglFSKmsScreen *screenForConnector(drmModeResPtr resources, drmModeConnectorPtr connector, QPoint pos); + drmModePropertyPtr connectorProperty(drmModeConnectorPtr connector, const QByteArray &name); static void pageFlipHandler(int fd, unsigned int sequence, diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsintegration.cpp index 45224ccb87..d1814fb85d 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsintegration.cpp @@ -36,8 +36,8 @@ #include "qeglfskmsdevice.h" #include "qeglfskmsscreen.h" #include "qeglfskmscursor.h" +#include "qeglfscursor.h" -#include <QtPlatformSupport/private/qeglplatformcursor_p.h> #include <QtPlatformSupport/private/qdevicediscovery_p.h> #include <QtCore/QLoggingCategory> #include <QtCore/QJsonDocument> @@ -176,7 +176,7 @@ QPlatformCursor *QEglFSKmsIntegration::createCursor(QPlatformScreen *screen) con if (m_hwCursor) return Q_NULLPTR; else - return new QEGLPlatformCursor(screen); + return new QEglFSCursor(screen); } void QEglFSKmsIntegration::waitForVSync(QPlatformSurface *surface) const diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.cpp index 5e49c224a0..227c8f9a62 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.cpp @@ -35,11 +35,11 @@ #include "qeglfskmsscreen.h" #include "qeglfskmsdevice.h" #include "qeglfskmscursor.h" +#include "qeglfsintegration.h" #include <QtCore/QLoggingCategory> #include <QtGui/private/qguiapplication_p.h> -#include <QtPlatformSupport/private/qeglplatformintegration_p.h> #include <QtPlatformSupport/private/qfbvthandler_p.h> QT_BEGIN_NAMESPACE @@ -50,7 +50,7 @@ class QEglFSKmsInterruptHandler : public QObject { public: QEglFSKmsInterruptHandler(QEglFSKmsScreen *screen) : m_screen(screen) { - m_vtHandler = static_cast<QEGLPlatformIntegration *>(QGuiApplicationPrivate::platformIntegration())->vtHandler(); + m_vtHandler = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration())->vtHandler(); connect(m_vtHandler, &QFbVtHandler::interrupted, this, &QEglFSKmsInterruptHandler::restoreVideoMode); connect(m_vtHandler, &QFbVtHandler::suspendRequested, this, &QEglFSKmsInterruptHandler::handleSuspendRequest); } @@ -119,6 +119,7 @@ QEglFSKmsScreen::QEglFSKmsScreen(QEglFSKmsIntegration *integration, , m_output(output) , m_pos(position) , m_cursor(Q_NULLPTR) + , m_powerState(PowerStateOn) , m_interruptHandler(new QEglFSKmsInterruptHandler(this)) { m_siblings << this; @@ -126,6 +127,10 @@ QEglFSKmsScreen::QEglFSKmsScreen(QEglFSKmsIntegration *integration, QEglFSKmsScreen::~QEglFSKmsScreen() { + if (m_output.dpms_prop) { + drmModeFreeProperty(m_output.dpms_prop); + m_output.dpms_prop = Q_NULLPTR; + } restoreMode(); if (m_output.saved_crtc) { drmModeFreeCrtc(m_output.saved_crtc); @@ -266,10 +271,12 @@ void QEglFSKmsScreen::flip() &m_output.connector_id, 1, &m_output.modes[m_output.mode]); - if (ret) + if (ret) { qErrnoWarning("Could not set DRM mode!"); - else + } else { m_output.mode_set = true; + setPowerState(PowerStateOn); + } } int ret = drmModePageFlip(m_device->fd(), @@ -314,4 +321,19 @@ qreal QEglFSKmsScreen::refreshRate() const return refresh > 0 ? refresh : 60; } +QPlatformScreen::PowerState QEglFSKmsScreen::powerState() const +{ + return m_powerState; +} + +void QEglFSKmsScreen::setPowerState(QPlatformScreen::PowerState state) +{ + if (!m_output.dpms_prop) + return; + + drmModeConnectorSetProperty(m_device->fd(), m_output.connector_id, + m_output.dpms_prop->prop_id, (int)state); + m_powerState = state; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.h index 4c1b0d02ad..2ce8700478 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.h +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsscreen.h @@ -60,6 +60,7 @@ struct QEglFSKmsOutput bool mode_set; drmModeCrtcPtr saved_crtc; QList<drmModeModeInfo> modes; + drmModePropertyPtr dpms_prop; }; class QEglFSKmsScreen : public QEglFSScreen @@ -103,6 +104,9 @@ public: QEglFSKmsOutput &output() { return m_output; } void restoreMode(); + QPlatformScreen::PowerState powerState() const Q_DECL_OVERRIDE; + void setPowerState(QPlatformScreen::PowerState state) Q_DECL_OVERRIDE; + private: QEglFSKmsIntegration *m_integration; QEglFSKmsDevice *m_device; @@ -117,6 +121,8 @@ private: QList<QPlatformScreen *> m_siblings; + PowerState m_powerState; + struct FrameBuffer { FrameBuffer() : fb(0) {} uint32_t fb; diff --git a/src/plugins/platforms/eglfs/eglfs_device_lib.pro b/src/plugins/platforms/eglfs/eglfs_device_lib.pro index 729290706d..22a32663c7 100644 --- a/src/plugins/platforms/eglfs/eglfs_device_lib.pro +++ b/src/plugins/platforms/eglfs/eglfs_device_lib.pro @@ -26,6 +26,7 @@ DEFINES += QT_BUILD_EGL_DEVICE_LIB SOURCES += $$PWD/qeglfsintegration.cpp \ $$PWD/qeglfswindow.cpp \ $$PWD/qeglfsscreen.cpp \ + $$PWD/qeglfscursor.cpp \ $$PWD/qeglfshooks.cpp \ $$PWD/qeglfscontext.cpp \ $$PWD/qeglfsoffscreenwindow.cpp \ @@ -34,6 +35,7 @@ SOURCES += $$PWD/qeglfsintegration.cpp \ HEADERS += $$PWD/qeglfsintegration.h \ $$PWD/qeglfswindow.h \ $$PWD/qeglfsscreen.h \ + $$PWD/qeglfscursor.h \ $$PWD/qeglfshooks.h \ $$PWD/qeglfscontext.h \ $$PWD/qeglfsoffscreenwindow.h \ diff --git a/src/plugins/platforms/eglfs/qeglfscontext.cpp b/src/plugins/platforms/eglfs/qeglfscontext.cpp index 9216b7a85d..e2223aba43 100644 --- a/src/plugins/platforms/eglfs/qeglfscontext.cpp +++ b/src/plugins/platforms/eglfs/qeglfscontext.cpp @@ -32,15 +32,13 @@ ****************************************************************************/ #include <QtGui/QSurface> -#include <QtDebug> - -#include <QtPlatformSupport/private/qeglplatformcursor_p.h> #include <QtPlatformSupport/private/qeglconvenience_p.h> #include <QtPlatformSupport/private/qeglpbuffer_p.h> +#include "qeglfscontext.h" #include "qeglfswindow.h" #include "qeglfshooks.h" -#include "qeglfscontext.h" +#include "qeglfscursor.h" QT_BEGIN_NAMESPACE @@ -91,7 +89,7 @@ void QEglFSContext::swapBuffers(QPlatformSurface *surface) // draw the cursor if (surface->surface()->surfaceClass() == QSurface::Window) { QPlatformWindow *window = static_cast<QPlatformWindow *>(surface); - if (QEGLPlatformCursor *cursor = qobject_cast<QEGLPlatformCursor *>(window->screen()->cursor())) + if (QEglFSCursor *cursor = qobject_cast<QEglFSCursor *>(window->screen()->cursor())) cursor->paintOnScreen(); } diff --git a/src/plugins/platforms/eglfs/qeglfscursor.cpp b/src/plugins/platforms/eglfs/qeglfscursor.cpp new file mode 100644 index 0000000000..eea130a754 --- /dev/null +++ b/src/plugins/platforms/eglfs/qeglfscursor.cpp @@ -0,0 +1,502 @@ +/**************************************************************************** +** +** 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 "qeglfscursor.h" +#include "qeglfsintegration.h" +#include "qeglfsscreen.h" + +#include <qpa/qwindowsysteminterface.h> +#include <QtGui/QOpenGLContext> +#include <QtGui/QOpenGLShaderProgram> +#include <QtCore/QJsonDocument> +#include <QtCore/QJsonArray> +#include <QtCore/QJsonObject> + +#include <QtGui/private/qguiapplication_p.h> +#include <QtGui/private/qopenglvertexarrayobject_p.h> + +#ifndef GL_VERTEX_ARRAY_BINDING +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +#endif + +QT_BEGIN_NAMESPACE + +QEglFSCursor::QEglFSCursor(QPlatformScreen *screen) + : m_visible(true), + m_screen(static_cast<QEglFSScreen *>(screen)), + m_program(0), + m_textureEntry(0), + m_deviceListener(0), + m_updateRequested(false) +{ + QByteArray hideCursorVal = qgetenv("QT_QPA_EGLFS_HIDECURSOR"); + if (!hideCursorVal.isEmpty()) + m_visible = hideCursorVal.toInt() == 0; + if (!m_visible) + return; + + // Try to load the cursor atlas. If this fails, m_visible is set to false and + // paintOnScreen() and setCurrentCursor() become no-ops. + initCursorAtlas(); + + // initialize the cursor +#ifndef QT_NO_CURSOR + QCursor cursor(Qt::ArrowCursor); + setCurrentCursor(&cursor); +#endif + + m_deviceListener = new QEglFSCursorDeviceListener(this); + connect(QGuiApplicationPrivate::inputDeviceManager(), &QInputDeviceManager::deviceListChanged, + m_deviceListener, &QEglFSCursorDeviceListener::onDeviceListChanged); + updateMouseStatus(); +} + +QEglFSCursor::~QEglFSCursor() +{ + resetResources(); + delete m_deviceListener; +} + +void QEglFSCursor::updateMouseStatus() +{ + m_visible = m_deviceListener->hasMouse(); +} + +bool QEglFSCursorDeviceListener::hasMouse() const +{ + return QGuiApplicationPrivate::inputDeviceManager()->deviceCount(QInputDeviceManager::DeviceTypePointer) > 0; +} + +void QEglFSCursorDeviceListener::onDeviceListChanged(QInputDeviceManager::DeviceType type) +{ + if (type == QInputDeviceManager::DeviceTypePointer) + m_cursor->updateMouseStatus(); +} + +void QEglFSCursor::resetResources() +{ + if (QOpenGLContext::currentContext()) { + delete m_program; + glDeleteTextures(1, &m_cursor.customCursorTexture); + glDeleteTextures(1, &m_cursorAtlas.texture); + } + m_program = 0; + m_cursor.customCursorTexture = 0; + m_cursor.customCursorPending = !m_cursor.customCursorImage.isNull(); + m_cursorAtlas.texture = 0; +} + +void QEglFSCursor::createShaderPrograms() +{ + 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, 1.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_textureEntry = m_program->uniformLocation("texture"); +} + +void QEglFSCursor::createCursorTexture(uint *texture, const QImage &image) +{ + if (!*texture) + glGenTextures(1, texture); + glBindTexture(GL_TEXTURE_2D, *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 /* level */, GL_RGBA, image.width(), image.height(), 0 /* border */, + GL_RGBA, GL_UNSIGNED_BYTE, image.constBits()); +} + +void QEglFSCursor::initCursorAtlas() +{ + static QByteArray json = qgetenv("QT_QPA_EGLFS_CURSOR"); + if (json.isEmpty()) + json = ":/cursor.json"; + + QFile file(QString::fromUtf8(json)); + if (!file.open(QFile::ReadOnly)) { + m_visible = false; + return; + } + + QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); + QJsonObject object = doc.object(); + + QString atlas = object.value(QLatin1String("image")).toString(); + Q_ASSERT(!atlas.isEmpty()); + + const int cursorsPerRow = object.value(QLatin1String("cursorsPerRow")).toDouble(); + Q_ASSERT(cursorsPerRow); + m_cursorAtlas.cursorsPerRow = cursorsPerRow; + + const QJsonArray hotSpots = object.value(QLatin1String("hotSpots")).toArray(); + Q_ASSERT(hotSpots.count() == Qt::LastCursor + 1); + for (int i = 0; i < hotSpots.count(); i++) { + QPoint hotSpot(hotSpots[i].toArray()[0].toDouble(), hotSpots[i].toArray()[1].toDouble()); + m_cursorAtlas.hotSpots << hotSpot; + } + + QImage image = QImage(atlas).convertToFormat(QImage::Format_ARGB32_Premultiplied); + m_cursorAtlas.cursorWidth = image.width() / m_cursorAtlas.cursorsPerRow; + m_cursorAtlas.cursorHeight = image.height() / ((Qt::LastCursor + cursorsPerRow) / cursorsPerRow); + m_cursorAtlas.width = image.width(); + m_cursorAtlas.height = image.height(); + m_cursorAtlas.image = image; +} + +#ifndef QT_NO_CURSOR +void QEglFSCursor::changeCursor(QCursor *cursor, QWindow *window) +{ + Q_UNUSED(window); + const QRect oldCursorRect = cursorRect(); + if (setCurrentCursor(cursor)) + update(oldCursorRect | cursorRect()); +} + +bool QEglFSCursor::setCurrentCursor(QCursor *cursor) +{ + if (!m_visible) + return false; + + const Qt::CursorShape newShape = cursor ? cursor->shape() : Qt::ArrowCursor; + if (m_cursor.shape == newShape && newShape != Qt::BitmapCursor) + return false; + + if (m_cursor.shape == Qt::BitmapCursor) { + m_cursor.customCursorImage = QImage(); + m_cursor.customCursorPending = false; + } + m_cursor.shape = newShape; + if (newShape != Qt::BitmapCursor) { // standard cursor + const float ws = (float)m_cursorAtlas.cursorWidth / m_cursorAtlas.width, + hs = (float)m_cursorAtlas.cursorHeight / m_cursorAtlas.height; + m_cursor.textureRect = QRectF(ws * (m_cursor.shape % m_cursorAtlas.cursorsPerRow), + hs * (m_cursor.shape / m_cursorAtlas.cursorsPerRow), + ws, hs); + m_cursor.hotSpot = m_cursorAtlas.hotSpots[m_cursor.shape]; + m_cursor.texture = m_cursorAtlas.texture; + m_cursor.size = QSize(m_cursorAtlas.cursorWidth, m_cursorAtlas.cursorHeight); + } else { + QImage image = cursor->pixmap().toImage(); + m_cursor.textureRect = QRectF(0, 0, 1, 1); + m_cursor.hotSpot = cursor->hotSpot(); + m_cursor.texture = 0; // will get updated in the next render() + m_cursor.size = image.size(); + m_cursor.customCursorImage = image; + m_cursor.customCursorPending = true; + } + + return true; +} +#endif + +class CursorUpdateEvent : public QEvent +{ +public: + CursorUpdateEvent(const QPoint &pos, const QRegion &rgn) + : QEvent(QEvent::Type(QEvent::User + 1)), + m_pos(pos), + m_region(rgn) + { } + QPoint pos() const { return m_pos; } + QRegion region() const { return m_region; } + +private: + QPoint m_pos; + QRegion m_region; +}; + +bool QEglFSCursor::event(QEvent *e) +{ + if (e->type() == QEvent::User + 1) { + CursorUpdateEvent *ev = static_cast<CursorUpdateEvent *>(e); + m_updateRequested = false; + QWindowSystemInterface::handleExposeEvent(m_screen->topLevelAt(ev->pos()), ev->region()); + QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); + return true; + } + return QPlatformCursor::event(e); +} + +void QEglFSCursor::update(const QRegion &rgn) +{ + if (!m_updateRequested) { + // Must not flush the window system events directly from here since we are likely to + // be a called directly from QGuiApplication's processMouseEvents. Flushing events + // could cause reentering by dispatching more queued mouse events. + m_updateRequested = true; + QCoreApplication::postEvent(this, new CursorUpdateEvent(m_cursor.pos, rgn)); + } +} + +QRect QEglFSCursor::cursorRect() const +{ + return QRect(m_cursor.pos - m_cursor.hotSpot, m_cursor.size); +} + +QPoint QEglFSCursor::pos() const +{ + return m_cursor.pos; +} + +void QEglFSCursor::setPos(const QPoint &pos) +{ + QGuiApplicationPrivate::inputDeviceManager()->setCursorPos(pos); + const QRect oldCursorRect = cursorRect(); + m_cursor.pos = pos; + update(oldCursorRect | cursorRect()); + m_screen->handleCursorMove(m_cursor.pos); +} + +void QEglFSCursor::pointerEvent(const QMouseEvent &event) +{ + if (event.type() != QEvent::MouseMove) + return; + const QRect oldCursorRect = cursorRect(); + m_cursor.pos = event.screenPos().toPoint(); + update(oldCursorRect | cursorRect()); + m_screen->handleCursorMove(m_cursor.pos); +} + +void QEglFSCursor::paintOnScreen() +{ + if (!m_visible) + return; + + const QRectF cr = cursorRect(); + const QRect screenRect(m_screen->geometry()); + const GLfloat x1 = 2 * (cr.left() / screenRect.width()) - 1; + const GLfloat x2 = 2 * (cr.right() / screenRect.width()) - 1; + const GLfloat y1 = 1 - (cr.top() / screenRect.height()) * 2; + const GLfloat y2 = 1 - (cr.bottom() / screenRect.height()) * 2; + QRectF r(QPointF(x1, y1), QPointF(x2, y2)); + + draw(r); +} + +// In order to prevent breaking code doing custom OpenGL rendering while +// expecting the state in the context unchanged, save and restore all the state +// we touch. The exception is Qt Quick where the scenegraph is known to be able +// to deal with the changes we make. +struct StateSaver +{ + StateSaver() { + f = QOpenGLContext::currentContext()->functions(); + vaoHelper = new QOpenGLVertexArrayObjectHelper(QOpenGLContext::currentContext()); + + static bool windowsChecked = false; + static bool shouldSave = true; + if (!windowsChecked) { + windowsChecked = true; + QWindowList windows = QGuiApplication::allWindows(); + if (!windows.isEmpty() && windows[0]->inherits("QQuickWindow")) + shouldSave = false; + } + saved = shouldSave; + if (!shouldSave) + return; + + f->glGetIntegerv(GL_CURRENT_PROGRAM, &program); + f->glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture); + f->glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture); + f->glGetIntegerv(GL_FRONT_FACE, &frontFace); + cull = f->glIsEnabled(GL_CULL_FACE); + depthTest = f->glIsEnabled(GL_DEPTH_TEST); + blend = f->glIsEnabled(GL_BLEND); + f->glGetIntegerv(GL_BLEND_SRC_RGB, blendFunc); + f->glGetIntegerv(GL_BLEND_SRC_ALPHA, blendFunc + 1); + f->glGetIntegerv(GL_BLEND_DST_RGB, blendFunc + 2); + f->glGetIntegerv(GL_BLEND_DST_ALPHA, blendFunc + 3); + f->glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &arrayBuf); + if (vaoHelper->isValid()) + f->glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &vao); + for (int i = 0; i < 2; ++i) { + f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &va[i].enabled); + f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &va[i].size); + f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &va[i].type); + f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &va[i].normalized); + f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &va[i].stride); + f->glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &va[i].buffer); + f->glGetVertexAttribPointerv(i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &va[i].pointer); + } + } + ~StateSaver() { + if (saved) { + f->glUseProgram(program); + f->glBindTexture(GL_TEXTURE_2D, texture); + f->glActiveTexture(activeTexture); + f->glFrontFace(frontFace); + if (cull) + f->glEnable(GL_CULL_FACE); + else + f->glDisable(GL_CULL_FACE); + if (depthTest) + f->glEnable(GL_DEPTH_TEST); + else + f->glDisable(GL_DEPTH_TEST); + if (blend) + f->glEnable(GL_BLEND); + else + f->glDisable(GL_BLEND); + f->glBlendFuncSeparate(blendFunc[0], blendFunc[1], blendFunc[2], blendFunc[3]); + f->glBindBuffer(GL_ARRAY_BUFFER, arrayBuf); + if (vaoHelper->isValid()) + vaoHelper->glBindVertexArray(vao); + for (int i = 0; i < 2; ++i) { + if (va[i].enabled) + f->glEnableVertexAttribArray(i); + else + f->glDisableVertexAttribArray(i); + f->glBindBuffer(GL_ARRAY_BUFFER, va[i].buffer); + f->glVertexAttribPointer(i, va[i].size, va[i].type, va[i].normalized, va[i].stride, va[i].pointer); + } + } + delete vaoHelper; + } + QOpenGLFunctions *f; + QOpenGLVertexArrayObjectHelper *vaoHelper; + bool saved; + GLint program; + GLint texture; + GLint activeTexture; + GLint frontFace; + bool cull; + bool depthTest; + bool blend; + GLint blendFunc[4]; + GLint vao; + GLint arrayBuf; + struct { GLint enabled, type, size, normalized, stride, buffer; GLvoid *pointer; } va[2]; +}; + +void QEglFSCursor::draw(const QRectF &r) +{ + StateSaver stateSaver; + + if (!m_program) { + // one time initialization + initializeOpenGLFunctions(); + + createShaderPrograms(); + + if (!m_cursorAtlas.texture) { + createCursorTexture(&m_cursorAtlas.texture, m_cursorAtlas.image); + + if (m_cursor.shape != Qt::BitmapCursor) + m_cursor.texture = m_cursorAtlas.texture; + } + } + + if (m_cursor.shape == Qt::BitmapCursor && m_cursor.customCursorPending) { + // upload the custom cursor + createCursorTexture(&m_cursor.customCursorTexture, m_cursor.customCursorImage); + m_cursor.texture = m_cursor.customCursorTexture; + m_cursor.customCursorPending = false; + } + + Q_ASSERT(m_cursor.texture); + + m_program->bind(); + + const GLfloat x1 = r.left(); + const GLfloat x2 = r.right(); + const GLfloat y1 = r.top(); + const GLfloat y2 = r.bottom(); + const GLfloat cursorCoordinates[] = { + x1, y2, + x2, y2, + x1, y1, + x2, y1 + }; + + const GLfloat s1 = m_cursor.textureRect.left(); + const GLfloat s2 = m_cursor.textureRect.right(); + const GLfloat t1 = m_cursor.textureRect.top(); + const GLfloat t2 = m_cursor.textureRect.bottom(); + const GLfloat textureCoordinates[] = { + s1, t2, + s2, t2, + s1, t1, + s2, t1 + }; + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_cursor.texture); + + if (stateSaver.vaoHelper->isValid()) + stateSaver.vaoHelper->glBindVertexArray(0); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + + m_program->enableAttributeArray(0); + m_program->enableAttributeArray(1); + m_program->setAttributeArray(0, cursorCoordinates, 2); + m_program->setAttributeArray(1, textureCoordinates, 2); + + m_program->setUniformValue(m_textureEntry, 0); + + glDisable(GL_CULL_FACE); + glFrontFace(GL_CCW); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_DEPTH_TEST); // disable depth testing to make sure cursor is always on top + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + m_program->disableAttributeArray(0); + m_program->disableAttributeArray(1); + m_program->release(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfscursor.h b/src/plugins/platforms/eglfs/qeglfscursor.h new file mode 100644 index 0000000000..be5db41b37 --- /dev/null +++ b/src/plugins/platforms/eglfs/qeglfscursor.h @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** 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 QEGLFSCURSOR_H +#define QEGLFSCURSOR_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qeglfsglobal.h" +#include <qpa/qplatformcursor.h> +#include <qpa/qplatformscreen.h> +#include <QtGui/QOpenGLFunctions> +#include <QtGui/private/qinputdevicemanager_p.h> + +QT_BEGIN_NAMESPACE + +class QOpenGLShaderProgram; +class QEglFSCursor; +class QEglFSScreen; + +class QEglFSCursorDeviceListener : public QObject +{ + Q_OBJECT + +public: + QEglFSCursorDeviceListener(QEglFSCursor *cursor) : m_cursor(cursor) { } + bool hasMouse() const; + +public slots: + void onDeviceListChanged(QInputDeviceManager::DeviceType type); + +private: + QEglFSCursor *m_cursor; +}; + +class Q_EGLFS_EXPORT QEglFSCursor : public QPlatformCursor, protected QOpenGLFunctions +{ + Q_OBJECT +public: + QEglFSCursor(QPlatformScreen *screen); + ~QEglFSCursor(); + +#ifndef QT_NO_CURSOR + void changeCursor(QCursor *cursor, QWindow *widget) Q_DECL_OVERRIDE; +#endif + void pointerEvent(const QMouseEvent &event) Q_DECL_OVERRIDE; + QPoint pos() const Q_DECL_OVERRIDE; + void setPos(const QPoint &pos) Q_DECL_OVERRIDE; + + QRect cursorRect() const; + void paintOnScreen(); + void resetResources(); + + void updateMouseStatus(); + +private: + bool event(QEvent *e) Q_DECL_OVERRIDE; +#ifndef QT_NO_CURSOR + bool setCurrentCursor(QCursor *cursor); +#endif + void draw(const QRectF &rect); + void update(const QRegion ®ion); + void createShaderPrograms(); + void createCursorTexture(uint *texture, const QImage &image); + void initCursorAtlas(); + + // current cursor information + struct Cursor { + Cursor() : texture(0), shape(Qt::BlankCursor), customCursorTexture(0), customCursorPending(false) { } + uint texture; // a texture from 'image' or the atlas + Qt::CursorShape shape; + QRectF textureRect; // normalized rect inside texture + QSize size; // size of the cursor + QPoint hotSpot; + QImage customCursorImage; + QPoint pos; // current cursor position + uint customCursorTexture; + bool customCursorPending; + } m_cursor; + + // cursor atlas information + struct CursorAtlas { + CursorAtlas() : cursorsPerRow(0), texture(0), cursorWidth(0), cursorHeight(0) { } + int cursorsPerRow; + uint texture; + int width, height; // width and height of the atlas + int cursorWidth, cursorHeight; // width and height of cursors inside the atlas + QList<QPoint> hotSpots; + QImage image; // valid until it's uploaded + } m_cursorAtlas; + + bool m_visible; + QEglFSScreen *m_screen; + QOpenGLShaderProgram *m_program; + int m_textureEntry; + QEglFSCursorDeviceListener *m_deviceListener; + bool m_updateRequested; +}; + +QT_END_NAMESPACE + +#endif // QEGLFSCURSOR_H diff --git a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp b/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp index 359b90f205..d27c949c8d 100644 --- a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp +++ b/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp @@ -33,8 +33,8 @@ #include "qeglfsdeviceintegration.h" #include "qeglfsintegration.h" +#include "qeglfscursor.h" #include <QtPlatformSupport/private/qeglconvenience_p.h> -#include <QtPlatformSupport/private/qeglplatformcursor_p.h> #include <QGuiApplication> #include <private/qguiapplication_p.h> #include <QScreen> @@ -99,6 +99,7 @@ QStringList QEGLDeviceIntegrationFactory::keys(const QString &pluginPath) qCDebug(qLcEglDevDebug) << "EGL device integration plugin keys:" << list; return list; #else + Q_UNUSED(pluginPath); return QStringList(); #endif } @@ -117,6 +118,9 @@ QEGLDeviceIntegration *QEGLDeviceIntegrationFactory::create(const QString &key, qCDebug(qLcEglDevDebug) << "Using EGL device integration" << key; else qCWarning(qLcEglDevDebug) << "Failed to load EGL device integration" << key; +#else + Q_UNUSED(key); + Q_UNUSED(pluginPath); #endif return integration; } @@ -282,7 +286,7 @@ bool QEGLDeviceIntegration::hasCapability(QPlatformIntegration::Capability cap) QPlatformCursor *QEGLDeviceIntegration::createCursor(QPlatformScreen *screen) const { - return new QEGLPlatformCursor(screen); + return new QEglFSCursor(screen); } void QEGLDeviceIntegration::waitForVSync(QPlatformSurface *surface) const diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp index 5eb8485dc7..5f2cc9abbc 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp +++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp @@ -39,19 +39,46 @@ #include <QtGui/QOpenGLContext> #include <QtGui/QScreen> #include <QtGui/QOffscreenSurface> -#include <qpa/qplatformcursor.h> +#include <QtGui/QWindow> +#include <QtCore/QLoggingCategory> +#include <qpa/qwindowsysteminterface.h> +#include <qpa/qplatforminputcontextfactory_p.h> #include "qeglfsintegration.h" #include "qeglfswindow.h" #include "qeglfshooks.h" #include "qeglfscontext.h" #include "qeglfsoffscreenwindow.h" +#include "qeglfscursor.h" #include <QtPlatformSupport/private/qeglconvenience_p.h> #include <QtPlatformSupport/private/qeglplatformcontext_p.h> #include <QtPlatformSupport/private/qeglpbuffer_p.h> + +#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> +#include <QtPlatformSupport/private/qgenericunixservices_p.h> +#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> +#include <QtPlatformSupport/private/qfbvthandler_p.h> +#include <QtPlatformSupport/private/qopenglcompositorbackingstore_p.h> + #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> +#include <QtPlatformSupport/private/qevdevtouchmanager_p.h> +#endif + +#if !defined(QT_NO_TSLIB) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) +#include <QtPlatformSupport/private/qtslib_p.h> +#endif + +#include <QtPlatformHeaders/qeglfsfunctions.h> + #include <EGL/egl.h> static void initResources() @@ -64,21 +91,18 @@ static void initResources() QT_BEGIN_NAMESPACE QEglFSIntegration::QEglFSIntegration() + : m_display(EGL_NO_DISPLAY), + m_inputContext(0), + m_fontDb(new QGenericUnixFontDatabase), + m_services(new QGenericUnixServices), + m_kbdMgr(0), + m_disableInputHandlers(false) { - mDisableInputHandlers = qEnvironmentVariableIntValue("QT_QPA_EGLFS_DISABLE_INPUT"); + m_disableInputHandlers = qEnvironmentVariableIntValue("QT_QPA_EGLFS_DISABLE_INPUT"); initResources(); } -bool QEglFSIntegration::hasCapability(QPlatformIntegration::Capability cap) const -{ - // We assume that devices will have more and not less capabilities - if (qt_egl_device_integration()->hasCapability(cap)) - return true; - - return QEGLPlatformIntegration::hasCapability(cap); -} - void QEglFSIntegration::addScreen(QPlatformScreen *screen) { screenAdded(screen); @@ -93,9 +117,19 @@ void QEglFSIntegration::initialize() { qt_egl_device_integration()->platformInit(); - QEGLPlatformIntegration::initialize(); + m_display = eglGetDisplay(nativeDisplay()); + if (m_display == EGL_NO_DISPLAY) + qFatal("Could not open egl display"); + + EGLint major, minor; + if (!eglInitialize(m_display, &major, &minor)) + qFatal("Could not initialize egl display"); - if (!mDisableInputHandlers) + m_inputContext = QPlatformInputContextFactory::create(); + + m_vtHandler.reset(new QFbVtHandler); + + if (!m_disableInputHandlers) createInputHandlers(); if (qt_egl_device_integration()->usesDefaultScreen()) @@ -108,52 +142,283 @@ void QEglFSIntegration::destroy() { foreach (QWindow *w, qGuiApp->topLevelWindows()) w->destroy(); + qt_egl_device_integration()->screenDestroy(); - if (display() != EGL_NO_DISPLAY) - eglTerminate(display()); + + if (m_display != EGL_NO_DISPLAY) + eglTerminate(m_display); + qt_egl_device_integration()->platformDestroy(); } -EGLNativeDisplayType QEglFSIntegration::nativeDisplay() const +QAbstractEventDispatcher *QEglFSIntegration::createEventDispatcher() const { - return qt_egl_device_integration()->platformDisplay(); + return createUnixEventDispatcher(); +} + +QPlatformServices *QEglFSIntegration::services() const +{ + return m_services.data(); } -QEGLPlatformWindow *QEglFSIntegration::createWindow(QWindow *window) const +QPlatformFontDatabase *QEglFSIntegration::fontDatabase() const { - return new QEglFSWindow(window); + return m_fontDb.data(); } -QEGLPlatformContext *QEglFSIntegration::createContext(const QSurfaceFormat &format, - QPlatformOpenGLContext *shareContext, - EGLDisplay display, - QVariant *nativeHandle) const +QPlatformBackingStore *QEglFSIntegration::createPlatformBackingStore(QWindow *window) const { + QOpenGLCompositorBackingStore *bs = new QOpenGLCompositorBackingStore(window); + if (!window->handle()) + window->create(); + static_cast<QEglFSWindow *>(window->handle())->setBackingStore(bs); + return bs; +} + +QPlatformWindow *QEglFSIntegration::createPlatformWindow(QWindow *window) const +{ + QWindowSystemInterface::flushWindowSystemEvents(); + QEglFSWindow *w = new QEglFSWindow(window); + w->create(); + if (window->type() != Qt::ToolTip) + w->requestActivateWindow(); + return w; +} + +QPlatformOpenGLContext *QEglFSIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const +{ + // If there is a "root" window into which raster and QOpenGLWidget content is + // composited, all other contexts must share with its context. + QOpenGLContext *compositingContext = QOpenGLCompositor::instance()->context(); + EGLDisplay dpy = context->screen() ? static_cast<QEglFSScreen *>(context->screen()->handle())->display() : display(); + QPlatformOpenGLContext *share = compositingContext ? compositingContext->handle() : context->shareHandle(); + QVariant nativeHandle = context->nativeHandle(); + QEglFSContext *ctx; - QSurfaceFormat adjustedFormat = qt_egl_device_integration()->surfaceFormatFor(format); - if (!nativeHandle || nativeHandle->isNull()) { - EGLConfig config = QEglFSIntegration::chooseConfig(display, adjustedFormat); - ctx = new QEglFSContext(adjustedFormat, shareContext, display, &config, QVariant()); + QSurfaceFormat adjustedFormat = qt_egl_device_integration()->surfaceFormatFor(context->format()); + if (nativeHandle.isNull()) { + EGLConfig config = QEglFSIntegration::chooseConfig(dpy, adjustedFormat); + ctx = new QEglFSContext(adjustedFormat, share, dpy, &config, QVariant()); } else { - ctx = new QEglFSContext(adjustedFormat, shareContext, display, 0, *nativeHandle); + ctx = new QEglFSContext(adjustedFormat, share, dpy, 0, nativeHandle); } - *nativeHandle = QVariant::fromValue<QEGLNativeContext>(QEGLNativeContext(ctx->eglContext(), display)); + nativeHandle = QVariant::fromValue<QEGLNativeContext>(QEGLNativeContext(ctx->eglContext(), dpy)); + + context->setNativeHandle(nativeHandle); return ctx; } -QPlatformOffscreenSurface *QEglFSIntegration::createOffscreenSurface(EGLDisplay display, - const QSurfaceFormat &format, - QOffscreenSurface *surface) const +QPlatformOffscreenSurface *QEglFSIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const { - QSurfaceFormat fmt = qt_egl_device_integration()->surfaceFormatFor(format); + EGLDisplay dpy = surface->screen() ? static_cast<QEglFSScreen *>(surface->screen()->handle())->display() : display(); + QSurfaceFormat fmt = qt_egl_device_integration()->surfaceFormatFor(surface->requestedFormat()); if (qt_egl_device_integration()->supportsPBuffers()) - return new QEGLPbuffer(display, fmt, surface); + return new QEGLPbuffer(dpy, fmt, surface); else - return new QEglFSOffscreenWindow(display, fmt, surface); - + return new QEglFSOffscreenWindow(dpy, fmt, surface); // Never return null. Multiple QWindows are not supported by this plugin. } +bool QEglFSIntegration::hasCapability(QPlatformIntegration::Capability cap) const +{ + // We assume that devices will have more and not less capabilities + if (qt_egl_device_integration()->hasCapability(cap)) + return true; + + switch (cap) { + case ThreadedPixmaps: return true; + case OpenGL: return true; + case ThreadedOpenGL: return true; + case WindowManagement: return false; + case RasterGLSurface: return true; + default: return QPlatformIntegration::hasCapability(cap); + } +} + +QPlatformNativeInterface *QEglFSIntegration::nativeInterface() const +{ + return const_cast<QEglFSIntegration *>(this); +} + +enum ResourceType { + EglDisplay, + EglWindow, + EglContext, + EglConfig, + NativeDisplay, + XlibDisplay +}; + +static int resourceType(const QByteArray &key) +{ + static const QByteArray names[] = { // match ResourceType + QByteArrayLiteral("egldisplay"), + QByteArrayLiteral("eglwindow"), + QByteArrayLiteral("eglcontext"), + QByteArrayLiteral("eglconfig"), + QByteArrayLiteral("nativedisplay"), + QByteArrayLiteral("display") + }; + const QByteArray *end = names + sizeof(names) / sizeof(names[0]); + const QByteArray *result = std::find(names, end, key); + if (result == end) + result = std::find(names, end, key.toLower()); + return int(result - names); +} + +void *QEglFSIntegration::nativeResourceForIntegration(const QByteArray &resource) +{ + void *result = 0; + + switch (resourceType(resource)) { + case EglDisplay: + result = display(); + break; + case NativeDisplay: + result = reinterpret_cast<void*>(nativeDisplay()); + break; + default: + break; + } + + return result; +} + +void *QEglFSIntegration::nativeResourceForScreen(const QByteArray &resource, QScreen *) +{ + void *result = 0; + + switch (resourceType(resource)) { + case XlibDisplay: + // Play nice when using the x11 hooks: Be compatible with xcb that allows querying + // the X Display pointer, which is nothing but our native display. + result = reinterpret_cast<void*>(nativeDisplay()); + break; + default: + break; + } + + return result; +} + +void *QEglFSIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window) +{ + void *result = 0; + + switch (resourceType(resource)) { + case EglDisplay: + if (window && window->handle()) + result = static_cast<QEglFSScreen *>(window->handle()->screen())->display(); + else + result = display(); + break; + case EglWindow: + if (window && window->handle()) + result = reinterpret_cast<void*>(static_cast<QEglFSWindow *>(window->handle())->eglWindow()); + break; + default: + break; + } + + return result; +} + +void *QEglFSIntegration::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) +{ + void *result = 0; + + switch (resourceType(resource)) { + case EglContext: + if (context->handle()) + result = static_cast<QEglFSContext *>(context->handle())->eglContext(); + break; + case EglConfig: + if (context->handle()) + result = static_cast<QEglFSContext *>(context->handle())->eglConfig(); + break; + case EglDisplay: + if (context->handle()) + result = static_cast<QEglFSContext *>(context->handle())->eglDisplay(); + break; + default: + break; + } + + return result; +} + +static void *eglContextForContext(QOpenGLContext *context) +{ + Q_ASSERT(context); + + QEglFSContext *handle = static_cast<QEglFSContext *>(context->handle()); + if (!handle) + return 0; + + return handle->eglContext(); +} + +QPlatformNativeInterface::NativeResourceForContextFunction QEglFSIntegration::nativeResourceFunctionForContext(const QByteArray &resource) +{ + QByteArray lowerCaseResource = resource.toLower(); + if (lowerCaseResource == "get_egl_context") + return NativeResourceForContextFunction(eglContextForContext); + + return 0; +} + +QFunctionPointer QEglFSIntegration::platformFunction(const QByteArray &function) const +{ +#if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) + if (function == QEglFSFunctions::loadKeymapTypeIdentifier()) + return QFunctionPointer(loadKeymapStatic); +#else + Q_UNUSED(function) +#endif + + return 0; +} + +void QEglFSIntegration::loadKeymapStatic(const QString &filename) +{ +#if !defined(QT_NO_EVDEV) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_NO_SDK)) + QEglFSIntegration *self = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration()); + if (self->m_kbdMgr) + self->m_kbdMgr->loadKeymap(filename); + else + qWarning("QEglFSIntegration: Cannot load keymap, no keyboard handler found"); +#else + Q_UNUSED(filename); +#endif +} + +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); +#ifndef QT_NO_TSLIB + const bool useTslib = qEnvironmentVariableIntValue("QT_QPA_EGLFS_TSLIB"); + if (useTslib) + new QTsLibMouseHandler(QLatin1String("TsLib"), QString() /* spec */); + else +#endif // QT_NO_TSLIB + new QEvdevTouchManager(QLatin1String("EvdevTouch"), QString() /* spec */, this); +#endif +} + +EGLNativeDisplayType QEglFSIntegration::nativeDisplay() const +{ + return qt_egl_device_integration()->platformDisplay(); +} + EGLConfig QEglFSIntegration::chooseConfig(EGLDisplay display, const QSurfaceFormat &format) { class Chooser : public QEglConfigChooser { diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.h b/src/plugins/platforms/eglfs/qeglfsintegration.h index 11b643d540..98c7ee9f78 100644 --- a/src/plugins/platforms/eglfs/qeglfsintegration.h +++ b/src/plugins/platforms/eglfs/qeglfsintegration.h @@ -34,41 +34,72 @@ #ifndef QEGLFSINTEGRATION_H #define QEGLFSINTEGRATION_H -#include <QtPlatformSupport/private/qeglplatformintegration_p.h> +#include <QtCore/QVariant> +#include <qpa/qplatformintegration.h> +#include <qpa/qplatformnativeinterface.h> #include <qpa/qplatformscreen.h> #include <EGL/egl.h> #include "qeglfsglobal.h" QT_BEGIN_NAMESPACE -class Q_EGLFS_EXPORT QEglFSIntegration : public QEGLPlatformIntegration +class QEglFSWindow; +class QEglFSContext; +class QFbVtHandler; +class QEvdevKeyboardManager; + +class Q_EGLFS_EXPORT QEglFSIntegration : public QPlatformIntegration, public QPlatformNativeInterface { public: QEglFSIntegration(); - void addScreen(QPlatformScreen *screen); - void removeScreen(QPlatformScreen *screen); - void initialize() Q_DECL_OVERRIDE; void destroy() Q_DECL_OVERRIDE; + EGLDisplay display() const { return m_display; } + + QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE; + QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE; + QPlatformServices *services() const Q_DECL_OVERRIDE; + QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE { return m_inputContext; } + + QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE; + QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const Q_DECL_OVERRIDE; + QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE; + QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const Q_DECL_OVERRIDE; + bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE; - static EGLConfig chooseConfig(EGLDisplay display, const QSurfaceFormat &format); + QPlatformNativeInterface *nativeInterface() const Q_DECL_OVERRIDE; -protected: - QEGLPlatformWindow *createWindow(QWindow *window) const Q_DECL_OVERRIDE; - QEGLPlatformContext *createContext(const QSurfaceFormat &format, - QPlatformOpenGLContext *shareContext, - EGLDisplay display, - QVariant *nativeHandle) const Q_DECL_OVERRIDE; - QPlatformOffscreenSurface *createOffscreenSurface(EGLDisplay display, - const QSurfaceFormat &format, - QOffscreenSurface *surface) const Q_DECL_OVERRIDE; - EGLNativeDisplayType nativeDisplay() const Q_DECL_OVERRIDE; + // QPlatformNativeInterface + void *nativeResourceForIntegration(const QByteArray &resource) Q_DECL_OVERRIDE; + void *nativeResourceForScreen(const QByteArray &resource, QScreen *screen) Q_DECL_OVERRIDE; + void *nativeResourceForWindow(const QByteArray &resource, QWindow *window) Q_DECL_OVERRIDE; + void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) Q_DECL_OVERRIDE; + NativeResourceForContextFunction nativeResourceFunctionForContext(const QByteArray &resource) Q_DECL_OVERRIDE; + + QFunctionPointer platformFunction(const QByteArray &function) const Q_DECL_OVERRIDE; + + QFbVtHandler *vtHandler() { return m_vtHandler.data(); } + + void addScreen(QPlatformScreen *screen); + void removeScreen(QPlatformScreen *screen); + + static EGLConfig chooseConfig(EGLDisplay display, const QSurfaceFormat &format); private: - bool mDisableInputHandlers; + EGLNativeDisplayType nativeDisplay() const; + void createInputHandlers(); + static void loadKeymapStatic(const QString &filename); + + EGLDisplay m_display; + QPlatformInputContext *m_inputContext; + QScopedPointer<QPlatformFontDatabase> m_fontDb; + QScopedPointer<QPlatformServices> m_services; + QScopedPointer<QFbVtHandler> m_vtHandler; + QEvdevKeyboardManager *m_kbdMgr; + bool m_disableInputHandlers; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/qeglfsscreen.cpp index 1b6e2307f8..22ec424451 100644 --- a/src/plugins/platforms/eglfs/qeglfsscreen.cpp +++ b/src/plugins/platforms/eglfs/qeglfsscreen.cpp @@ -32,7 +32,10 @@ ****************************************************************************/ #include <QtCore/qtextstream.h> -#include <QtGui/qpa/qplatformcursor.h> +#include <QtGui/qwindow.h> +#include <qpa/qwindowsysteminterface.h> +#include <qpa/qplatformcursor.h> +#include <QtPlatformSupport/private/qopenglcompositor_p.h> #include "qeglfsscreen.h" #include "qeglfswindow.h" @@ -41,7 +44,8 @@ QT_BEGIN_NAMESPACE QEglFSScreen::QEglFSScreen(EGLDisplay dpy) - : QEGLPlatformScreen(dpy), + : m_dpy(dpy), + m_pointerWindow(0), m_surface(EGL_NO_SURFACE), m_cursor(0) { @@ -51,6 +55,7 @@ QEglFSScreen::QEglFSScreen(EGLDisplay dpy) QEglFSScreen::~QEglFSScreen() { delete m_cursor; + QOpenGLCompositor::destroy(); } QRect QEglFSScreen::geometry() const @@ -103,4 +108,89 @@ void QEglFSScreen::setPrimarySurface(EGLSurface surface) m_surface = surface; } +void QEglFSScreen::handleCursorMove(const QPoint &pos) +{ + const QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); + const QList<QOpenGLCompositorWindow *> windows = compositor->windows(); + + // Generate enter and leave events like a real windowing system would do. + if (windows.isEmpty()) + return; + + // First window is always fullscreen. + if (windows.count() == 1) { + QWindow *window = windows[0]->sourceWindow(); + if (m_pointerWindow != window) { + m_pointerWindow = window; + QWindowSystemInterface::handleEnterEvent(window, window->mapFromGlobal(pos), pos); + } + return; + } + + QWindow *enter = 0, *leave = 0; + for (int i = windows.count() - 1; i >= 0; --i) { + QWindow *window = windows[i]->sourceWindow(); + const QRect geom = window->geometry(); + if (geom.contains(pos)) { + if (m_pointerWindow != window) { + leave = m_pointerWindow; + m_pointerWindow = window; + enter = window; + } + break; + } + } + + if (enter && leave) + QWindowSystemInterface::handleEnterLeaveEvent(enter, leave, enter->mapFromGlobal(pos), pos); +} + +QPixmap QEglFSScreen::grabWindow(WId wid, int x, int y, int width, int height) const +{ + QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); + const QList<QOpenGLCompositorWindow *> windows = compositor->windows(); + Q_ASSERT(!windows.isEmpty()); + + QImage img; + + if (static_cast<QEglFSWindow *>(windows.first()->sourceWindow()->handle())->isRaster()) { + // Request the compositor to render everything into an FBO and read it back. This + // is of course slow, but it's safe and reliable. It will not include the mouse + // cursor, which is a plus. + img = compositor->grab(); + } else { + // Just a single OpenGL window without compositing. Do not support this case for now. Doing + // glReadPixels is not an option since it would read from the back buffer which may have + // undefined content when calling right after a swapBuffers (unless preserved swap is + // available and enabled, but we have no support for that). + qWarning("grabWindow: Not supported for non-composited OpenGL content. Use QQuickWindow::grabWindow() instead."); + return QPixmap(); + } + + if (!wid) { + const QSize screenSize = geometry().size(); + if (width < 0) + width = screenSize.width() - x; + if (height < 0) + height = screenSize.height() - y; + return QPixmap::fromImage(img).copy(x, y, width, height); + } + + foreach (QOpenGLCompositorWindow *w, windows) { + const QWindow *window = w->sourceWindow(); + if (window->winId() == wid) { + const QRect geom = window->geometry(); + if (width < 0) + width = geom.width() - x; + if (height < 0) + height = geom.height() - y; + QRect rect(geom.topLeft() + QPoint(x, y), QSize(width, height)); + rect &= window->geometry(); + return QPixmap::fromImage(img).copy(rect); + } + } + + return QPixmap(); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.h b/src/plugins/platforms/eglfs/qeglfsscreen.h index 07b6ff63ef..dc291285ad 100644 --- a/src/plugins/platforms/eglfs/qeglfsscreen.h +++ b/src/plugins/platforms/eglfs/qeglfsscreen.h @@ -35,7 +35,6 @@ #define QEGLFSSCREEN_H #include "qeglfsglobal.h" -#include <QtPlatformSupport/private/qeglplatformscreen_p.h> #include <EGL/egl.h> QT_BEGIN_NAMESPACE @@ -43,7 +42,7 @@ QT_BEGIN_NAMESPACE class QEglFSWindow; class QOpenGLContext; -class Q_EGLFS_EXPORT QEglFSScreen : public QEGLPlatformScreen +class Q_EGLFS_EXPORT QEglFSScreen : public QPlatformScreen { public: QEglFSScreen(EGLDisplay display); @@ -62,16 +61,23 @@ public: qreal refreshRate() const Q_DECL_OVERRIDE; + QPixmap grabWindow(WId wid, int x, int y, int width, int height) const Q_DECL_OVERRIDE; + EGLSurface primarySurface() const { return m_surface; } -protected: - void setPrimarySurface(EGLSurface surface); + EGLDisplay display() const { return m_dpy; } + + void handleCursorMove(const QPoint &pos); private: - friend class QEglFSWindow; + void setPrimarySurface(EGLSurface surface); + EGLDisplay m_dpy; + QWindow *m_pointerWindow; EGLSurface m_surface; QPlatformCursor *m_cursor; + + friend class QEglFSWindow; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp index c0d51c94a5..c3b9dd6ef0 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp @@ -37,21 +37,23 @@ #include <private/qguiapplication_p.h> #include <QtGui/private/qopenglcontext_p.h> #include <QtGui/QOpenGLContext> -#include <QtPlatformSupport/private/qeglplatformcursor_p.h> #include <QtPlatformSupport/private/qeglconvenience_p.h> +#include <QtPlatformSupport/private/qopenglcompositorbackingstore_p.h> #include "qeglfswindow.h" +#include "qeglfscursor.h" #include "qeglfshooks.h" -#include <QtDebug> - QT_BEGIN_NAMESPACE QEglFSWindow::QEglFSWindow(QWindow *w) - : QEGLPlatformWindow(w) - , m_surface(0) - , m_window(0) - , m_flags(0) + : QPlatformWindow(w), + m_backingStore(0), + m_raster(false), + m_winId(0), + m_surface(0), + m_window(0), + m_flags(0) { } @@ -60,12 +62,34 @@ QEglFSWindow::~QEglFSWindow() destroy(); } +static WId newWId() +{ + static WId id = 0; + + if (id == std::numeric_limits<WId>::max()) + qWarning("QEGLPlatformWindow: Out of window IDs"); + + return ++id; +} + void QEglFSWindow::create() { if (m_flags.testFlag(Created)) return; - QEGLPlatformWindow::create(); + m_winId = newWId(); + + // Save the original surface type before changing to OpenGLSurface. + m_raster = (window()->surfaceType() == QSurface::RasterSurface); + if (m_raster) // change to OpenGL, but not for RasterGLSurface + window()->setSurfaceType(QSurface::OpenGLSurface); + + if (window()->type() == Qt::Desktop) { + QRect fullscreenRect(QPoint(), screen()->availableGeometry().size()); + QPlatformWindow::setGeometry(fullscreenRect); + QWindowSystemInterface::handleGeometryChange(window(), fullscreenRect); + return; + } m_flags = Created; @@ -120,7 +144,7 @@ void QEglFSWindow::destroy() { QEglFSScreen *screen = this->screen(); if (m_flags.testFlag(HasNativeWindow)) { - QEGLPlatformCursor *cursor = qobject_cast<QEGLPlatformCursor *>(screen->cursor()); + QEglFSCursor *cursor = qobject_cast<QEglFSCursor *>(screen->cursor()); if (cursor) cursor->resetResources(); @@ -265,4 +289,41 @@ QEglFSScreen *QEglFSWindow::screen() const return static_cast<QEglFSScreen *>(QPlatformWindow::screen()); } +bool QEglFSWindow::isRaster() const +{ + return m_raster || window()->surfaceType() == QSurface::RasterGLSurface; +} + +QWindow *QEglFSWindow::sourceWindow() const +{ + return window(); +} + +const QPlatformTextureList *QEglFSWindow::textures() const +{ + if (m_backingStore) + return m_backingStore->textures(); + + return 0; +} + +void QEglFSWindow::endCompositing() +{ + if (m_backingStore) + m_backingStore->notifyComposited(); +} + +WId QEglFSWindow::winId() const +{ + return m_winId; +} + +void QEglFSWindow::setOpacity(qreal) +{ + if (!isRaster()) + qWarning("QEglFSWindow: Cannot set opacity for non-raster windows"); + + // Nothing to do here. The opacity is stored in the QWindow. +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/eglfs/qeglfswindow.h b/src/plugins/platforms/eglfs/qeglfswindow.h index f9d207c153..53b9e18dc1 100644 --- a/src/plugins/platforms/eglfs/qeglfswindow.h +++ b/src/plugins/platforms/eglfs/qeglfswindow.h @@ -37,17 +37,23 @@ #include "qeglfsintegration.h" #include "qeglfsscreen.h" #include "qeglfsglobal.h" -#include <QtPlatformSupport/private/qeglplatformwindow_p.h> + +#include <qpa/qplatformwindow.h> +#include <QtPlatformSupport/private/qopenglcompositor_p.h> +#include <EGL/egl.h> QT_BEGIN_NAMESPACE -class Q_EGLFS_EXPORT QEglFSWindow : public QEGLPlatformWindow +class QOpenGLCompositorBackingStore; +class QPlatformTextureList; + +class Q_EGLFS_EXPORT QEglFSWindow : public QPlatformWindow, public QOpenGLCompositorWindow { public: QEglFSWindow(QWindow *w); ~QEglFSWindow(); - void create() Q_DECL_OVERRIDE; + void create(); void destroy(); void setGeometry(const QRect &) Q_DECL_OVERRIDE; @@ -58,13 +64,15 @@ public: void lower() Q_DECL_OVERRIDE; void propagateSizeHints() Q_DECL_OVERRIDE { } - void setOpacity(qreal) Q_DECL_OVERRIDE { } void setMask(const QRegion &) Q_DECL_OVERRIDE { } bool setKeyboardGrabEnabled(bool) Q_DECL_OVERRIDE { return false; } bool setMouseGrabEnabled(bool) Q_DECL_OVERRIDE { return false; } + void setOpacity(qreal) Q_DECL_OVERRIDE; + WId winId() const Q_DECL_OVERRIDE; QSurfaceFormat format() const Q_DECL_OVERRIDE; - EGLNativeWindowType eglWindow() const Q_DECL_OVERRIDE; + + EGLNativeWindowType eglWindow() const; EGLSurface surface() const; QEglFSScreen *screen() const; @@ -73,11 +81,22 @@ public: virtual void invalidateSurface() Q_DECL_OVERRIDE; virtual void resetSurface(); -protected: + QOpenGLCompositorBackingStore *backingStore() { return m_backingStore; } + void setBackingStore(QOpenGLCompositorBackingStore *backingStore) { m_backingStore = backingStore; } + bool isRaster() const; + + QWindow *sourceWindow() const Q_DECL_OVERRIDE; + const QPlatformTextureList *textures() const Q_DECL_OVERRIDE; + void endCompositing() Q_DECL_OVERRIDE; + +private: + QOpenGLCompositorBackingStore *m_backingStore; + bool m_raster; + WId m_winId; + EGLSurface m_surface; EGLNativeWindowType m_window; -private: EGLConfig m_config; QSurfaceFormat m_format; diff --git a/src/plugins/platforms/haiku/qhaikuclipboard.cpp b/src/plugins/platforms/haiku/qhaikuclipboard.cpp index f3aa9dc36e..a2d7e96d71 100644 --- a/src/plugins/platforms/haiku/qhaikuclipboard.cpp +++ b/src/plugins/platforms/haiku/qhaikuclipboard.cpp @@ -41,6 +41,8 @@ #include <Clipboard.h> QHaikuClipboard::QHaikuClipboard() + : m_systemMimeData(Q_NULLPTR) + , m_userMimeData(Q_NULLPTR) { if (be_clipboard) be_clipboard->StartWatching(BMessenger(this)); @@ -50,17 +52,26 @@ QHaikuClipboard::~QHaikuClipboard() { if (be_clipboard) be_clipboard->StopWatching(BMessenger(this)); + + delete m_userMimeData; + delete m_systemMimeData; } QMimeData *QHaikuClipboard::mimeData(QClipboard::Mode mode) { - QMimeData *mimeData = new QMimeData(); - if (mode != QClipboard::Clipboard) - return mimeData; + return 0; + + if (m_userMimeData) + return m_userMimeData; if (!be_clipboard->Lock()) - return mimeData; + return 0; + + if (!m_systemMimeData) + m_systemMimeData = new QMimeData(); + else + m_systemMimeData->clear(); const BMessage *clipboard = be_clipboard->Data(); if (clipboard) { @@ -76,11 +87,11 @@ QMimeData *QHaikuClipboard::mimeData(QClipboard::Mode mode) if (dataLen && (status == B_OK)) { const QString format = QString::fromLatin1(name); if (format == QStringLiteral("text/plain")) { - mimeData->setText(QString::fromLocal8Bit(reinterpret_cast<const char*>(data), dataLen)); + m_systemMimeData->setText(QString::fromLocal8Bit(reinterpret_cast<const char*>(data), dataLen)); } else if (format == QStringLiteral("text/html")) { - mimeData->setHtml(QString::fromLocal8Bit(reinterpret_cast<const char*>(data), dataLen)); + m_systemMimeData->setHtml(QString::fromLocal8Bit(reinterpret_cast<const char*>(data), dataLen)); } else { - mimeData->setData(format, QByteArray(reinterpret_cast<const char*>(data), dataLen)); + m_systemMimeData->setData(format, QByteArray(reinterpret_cast<const char*>(data), dataLen)); } } } @@ -88,7 +99,7 @@ QMimeData *QHaikuClipboard::mimeData(QClipboard::Mode mode) be_clipboard->Unlock(); - return mimeData; + return m_systemMimeData; } void QHaikuClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode) @@ -96,6 +107,14 @@ void QHaikuClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode) if (mode != QClipboard::Clipboard) return; + if (mimeData) { + if (m_systemMimeData == mimeData) + return; + + if (m_userMimeData == mimeData) + return; + } + if (!be_clipboard->Lock()) return; @@ -115,6 +134,10 @@ void QHaikuClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode) qWarning("Unable to store mime data on clipboard"); be_clipboard->Unlock(); + + m_userMimeData = mimeData; + + emitChanged(QClipboard::Clipboard); } bool QHaikuClipboard::supportsMode(QClipboard::Mode mode) const @@ -131,8 +154,12 @@ bool QHaikuClipboard::ownsMode(QClipboard::Mode mode) const void QHaikuClipboard::MessageReceived(BMessage* message) { - if (message->what == B_CLIPBOARD_CHANGED) + if (message->what == B_CLIPBOARD_CHANGED) { + delete m_userMimeData; + m_userMimeData = Q_NULLPTR; + emitChanged(QClipboard::Clipboard); + } BHandler::MessageReceived(message); } diff --git a/src/plugins/platforms/haiku/qhaikuclipboard.h b/src/plugins/platforms/haiku/qhaikuclipboard.h index 0dc2bfdd3b..3c1f92c615 100644 --- a/src/plugins/platforms/haiku/qhaikuclipboard.h +++ b/src/plugins/platforms/haiku/qhaikuclipboard.h @@ -55,6 +55,10 @@ public: // override from BHandler to catch change notifications from Haiku clipboard void MessageReceived(BMessage* message) Q_DECL_OVERRIDE; + +private: + QMimeData *m_systemMimeData; + QMimeData *m_userMimeData; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/haiku/qhaikuwindow.cpp b/src/plugins/platforms/haiku/qhaikuwindow.cpp index 5768e1cb40..9622d12111 100644 --- a/src/plugins/platforms/haiku/qhaikuwindow.cpp +++ b/src/plugins/platforms/haiku/qhaikuwindow.cpp @@ -130,6 +130,7 @@ QHaikuWindow::QHaikuWindow(QWindow *window) if (!m_window) qFatal("QHaikuWindow: failed to create window"); + setGeometry(rect); setWindowFlags(window->flags()); } @@ -164,13 +165,13 @@ void QHaikuWindow::setVisible(bool visible) { if (visible) { m_window->Show(); + + window()->requestActivate(); + + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), window()->geometry().size())); } else { m_window->Hide(); } - - window()->requestActivate(); - - QWindowSystemInterface::handleExposeEvent(window(), window()->geometry()); } bool QHaikuWindow::isExposed() const @@ -306,10 +307,8 @@ void QHaikuWindow::haikuWindowMoved(const QPoint &pos) const QRect newGeometry(pos, geometry().size()); QPlatformWindow::setGeometry(newGeometry); - QWindowSystemInterface::setSynchronousWindowsSystemEvents(true); QWindowSystemInterface::handleGeometryChange(window(), newGeometry); - QWindowSystemInterface::handleExposeEvent(window(), newGeometry); - QWindowSystemInterface::setSynchronousWindowsSystemEvents(false); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), newGeometry.size())); } void QHaikuWindow::haikuWindowResized(const QSize &size, bool zoomInProgress) @@ -317,10 +316,8 @@ void QHaikuWindow::haikuWindowResized(const QSize &size, bool zoomInProgress) const QRect newGeometry(geometry().topLeft(), size); QPlatformWindow::setGeometry(newGeometry); - QWindowSystemInterface::setSynchronousWindowsSystemEvents(true); QWindowSystemInterface::handleGeometryChange(window(), newGeometry); - QWindowSystemInterface::handleExposeEvent(window(), newGeometry); - QWindowSystemInterface::setSynchronousWindowsSystemEvents(false); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), newGeometry.size())); if ((m_windowState == Qt::WindowMaximized) && !zoomInProgress) { // the user has resized the window while maximized -> reset maximized flag diff --git a/src/plugins/platforms/ios/qiosapplicationstate.mm b/src/plugins/platforms/ios/qiosapplicationstate.mm index 92799f80c1..7a37e213bd 100644 --- a/src/plugins/platforms/ios/qiosapplicationstate.mm +++ b/src/plugins/platforms/ios/qiosapplicationstate.mm @@ -43,7 +43,7 @@ @implementation QIOSApplicationStateListener -- (id) init +- (id)init { self = [super init]; if (self) { @@ -75,7 +75,7 @@ return self; } -- (void) dealloc +- (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self @@ -92,12 +92,12 @@ [super dealloc]; } -- (void) applicationDidBecomeActive +- (void)applicationDidBecomeActive { [self handleApplicationStateChanged:UIApplicationStateActive]; } -- (void) applicationWillResignActive +- (void)applicationWillResignActive { // Note that UIApplication is still UIApplicationStateActive at this // point, but since there is no separate notification for the inactive @@ -105,12 +105,12 @@ [self handleApplicationStateChanged:UIApplicationStateInactive]; } -- (void) applicationDidEnterBackground +- (void)applicationDidEnterBackground { [self handleApplicationStateChanged:UIApplicationStateBackground]; } -- (void) handleApplicationStateChanged:(UIApplicationState) uiApplicationState +- (void)handleApplicationStateChanged:(UIApplicationState)uiApplicationState { // We may receive application state changes after QCoreApplication has // gone down, as the block we schedule on the main queue keeps the diff --git a/src/plugins/platforms/ios/qiosclipboard.mm b/src/plugins/platforms/ios/qiosclipboard.mm index 192ee67689..e0c6ec5d72 100644 --- a/src/plugins/platforms/ios/qiosclipboard.mm +++ b/src/plugins/platforms/ios/qiosclipboard.mm @@ -62,7 +62,7 @@ @implementation QUIClipboard --(id)initWithQIOSClipboard:(QIOSClipboard *)qiosClipboard +- (id)initWithQIOSClipboard:(QIOSClipboard *)qiosClipboard { self = [super init]; if (self) { @@ -87,7 +87,7 @@ return self; } --(void)dealloc +- (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm index fc12e83a81..bd4b8778ed 100644 --- a/src/plugins/platforms/ios/qioseventdispatcher.mm +++ b/src/plugins/platforms/ios/qioseventdispatcher.mm @@ -198,7 +198,7 @@ namespace bool debugStackUsage = false; } -extern "C" int __attribute__((weak)) main(int argc, char *argv[]) +extern "C" int qt_main_wrapper(int argc, char *argv[]) { @autoreleasepool { size_t defaultStackSize = 512 * kBytesPerKiloByte; // Same as secondary threads @@ -233,18 +233,7 @@ enum SetJumpResult kJumpedFromUserMainTrampoline, }; -// We define qtmn so that user_main_trampoline() will not cause -// missing symbols in the case of hybrid applications that don't -// use our main wrapper. Since the symbol is weak, it will not -// get used or cause a clash in the normal Qt application usecase, -// where we rename main to qtmn before linking. -extern "C" int __attribute__((weak)) qtmn(int argc, char *argv[]) -{ - Q_UNUSED(argc); - Q_UNUSED(argv); - - Q_UNREACHABLE(); -} +extern "C" int main(int argc, char *argv[]); static void __attribute__((noinline, noreturn)) user_main_trampoline() { @@ -263,7 +252,7 @@ static void __attribute__((noinline, noreturn)) user_main_trampoline() qFatal("Could not convert argv[%d] to C string", i); } - int exitCode = qtmn(argc, argv); + int exitCode = main(argc, argv); delete[] argv; qEventDispatcherDebug() << "Returned from main with exit code " << exitCode; @@ -293,7 +282,7 @@ static bool rootLevelRunLoopIntegration() @implementation QIOSApplicationStateTracker -+ (void) load ++ (void)load { [[NSNotificationCenter defaultCenter] addObserver:self @@ -323,7 +312,7 @@ static bool rootLevelRunLoopIntegration() # error "Unknown processor family" #endif -+ (void) applicationDidFinishLaunching ++ (void)applicationDidFinishLaunching { if (!isQtApplication()) return; @@ -377,7 +366,7 @@ static bool rootLevelRunLoopIntegration() // four bits of the exit code (exit(3) will only pass on the lower 8 bits). static const char kApplicationWillTerminateExitCode = SIGTERM | 0x80; -+ (void) applicationWillTerminate ++ (void)applicationWillTerminate { if (!isQtApplication()) return; diff --git a/src/plugins/platforms/ios/qiosglobal.h b/src/plugins/platforms/ios/qiosglobal.h index 86b784618f..544f9e0a42 100644 --- a/src/plugins/platforms/ios/qiosglobal.h +++ b/src/plugins/platforms/ios/qiosglobal.h @@ -68,7 +68,7 @@ int infoPlistValue(NSString* key, int defaultValue); QT_END_NAMESPACE @interface UIResponder (QtFirstResponder) -+(id)currentFirstResponder; ++ (id)currentFirstResponder; @end class FirstResponderCandidate : public QScopedValueRollback<UIResponder *> diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm index ef24abbfd9..f5b971391d 100644 --- a/src/plugins/platforms/ios/qiosglobal.mm +++ b/src/plugins/platforms/ios/qiosglobal.mm @@ -133,7 +133,7 @@ int infoPlistValue(NSString* key, int defaultValue) @end @implementation QtFirstResponderEvent -- (void) dealloc +- (void)dealloc { self.firstResponder = 0; [super dealloc]; @@ -158,7 +158,7 @@ int infoPlistValue(NSString* key, int defaultValue) @implementation UIResponder (QtFirstResponder) -+(id)currentFirstResponder ++ (id)currentFirstResponder { QtFirstResponderEvent *event = [[[QtFirstResponderEvent alloc] init] autorelease]; [[UIApplication sharedApplication] sendAction:@selector(qt_findFirstResponder:event:) to:nil from:nil forEvent:event]; diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index 090df66e0d..d03c589b2a 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -579,7 +579,7 @@ void QIOSInputContext::focusWindowChanged(QWindow *focusWindow) void QIOSInputContext::update(Qt::InputMethodQueries updatedProperties) { // Mask for properties that we are interested in and see if any of them changed - updatedProperties &= (Qt::ImEnabled | Qt::ImHints | Qt::ImQueryInput | Qt::ImPlatformData); + updatedProperties &= (Qt::ImEnabled | Qt::ImHints | Qt::ImQueryInput | Qt::ImEnterKeyType | Qt::ImPlatformData); qImDebug() << "fw =" << qApp->focusWindow() << "fo =" << qApp->focusObject(); diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm index 8395db81ff..eaff0daf19 100644 --- a/src/plugins/platforms/ios/qiosintegration.mm +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -219,6 +219,10 @@ QPlatformServices *QIOSIntegration::services() const QVariant QIOSIntegration::styleHint(StyleHint hint) const { switch (hint) { + case PasswordMaskDelay: + // this number is based on timing the native delay + // since there is no API to get it + return 2000; case ShowIsMaximized: return true; case SetFocusOnTouchRelease: diff --git a/src/plugins/platforms/ios/qiosmenu.mm b/src/plugins/platforms/ios/qiosmenu.mm index 08fc8a5e9c..045d39e328 100644 --- a/src/plugins/platforms/ios/qiosmenu.mm +++ b/src/plugins/platforms/ios/qiosmenu.mm @@ -165,7 +165,7 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_"; [self reloadAllComponents]; } --(void)listenForKeyboardWillHideNotification:(BOOL)listen +- (void)listenForKeyboardWillHideNotification:(BOOL)listen { if (listen) { [[NSNotificationCenter defaultCenter] @@ -179,7 +179,7 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_"; } } --(void)dealloc +- (void)dealloc { [self listenForKeyboardWillHideNotification:NO]; self.toolbar = 0; diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm index 324133074b..3e16efcd22 100644 --- a/src/plugins/platforms/ios/qiosscreen.mm +++ b/src/plugins/platforms/ios/qiosscreen.mm @@ -104,12 +104,12 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen) @public QIOSScreen *m_screen; } -- (id) initWithQIOSScreen:(QIOSScreen *)screen; +- (id)initWithQIOSScreen:(QIOSScreen *)screen; @end @implementation QIOSOrientationListener -- (id) initWithQIOSScreen:(QIOSScreen *)screen +- (id)initWithQIOSScreen:(QIOSScreen *)screen { self = [super init]; if (self) { @@ -123,7 +123,7 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen) return self; } -- (void) dealloc +- (void)dealloc { [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications]; [[NSNotificationCenter defaultCenter] @@ -132,7 +132,7 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen) [super dealloc]; } -- (void) orientationChanged:(NSNotification *)notification +- (void)orientationChanged:(NSNotification *)notification { Q_UNUSED(notification); m_screen->updateProperties(); diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index be9c3b9e27..e4917593db 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -92,12 +92,12 @@ return [QUITextPosition positionWithIndex:(self.range.location + self.range.length)]; } -- (NSRange) range +- (NSRange)range { return _range; } --(BOOL)isEmpty +- (BOOL)isEmpty { return (self.range.length == 0); } @@ -111,7 +111,7 @@ @implementation WrapperView --(id)initWithView:(UIView *)view +- (id)initWithView:(UIView *)view { if (self = [self init]) { [self addSubview:view]; @@ -143,7 +143,7 @@ // retained, we ensure that all messages sent to the view during // its lifetime in a window hierarcy will be able to traverse the // responder chain. --(void)willMoveToWindow:(UIWindow *)window +- (void)willMoveToWindow:(UIWindow *)window { if (window) [[self nextResponder] retain]; @@ -170,9 +170,31 @@ QVariantMap platformData = m_configuredImeState->value(Qt::ImPlatformData).toMap(); Qt::InputMethodHints hints = Qt::InputMethodHints(m_configuredImeState->value(Qt::ImHints).toUInt()); - self.returnKeyType = platformData.value(kImePlatformDataReturnKeyType).isValid() ? - UIReturnKeyType(platformData.value(kImePlatformDataReturnKeyType).toInt()) : - (hints & Qt::ImhMultiLine) ? UIReturnKeyDefault : UIReturnKeyDone; + Qt::EnterKeyType enterKeyType = Qt::EnterKeyType(m_configuredImeState->value(Qt::ImEnterKeyType).toUInt()); + + switch (enterKeyType) { + case Qt::EnterKeyReturn: + self.returnKeyType = UIReturnKeyDefault; + break; + case Qt::EnterKeyDone: + self.returnKeyType = UIReturnKeyDone; + break; + case Qt::EnterKeyGo: + self.returnKeyType = UIReturnKeyGo; + break; + case Qt::EnterKeySend: + self.returnKeyType = UIReturnKeySend; + break; + case Qt::EnterKeySearch: + self.returnKeyType = UIReturnKeySearch; + break; + case Qt::EnterKeyNext: + self.returnKeyType = UIReturnKeyNext; + break; + default: + self.returnKeyType = (hints & Qt::ImhMultiLine) ? UIReturnKeyDefault : UIReturnKeyDone; + break; + } self.secureTextEntry = BOOL(hints & Qt::ImhHiddenText); self.autocorrectionType = (hints & Qt::ImhNoPredictiveText) ? @@ -235,7 +257,7 @@ } // Based on what we set up in initWithInputContext above - updatedProperties &= (Qt::ImHints | Qt::ImPlatformData); + updatedProperties &= (Qt::ImHints | Qt::ImEnterKeyType | Qt::ImPlatformData); if (!updatedProperties) return NO; @@ -403,17 +425,17 @@ return m_inputContext->imeState().currentState.value(query); } --(id<UITextInputTokenizer>)tokenizer +- (id<UITextInputTokenizer>)tokenizer { return [[[UITextInputStringTokenizer alloc] initWithTextInput:id<UITextInput>(self)] autorelease]; } --(UITextPosition *)beginningOfDocument +- (UITextPosition *)beginningOfDocument { return [QUITextPosition positionWithIndex:0]; } --(UITextPosition *)endOfDocument +- (UITextPosition *)endOfDocument { int endPosition = [self currentImeState:Qt::ImSurroundingText].toString().length(); return [QUITextPosition positionWithIndex:endPosition]; @@ -679,7 +701,7 @@ return [NSDictionary dictionaryWithObject:uifont forKey:UITextInputTextFontKey]; } --(NSDictionary *)markedTextStyle +- (NSDictionary *)markedTextStyle { return [NSDictionary dictionary]; } @@ -698,7 +720,8 @@ if ([text isEqualToString:@"\n"]) { [self sendKeyPressRelease:Qt::Key_Return modifiers:Qt::NoModifier]; - if (self.returnKeyType == UIReturnKeyDone) + if (self.returnKeyType == UIReturnKeyDone || self.returnKeyType == UIReturnKeyGo + || self.returnKeyType == UIReturnKeySend || self.returnKeyType == UIReturnKeySearch) [self resignFirstResponder]; return; diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm index a7068b9246..be89521c04 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.mm +++ b/src/plugins/platforms/ios/qiosviewcontroller.mm @@ -289,13 +289,13 @@ // ------------------------------------------------------------------------- --(BOOL)shouldAutorotate +- (BOOL)shouldAutorotate { return m_screen && m_screen->uiScreen() == [UIScreen mainScreen] && !self.lockedOrientation; } #if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_6_0) --(NSUInteger)supportedInterfaceOrientations +- (NSUInteger)supportedInterfaceOrientations { // As documented by Apple in the iOS 6.0 release notes, setStatusBarOrientation:animated: // only works if the supportedInterfaceOrientations of the view controller is 0, making @@ -308,7 +308,7 @@ #endif #if QT_IOS_DEPLOYMENT_TARGET_BELOW(__IPHONE_6_0) --(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { Q_UNUSED(interfaceOrientation); return [self shouldAutorotate]; diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.h b/src/plugins/platforms/ios/quiaccessibilityelement.h index a690e12c7d..c76e3a6a1e 100644 --- a/src/plugins/platforms/ios/quiaccessibilityelement.h +++ b/src/plugins/platforms/ios/quiaccessibilityelement.h @@ -42,8 +42,8 @@ @property (readonly) QAccessible::Id axid; -- (id) initWithId: (QAccessible::Id) anId withAccessibilityContainer: (id) view; -+ (QMacAccessibilityElement *) elementWithId: (QAccessible::Id) anId withAccessibilityContainer: (id) view; +- (id)initWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view; ++ (QMacAccessibilityElement *)elementWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view; @end diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.mm b/src/plugins/platforms/ios/quiaccessibilityelement.mm index 2cecfc1126..3bac1ca88d 100644 --- a/src/plugins/platforms/ios/quiaccessibilityelement.mm +++ b/src/plugins/platforms/ios/quiaccessibilityelement.mm @@ -37,7 +37,7 @@ @implementation QMacAccessibilityElement -- (id) initWithId: (QAccessible::Id) anId withAccessibilityContainer: (id) view +- (id)initWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view { Q_ASSERT((int)anId < 0); self = [super initWithAccessibilityContainer: view]; @@ -47,7 +47,7 @@ return self; } -+ (id) elementWithId: (QAccessible::Id) anId withAccessibilityContainer: (id) view ++ (id)elementWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view { Q_ASSERT(anId); if (!anId) @@ -64,17 +64,17 @@ return element; } -- (void) invalidate +- (void)invalidate { [self release]; } -- (BOOL) isAccessibilityElement +- (BOOL)isAccessibilityElement { return YES; } -- (NSString*) accessibilityLabel +- (NSString*)accessibilityLabel { QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); if (!iface) { @@ -85,7 +85,7 @@ return iface->text(QAccessible::Name).toNSString(); } -- (NSString*) accessibilityHint +- (NSString*)accessibilityHint { QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); if (!iface) { @@ -95,7 +95,7 @@ return iface->text(QAccessible::Description).toNSString(); } -- (NSString*) accessibilityValue +- (NSString*)accessibilityValue { QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); if (!iface) { @@ -119,7 +119,7 @@ return [super accessibilityHint]; } -- (CGRect) accessibilityFrame +- (CGRect)accessibilityFrame { QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); if (!iface) { @@ -131,7 +131,7 @@ return CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()); } -- (UIAccessibilityTraits) accessibilityTraits +- (UIAccessibilityTraits)accessibilityTraits { UIAccessibilityTraits traits = UIAccessibilityTraitNone; @@ -156,7 +156,7 @@ return traits; } -- (BOOL) accessibilityActivate +- (BOOL)accessibilityActivate { QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); if (QAccessibleActionInterface *action = iface->actionInterface()) { @@ -171,21 +171,21 @@ return NO; // fall back to sending mouse clicks } -- (void) accessibilityIncrement +- (void)accessibilityIncrement { QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); if (QAccessibleActionInterface *action = iface->actionInterface()) action->doAction(QAccessibleActionInterface::increaseAction()); } -- (void) accessibilityDecrement +- (void)accessibilityDecrement { QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); if (QAccessibleActionInterface *action = iface->actionInterface()) action->doAction(QAccessibleActionInterface::decreaseAction()); } -- (BOOL) accessibilityScroll : (UIAccessibilityScrollDirection) direction +- (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction { QAccessibleInterface *iface = QAccessible::accessibleInterface(self.axid); QAccessibleActionInterface *action = iface->actionInterface(); diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm index 87dc3b9dcb..c6ef843b9f 100644 --- a/src/plugins/platforms/ios/quiview.mm +++ b/src/plugins/platforms/ios/quiview.mm @@ -50,7 +50,7 @@ return [CAEAGLLayer class]; } --(id)initWithQIOSWindow:(QIOSWindow *)window +- (id)initWithQIOSWindow:(QIOSWindow *)window { if (self = [self initWithFrame:toCGRect(window->geometry())]) m_qioswindow = window; @@ -316,7 +316,7 @@ } } -- (void) sendTouchEventWithTimestamp:(ulong)timeStamp +- (void)sendTouchEventWithTimestamp:(ulong)timeStamp { // Send touch event synchronously QIOSIntegration *iosIntegration = QIOSIntegration::instance(); 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/mirclient/mirclient.json b/src/plugins/platforms/mirclient/mirclient.json new file mode 100644 index 0000000000..c31558a2f1 --- /dev/null +++ b/src/plugins/platforms/mirclient/mirclient.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "mirclient" ] +} diff --git a/src/plugins/platforms/mirclient/mirclient.pro b/src/plugins/platforms/mirclient/mirclient.pro new file mode 100644 index 0000000000..033ce579b9 --- /dev/null +++ b/src/plugins/platforms/mirclient/mirclient.pro @@ -0,0 +1,47 @@ +TARGET = mirclient +TEMPLATE = lib + +PLUGIN_TYPE = platforms +PLUGIN_CLASS_NAME = MirServerIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - +load(qt_plugin) + +QT += core-private gui-private platformsupport-private dbus + +CONFIG += qpa/genericunixfontdatabase + +DEFINES += MESA_EGL_NO_X11_HEADERS +# CONFIG += c++11 # only enables C++0x +QMAKE_CXXFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden -std=c++11 -Werror -Wall +QMAKE_LFLAGS += -std=c++11 -Wl,-no-undefined + +CONFIG += link_pkgconfig +PKGCONFIG += egl mirclient ubuntu-platform-api + +SOURCES = \ + qmirclientbackingstore.cpp \ + qmirclientclipboard.cpp \ + qmirclientglcontext.cpp \ + qmirclientinput.cpp \ + qmirclientintegration.cpp \ + qmirclientnativeinterface.cpp \ + qmirclientplatformservices.cpp \ + qmirclientplugin.cpp \ + qmirclientscreen.cpp \ + qmirclienttheme.cpp \ + qmirclientwindow.cpp + +HEADERS = \ + qmirclientbackingstore.h \ + qmirclientclipboard.h \ + qmirclientglcontext.h \ + qmirclientinput.h \ + qmirclientintegration.h \ + qmirclientlogging.h \ + qmirclientnativeinterface.h \ + qmirclientorientationchangeevent_p.h \ + qmirclientplatformservices.h \ + qmirclientplugin.h \ + qmirclientscreen.h \ + qmirclienttheme.h \ + qmirclientwindow.h diff --git a/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp b/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp new file mode 100644 index 0000000000..daa0b229ec --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qmirclientbackingstore.h" +#include "qmirclientlogging.h" +#include <QtGui/QOpenGLContext> +#include <QtGui/QOpenGLTexture> +#include <QtGui/QMatrix4x4> +#include <QtGui/private/qopengltextureblitter_p.h> +#include <QtGui/qopenglfunctions.h> + +QMirClientBackingStore::QMirClientBackingStore(QWindow* window) + : QPlatformBackingStore(window) + , mContext(new QOpenGLContext) + , mTexture(new QOpenGLTexture(QOpenGLTexture::Target2D)) + , mBlitter(new QOpenGLTextureBlitter) +{ + mContext->setFormat(window->requestedFormat()); + mContext->setScreen(window->screen()); + mContext->create(); + + window->setSurfaceType(QSurface::OpenGLSurface); +} + +QMirClientBackingStore::~QMirClientBackingStore() +{ +} + +void QMirClientBackingStore::flush(QWindow* window, const QRegion& region, const QPoint& offset) +{ + Q_UNUSED(region); + Q_UNUSED(offset); + mContext->makeCurrent(window); + glViewport(0, 0, window->width(), window->height()); + + updateTexture(); + + if (!mBlitter->isCreated()) + mBlitter->create(); + + mBlitter->bind(); + mBlitter->setSwizzleRB(true); + mBlitter->blit(mTexture->textureId(), QMatrix4x4(), QOpenGLTextureBlitter::OriginTopLeft); + mBlitter->release(); + + mContext->swapBuffers(window); +} + +void QMirClientBackingStore::updateTexture() +{ + if (mDirty.isNull()) + return; + + if (!mTexture->isCreated()) { + mTexture->setMinificationFilter(QOpenGLTexture::Nearest); + mTexture->setMagnificationFilter(QOpenGLTexture::Nearest); + mTexture->setWrapMode(QOpenGLTexture::ClampToEdge); + mTexture->setData(mImage, QOpenGLTexture::DontGenerateMipMaps); + mTexture->create(); + } + mTexture->bind(); + + QRegion fixed; + QRect imageRect = mImage.rect(); + + Q_FOREACH (const QRect &rect, mDirty.rects()) { + // intersect with image rect to be sure + QRect r = imageRect & rect; + + // if the rect is wide enough it is 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 is 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, + mImage.constScanLine(rect.y())); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, + mImage.copy(rect).constBits()); + } + } + /* End of code taken from QEGLPlatformBackingStore */ + + mDirty = QRegion(); +} + + +void QMirClientBackingStore::beginPaint(const QRegion& region) +{ + mDirty |= region; +} + +void QMirClientBackingStore::resize(const QSize& size, const QRegion& /*staticContents*/) +{ + mImage = QImage(size, QImage::Format_RGB32); + + if (mTexture->isCreated()) + mTexture->destroy(); +} + +QPaintDevice* QMirClientBackingStore::paintDevice() +{ + return &mImage; +} diff --git a/src/plugins/platforms/mirclient/qmirclientbackingstore.h b/src/plugins/platforms/mirclient/qmirclientbackingstore.h new file mode 100644 index 0000000000..22b8bf9bc5 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientbackingstore.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMIRCLIENTBACKINGSTORE_H +#define QMIRCLIENTBACKINGSTORE_H + +#include <qpa/qplatformbackingstore.h> + +class QOpenGLContext; +class QOpenGLTexture; +class QOpenGLTextureBlitter; + +class QMirClientBackingStore : public QPlatformBackingStore +{ +public: + QMirClientBackingStore(QWindow* window); + virtual ~QMirClientBackingStore(); + + // QPlatformBackingStore methods. + void beginPaint(const QRegion&) override; + void flush(QWindow* window, const QRegion& region, const QPoint& offset) override; + void resize(const QSize& size, const QRegion& staticContents) override; + QPaintDevice* paintDevice() override; + +protected: + void updateTexture(); + +private: + QScopedPointer<QOpenGLContext> mContext; + QScopedPointer<QOpenGLTexture> mTexture; + QScopedPointer<QOpenGLTextureBlitter> mBlitter; + QImage mImage; + QRegion mDirty; +}; + +#endif // QMIRCLIENTBACKINGSTORE_H diff --git a/src/plugins/platforms/mirclient/qmirclientclipboard.cpp b/src/plugins/platforms/mirclient/qmirclientclipboard.cpp new file mode 100644 index 0000000000..aa2ddf2103 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientclipboard.cpp @@ -0,0 +1,305 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qmirclientclipboard.h" + +#include <QtCore/QMimeData> +#include <QtCore/QStringList> +#include <QDBusInterface> +#include <QDBusPendingCallWatcher> +#include <QDBusPendingReply> + +// FIXME(loicm) The clipboard data format is not defined by Ubuntu Platform API +// which makes it impossible to have non-Qt applications communicate with Qt +// applications through the clipboard API. The solution would be to have +// Ubuntu Platform define the data format or propose an API that supports +// embedding different mime types in the clipboard. + +// Data format: +// number of mime types (sizeof(int)) +// data layout ((4 * sizeof(int)) * number of mime types) +// mime type string offset (sizeof(int)) +// mime type string size (sizeof(int)) +// data offset (sizeof(int)) +// data size (sizeof(int)) +// data (n bytes) + +namespace { + +const int maxFormatsCount = 16; +const int maxBufferSize = 4 * 1024 * 1024; // 4 Mb + +} + +QMirClientClipboard::QMirClientClipboard() + : mMimeData(new QMimeData) + , mIsOutdated(true) + , mUpdatesDisabled(false) + , mDBusSetupDone(false) +{ +} + +QMirClientClipboard::~QMirClientClipboard() +{ + delete mMimeData; +} + +void QMirClientClipboard::requestDBusClipboardContents() +{ + if (!mDBusSetupDone) { + setupDBus(); + } + + if (!mPendingGetContentsCall.isNull()) + return; + + QDBusPendingCall pendingCall = mDBusClipboard->asyncCall("GetContents"); + + mPendingGetContentsCall = new QDBusPendingCallWatcher(pendingCall, this); + + QObject::connect(mPendingGetContentsCall.data(), SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(onDBusClipboardGetContentsFinished(QDBusPendingCallWatcher*))); +} + +void QMirClientClipboard::onDBusClipboardGetContentsFinished(QDBusPendingCallWatcher* call) +{ + Q_ASSERT(call == mPendingGetContentsCall.data()); + + QDBusPendingReply<QByteArray> reply = *call; + if (reply.isError()) { + qCritical("QMirClientClipboard - Failed to get system clipboard contents via D-Bus. %s, %s", + qPrintable(reply.error().name()), qPrintable(reply.error().message())); + // TODO: Might try again later a number of times... + } else { + QByteArray serializedMimeData = reply.argumentAt<0>(); + updateMimeData(serializedMimeData); + } + call->deleteLater(); +} + +void QMirClientClipboard::onDBusClipboardSetContentsFinished(QDBusPendingCallWatcher *call) +{ + QDBusPendingReply<void> reply = *call; + if (reply.isError()) { + qCritical("QMirClientClipboard - Failed to set the system clipboard contents via D-Bus. %s, %s", + qPrintable(reply.error().name()), qPrintable(reply.error().message())); + // TODO: Might try again later a number of times... + } + call->deleteLater(); +} + +void QMirClientClipboard::updateMimeData(const QByteArray &serializedMimeData) +{ + if (mUpdatesDisabled) + return; + + QMimeData *newMimeData = deserializeMimeData(serializedMimeData); + if (newMimeData) { + delete mMimeData; + mMimeData = newMimeData; + mIsOutdated = false; + emitChanged(QClipboard::Clipboard); + } else { + qWarning("QMirClientClipboard - Got invalid serialized mime data. Ignoring it."); + } +} + +void QMirClientClipboard::setupDBus() +{ + QDBusConnection dbusConnection = QDBusConnection::sessionBus(); + + bool ok = dbusConnection.connect( + "com.canonical.QtMir", + "/com/canonical/QtMir/Clipboard", + "com.canonical.QtMir.Clipboard", + "ContentsChanged", + this, SLOT(updateMimeData(QByteArray))); + if (!ok) { + qCritical("QMirClientClipboard - Failed to connect to ContentsChanged signal form the D-Bus system clipboard."); + } + + mDBusClipboard = new QDBusInterface("com.canonical.QtMir", + "/com/canonical/QtMir/Clipboard", + "com.canonical.QtMir.Clipboard", + dbusConnection); + + mDBusSetupDone = true; +} + +QByteArray QMirClientClipboard::serializeMimeData(QMimeData *mimeData) const +{ + const QStringList formats = mimeData->formats(); + const int formatCount = qMin(formats.size(), maxFormatsCount); + const int headerSize = sizeof(int) + (formatCount * 4 * sizeof(int)); + int bufferSize = headerSize; + + for (int i = 0; i < formatCount; i++) + bufferSize += formats[i].size() + mimeData->data(formats[i]).size(); + + QByteArray serializedMimeData; + if (bufferSize <= maxBufferSize) { + // Serialize data. + serializedMimeData.resize(bufferSize); + { + char *buffer = serializedMimeData.data(); + int* header = reinterpret_cast<int*>(serializedMimeData.data()); + int offset = headerSize; + header[0] = formatCount; + for (int i = 0; i < formatCount; i++) { + const int formatOffset = offset; + const int formatSize = formats[i].size(); + const int dataOffset = offset + formatSize; + const int dataSize = mimeData->data(formats[i]).size(); + memcpy(&buffer[formatOffset], formats[i].toLatin1().data(), formatSize); + memcpy(&buffer[dataOffset], mimeData->data(formats[i]).data(), dataSize); + header[i*4+1] = formatOffset; + header[i*4+2] = formatSize; + header[i*4+3] = dataOffset; + header[i*4+4] = dataSize; + offset += formatSize + dataSize; + } + } + } else { + qWarning("QMirClientClipboard: Not sending contents (%d bytes) to the global clipboard as it's" + " bigger than the maximum allowed size of %d bytes", bufferSize, maxBufferSize); + } + + return serializedMimeData; +} + +QMimeData *QMirClientClipboard::deserializeMimeData(const QByteArray &serializedMimeData) const +{ + if (static_cast<std::size_t>(serializedMimeData.size()) < sizeof(int)) { + // Data is invalid + return nullptr; + } + + QMimeData *mimeData = new QMimeData; + + const char* const buffer = serializedMimeData.constData(); + const int* const header = reinterpret_cast<const int*>(serializedMimeData.constData()); + + const int count = qMin(header[0], maxFormatsCount); + + for (int i = 0; i < count; i++) { + const int formatOffset = header[i*4+1]; + const int formatSize = header[i*4+2]; + const int dataOffset = header[i*4+3]; + const int dataSize = header[i*4+4]; + + if (formatOffset + formatSize <= serializedMimeData.size() + && dataOffset + dataSize <= serializedMimeData.size()) { + + QString mimeType = QString::fromLatin1(&buffer[formatOffset], formatSize); + QByteArray mimeDataBytes(&buffer[dataOffset], dataSize); + + mimeData->setData(mimeType, mimeDataBytes); + } + } + + return mimeData; +} + +QMimeData* QMirClientClipboard::mimeData(QClipboard::Mode mode) +{ + if (mode != QClipboard::Clipboard) + return nullptr; + + if (mIsOutdated && mPendingGetContentsCall.isNull()) { + requestDBusClipboardContents(); + } + + // Return whatever we have at the moment instead of blocking until we have something. + // + // This might be called during app startup just for the sake of checking if some + // "Paste" UI control should be enabled or not. + // We will emit QClipboard::changed() once we finally have something. + return mMimeData; +} + +void QMirClientClipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode) +{ + if (mode != QClipboard::Clipboard) + return; + + if (!mPendingGetContentsCall.isNull()) { + // Ignore whatever comes from the system clipboard as we are going to change it anyway + QObject::disconnect(mPendingGetContentsCall.data(), 0, this, 0); + mUpdatesDisabled = true; + mPendingGetContentsCall->waitForFinished(); + mUpdatesDisabled = false; + delete mPendingGetContentsCall.data(); + } + + QByteArray serializedMimeData = serializeMimeData(mimeData); + if (!serializedMimeData.isEmpty()) { + setDBusClipboardContents(serializedMimeData); + } + + mMimeData = mimeData; + emitChanged(QClipboard::Clipboard); +} + +bool QMirClientClipboard::supportsMode(QClipboard::Mode mode) const +{ + return mode == QClipboard::Clipboard; +} + +bool QMirClientClipboard::ownsMode(QClipboard::Mode mode) const +{ + Q_UNUSED(mode); + return false; +} + +void QMirClientClipboard::setDBusClipboardContents(const QByteArray &clipboardContents) +{ + if (!mPendingSetContentsCall.isNull()) { + // Ignore any previous set call as we are going to overwrite it anyway + QObject::disconnect(mPendingSetContentsCall.data(), 0, this, 0); + mUpdatesDisabled = true; + mPendingSetContentsCall->waitForFinished(); + mUpdatesDisabled = false; + delete mPendingSetContentsCall.data(); + } + + QDBusPendingCall pendingCall = mDBusClipboard->asyncCall("SetContents", clipboardContents); + + mPendingSetContentsCall = new QDBusPendingCallWatcher(pendingCall, this); + + QObject::connect(mPendingSetContentsCall.data(), SIGNAL(finished(QDBusPendingCallWatcher*)), + this, SLOT(onDBusClipboardSetContentsFinished(QDBusPendingCallWatcher*))); +} diff --git a/src/plugins/platforms/mirclient/qmirclientclipboard.h b/src/plugins/platforms/mirclient/qmirclientclipboard.h new file mode 100644 index 0000000000..d3d3d400d2 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientclipboard.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMIRCLIENTCLIPBOARD_H +#define QMIRCLIENTCLIPBOARD_H + +#include <qpa/qplatformclipboard.h> + +#include <QMimeData> +#include <QPointer> +class QDBusInterface; +class QDBusPendingCallWatcher; + +class QMirClientClipboard : public QObject, public QPlatformClipboard +{ + Q_OBJECT +public: + QMirClientClipboard(); + virtual ~QMirClientClipboard(); + + // QPlatformClipboard methods. + QMimeData* mimeData(QClipboard::Mode mode = QClipboard::Clipboard) override; + void setMimeData(QMimeData* data, QClipboard::Mode mode = QClipboard::Clipboard) override; + bool supportsMode(QClipboard::Mode mode) const override; + bool ownsMode(QClipboard::Mode mode) const override; + + void requestDBusClipboardContents(); + +private Q_SLOTS: + void onDBusClipboardGetContentsFinished(QDBusPendingCallWatcher*); + void onDBusClipboardSetContentsFinished(QDBusPendingCallWatcher*); + void updateMimeData(const QByteArray &serializedMimeData); + +private: + void setupDBus(); + + QByteArray serializeMimeData(QMimeData *mimeData) const; + QMimeData *deserializeMimeData(const QByteArray &serializedMimeData) const; + + void setDBusClipboardContents(const QByteArray &clipboardContents); + + QMimeData *mMimeData; + bool mIsOutdated; + + QPointer<QDBusInterface> mDBusClipboard; + + QPointer<QDBusPendingCallWatcher> mPendingGetContentsCall; + QPointer<QDBusPendingCallWatcher> mPendingSetContentsCall; + + bool mUpdatesDisabled; + bool mDBusSetupDone; +}; + +#endif // QMIRCLIENTCLIPBOARD_H diff --git a/src/plugins/platforms/mirclient/qmirclientglcontext.cpp b/src/plugins/platforms/mirclient/qmirclientglcontext.cpp new file mode 100644 index 0000000000..bfba5051e5 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientglcontext.cpp @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qmirclientglcontext.h" +#include "qmirclientwindow.h" +#include "qmirclientlogging.h" +#include <QtPlatformSupport/private/qeglconvenience_p.h> + +#if !defined(QT_NO_DEBUG) +static void printOpenGLESConfig() { + static bool once = true; + if (once) { + const char* string = (const char*) glGetString(GL_VENDOR); + LOG("OpenGL ES vendor: %s", string); + string = (const char*) glGetString(GL_RENDERER); + LOG("OpenGL ES renderer: %s", string); + string = (const char*) glGetString(GL_VERSION); + LOG("OpenGL ES version: %s", string); + string = (const char*) glGetString(GL_SHADING_LANGUAGE_VERSION); + LOG("OpenGL ES Shading Language version: %s", string); + string = (const char*) glGetString(GL_EXTENSIONS); + LOG("OpenGL ES extensions: %s", string); + once = false; + } +} +#endif + +static EGLenum api_in_use() +{ +#ifdef QTUBUNTU_USE_OPENGL + return EGL_OPENGL_API; +#else + return EGL_OPENGL_ES_API; +#endif +} + +QMirClientOpenGLContext::QMirClientOpenGLContext(QMirClientScreen* screen, QMirClientOpenGLContext* share) +{ + ASSERT(screen != NULL); + mEglDisplay = screen->eglDisplay(); + mScreen = screen; + + // Create an OpenGL ES 2 context. + QVector<EGLint> attribs; + attribs.append(EGL_CONTEXT_CLIENT_VERSION); + attribs.append(2); + attribs.append(EGL_NONE); + ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE); + + mEglContext = eglCreateContext(mEglDisplay, screen->eglConfig(), share ? share->eglContext() : EGL_NO_CONTEXT, + attribs.constData()); + DASSERT(mEglContext != EGL_NO_CONTEXT); +} + +QMirClientOpenGLContext::~QMirClientOpenGLContext() +{ + ASSERT(eglDestroyContext(mEglDisplay, mEglContext) == EGL_TRUE); +} + +bool QMirClientOpenGLContext::makeCurrent(QPlatformSurface* surface) +{ + DASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface); + EGLSurface eglSurface = static_cast<QMirClientWindow*>(surface)->eglSurface(); +#if defined(QT_NO_DEBUG) + eglBindAPI(api_in_use()); + eglMakeCurrent(mEglDisplay, eglSurface, eglSurface, mEglContext); +#else + ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE); + ASSERT(eglMakeCurrent(mEglDisplay, eglSurface, eglSurface, mEglContext) == EGL_TRUE); + printOpenGLESConfig(); +#endif + return true; +} + +void QMirClientOpenGLContext::doneCurrent() +{ +#if defined(QT_NO_DEBUG) + eglBindAPI(api_in_use()); + eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); +#else + ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE); + ASSERT(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) == EGL_TRUE); +#endif +} + +void QMirClientOpenGLContext::swapBuffers(QPlatformSurface* surface) +{ + QMirClientWindow *ubuntuWindow = static_cast<QMirClientWindow*>(surface); + + EGLSurface eglSurface = ubuntuWindow->eglSurface(); +#if defined(QT_NO_DEBUG) + eglBindAPI(api_in_use()); + eglSwapBuffers(mEglDisplay, eglSurface); +#else + ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE); + ASSERT(eglSwapBuffers(mEglDisplay, eglSurface) == EGL_TRUE); +#endif + + // "Technique" copied from mir, in examples/eglapp.c around line 96 + EGLint newBufferWidth = -1; + EGLint newBufferHeight = -1; + /* + * Querying the surface (actually the current buffer) dimensions here is + * the only truly safe way to be sure that the dimensions we think we + * have are those of the buffer being rendered to. But this should be + * improved in future; https://bugs.launchpad.net/mir/+bug/1194384 + */ + eglQuerySurface(mEglDisplay, eglSurface, EGL_WIDTH, &newBufferWidth); + eglQuerySurface(mEglDisplay, eglSurface, EGL_HEIGHT, &newBufferHeight); + + ubuntuWindow->onBuffersSwapped_threadSafe(newBufferWidth, newBufferHeight); +} + +void (*QMirClientOpenGLContext::getProcAddress(const QByteArray& procName)) () +{ +#if defined(QT_NO_DEBUG) + eglBindAPI(api_in_use()); +#else + ASSERT(eglBindAPI(api_in_use()) == EGL_TRUE); +#endif + return eglGetProcAddress(procName.constData()); +} diff --git a/src/plugins/platforms/mirclient/qmirclientglcontext.h b/src/plugins/platforms/mirclient/qmirclientglcontext.h new file mode 100644 index 0000000000..cc40298259 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientglcontext.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMIRCLIENTGLCONTEXT_H +#define QMIRCLIENTGLCONTEXT_H + +#include <qpa/qplatformopenglcontext.h> +#include "qmirclientscreen.h" + +class QMirClientOpenGLContext : public QPlatformOpenGLContext +{ +public: + QMirClientOpenGLContext(QMirClientScreen* screen, QMirClientOpenGLContext* share); + virtual ~QMirClientOpenGLContext(); + + // QPlatformOpenGLContext methods. + QSurfaceFormat format() const override { return mScreen->surfaceFormat(); } + void swapBuffers(QPlatformSurface* surface) override; + bool makeCurrent(QPlatformSurface* surface) override; + void doneCurrent() override; + bool isValid() const override { return mEglContext != EGL_NO_CONTEXT; } + void (*getProcAddress(const QByteArray& procName)) (); + + EGLContext eglContext() const { return mEglContext; } + +private: + QMirClientScreen* mScreen; + EGLContext mEglContext; + EGLDisplay mEglDisplay; +}; + +#endif // QMIRCLIENTGLCONTEXT_H diff --git a/src/plugins/platforms/mirclient/qmirclientinput.cpp b/src/plugins/platforms/mirclient/qmirclientinput.cpp new file mode 100644 index 0000000000..56bc21f420 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientinput.cpp @@ -0,0 +1,520 @@ +/**************************************************************************** +** +** Copyright (C) 2014-2015 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +// Local +#include "qmirclientinput.h" +#include "qmirclientintegration.h" +#include "qmirclientnativeinterface.h" +#include "qmirclientscreen.h" +#include "qmirclientwindow.h" +#include "qmirclientlogging.h" +#include "qmirclientorientationchangeevent_p.h" + +// Qt +#if !defined(QT_NO_DEBUG) +#include <QtCore/QThread> +#endif +#include <QtCore/qglobal.h> +#include <QtCore/QCoreApplication> +#include <private/qguiapplication_p.h> +#include <qpa/qplatforminputcontext.h> +#include <qpa/qwindowsysteminterface.h> + +#include <xkbcommon/xkbcommon.h> +#include <xkbcommon/xkbcommon-keysyms.h> + +#include <mir_toolkit/mir_client_library.h> + +#define LOG_EVENTS 0 + +// XKB Keysyms which do not map directly to Qt types (i.e. Unicode points) +static const uint32_t KeyTable[] = { + XKB_KEY_Escape, Qt::Key_Escape, + XKB_KEY_Tab, Qt::Key_Tab, + XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab, + XKB_KEY_BackSpace, Qt::Key_Backspace, + XKB_KEY_Return, Qt::Key_Return, + XKB_KEY_Insert, Qt::Key_Insert, + XKB_KEY_Delete, Qt::Key_Delete, + XKB_KEY_Clear, Qt::Key_Delete, + XKB_KEY_Pause, Qt::Key_Pause, + XKB_KEY_Print, Qt::Key_Print, + + XKB_KEY_Home, Qt::Key_Home, + XKB_KEY_End, Qt::Key_End, + XKB_KEY_Left, Qt::Key_Left, + XKB_KEY_Up, Qt::Key_Up, + XKB_KEY_Right, Qt::Key_Right, + XKB_KEY_Down, Qt::Key_Down, + XKB_KEY_Prior, Qt::Key_PageUp, + XKB_KEY_Next, Qt::Key_PageDown, + + XKB_KEY_Shift_L, Qt::Key_Shift, + XKB_KEY_Shift_R, Qt::Key_Shift, + XKB_KEY_Shift_Lock, Qt::Key_Shift, + XKB_KEY_Control_L, Qt::Key_Control, + XKB_KEY_Control_R, Qt::Key_Control, + XKB_KEY_Meta_L, Qt::Key_Meta, + XKB_KEY_Meta_R, Qt::Key_Meta, + XKB_KEY_Alt_L, Qt::Key_Alt, + XKB_KEY_Alt_R, Qt::Key_Alt, + XKB_KEY_Caps_Lock, Qt::Key_CapsLock, + XKB_KEY_Num_Lock, Qt::Key_NumLock, + XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock, + XKB_KEY_Super_L, Qt::Key_Super_L, + XKB_KEY_Super_R, Qt::Key_Super_R, + XKB_KEY_Menu, Qt::Key_Menu, + XKB_KEY_Hyper_L, Qt::Key_Hyper_L, + XKB_KEY_Hyper_R, Qt::Key_Hyper_R, + XKB_KEY_Help, Qt::Key_Help, + + XKB_KEY_KP_Space, Qt::Key_Space, + XKB_KEY_KP_Tab, Qt::Key_Tab, + XKB_KEY_KP_Enter, Qt::Key_Enter, + XKB_KEY_KP_Home, Qt::Key_Home, + XKB_KEY_KP_Left, Qt::Key_Left, + XKB_KEY_KP_Up, Qt::Key_Up, + XKB_KEY_KP_Right, Qt::Key_Right, + XKB_KEY_KP_Down, Qt::Key_Down, + XKB_KEY_KP_Prior, Qt::Key_PageUp, + XKB_KEY_KP_Next, Qt::Key_PageDown, + XKB_KEY_KP_End, Qt::Key_End, + XKB_KEY_KP_Begin, Qt::Key_Clear, + XKB_KEY_KP_Insert, Qt::Key_Insert, + XKB_KEY_KP_Delete, Qt::Key_Delete, + XKB_KEY_KP_Equal, Qt::Key_Equal, + XKB_KEY_KP_Multiply, Qt::Key_Asterisk, + XKB_KEY_KP_Add, Qt::Key_Plus, + XKB_KEY_KP_Separator, Qt::Key_Comma, + XKB_KEY_KP_Subtract, Qt::Key_Minus, + XKB_KEY_KP_Decimal, Qt::Key_Period, + XKB_KEY_KP_Divide, Qt::Key_Slash, + + XKB_KEY_ISO_Level3_Shift, Qt::Key_AltGr, + XKB_KEY_Multi_key, Qt::Key_Multi_key, + XKB_KEY_Codeinput, Qt::Key_Codeinput, + XKB_KEY_SingleCandidate, Qt::Key_SingleCandidate, + XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate, + XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate, + + XKB_KEY_Mode_switch, Qt::Key_Mode_switch, + XKB_KEY_script_switch, Qt::Key_Mode_switch, + XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp, + XKB_KEY_XF86AudioLowerVolume, Qt::Key_VolumeDown, + XKB_KEY_XF86PowerOff, Qt::Key_PowerOff, + XKB_KEY_XF86PowerDown, Qt::Key_PowerDown, + + 0, 0 +}; + +class QMirClientEvent : public QEvent +{ +public: + QMirClientEvent(QMirClientWindow* window, const MirEvent *event, QEvent::Type type) + : QEvent(type), window(window) { + nativeEvent = mir_event_ref(event); + } + ~QMirClientEvent() + { + mir_event_unref(nativeEvent); + } + + QPointer<QMirClientWindow> window; + const MirEvent *nativeEvent; +}; + +QMirClientInput::QMirClientInput(QMirClientClientIntegration* integration) + : QObject(nullptr) + , mIntegration(integration) + , mEventFilterType(static_cast<QMirClientNativeInterface*>( + integration->nativeInterface())->genericEventFilterType()) + , mEventType(static_cast<QEvent::Type>(QEvent::registerEventType())) +{ + // Initialize touch device. + mTouchDevice = new QTouchDevice; + mTouchDevice->setType(QTouchDevice::TouchScreen); + mTouchDevice->setCapabilities( + QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure | + QTouchDevice::NormalizedPosition); + QWindowSystemInterface::registerTouchDevice(mTouchDevice); +} + +QMirClientInput::~QMirClientInput() +{ + // Qt will take care of deleting mTouchDevice. +} + +#if (LOG_EVENTS != 0) +static const char* nativeEventTypeToStr(MirEventType t) +{ + switch (t) + { + case mir_event_type_key: + return "mir_event_type_key"; + case mir_event_type_motion: + return "mir_event_type_motion"; + case mir_event_type_surface: + return "mir_event_type_surface"; + case mir_event_type_resize: + return "mir_event_type_resize"; + case mir_event_type_prompt_session_state_change: + return "mir_event_type_prompt_session_state_change"; + case mir_event_type_orientation: + return "mir_event_type_orientation"; + case mir_event_type_close_surface: + return "mir_event_type_close_surface"; + case mir_event_type_input: + return "mir_event_type_input"; + default: + DLOG("Invalid event type %d", t); + return "invalid"; + } +} +#endif // LOG_EVENTS != 0 + +void QMirClientInput::customEvent(QEvent* event) +{ + DASSERT(QThread::currentThread() == thread()); + QMirClientEvent* ubuntuEvent = static_cast<QMirClientEvent*>(event); + const MirEvent *nativeEvent = ubuntuEvent->nativeEvent; + + if ((ubuntuEvent->window == nullptr) || (ubuntuEvent->window->window() == nullptr)) { + qWarning() << "Attempted to deliver an event to a non-existent window, ignoring."; + return; + } + + // Event filtering. + long result; + if (QWindowSystemInterface::handleNativeEvent( + ubuntuEvent->window->window(), mEventFilterType, + const_cast<void *>(static_cast<const void *>(nativeEvent)), &result) == true) { + DLOG("event filtered out by native interface"); + return; + } + + #if (LOG_EVENTS != 0) + LOG("QMirClientInput::customEvent(type=%s)", nativeEventTypeToStr(mir_event_get_type(nativeEvent))); + #endif + + // Event dispatching. + switch (mir_event_get_type(nativeEvent)) + { + case mir_event_type_input: + dispatchInputEvent(ubuntuEvent->window->window(), mir_event_get_input_event(nativeEvent)); + break; + case mir_event_type_resize: + { + Q_ASSERT(ubuntuEvent->window->screen() == mIntegration->screen()); + + auto resizeEvent = mir_event_get_resize_event(nativeEvent); + + mIntegration->screen()->handleWindowSurfaceResize( + mir_resize_event_get_width(resizeEvent), + mir_resize_event_get_height(resizeEvent)); + + ubuntuEvent->window->handleSurfaceResize(mir_resize_event_get_width(resizeEvent), + mir_resize_event_get_height(resizeEvent)); + break; + } + case mir_event_type_surface: + { + auto surfaceEvent = mir_event_get_surface_event(nativeEvent); + if (mir_surface_event_get_attribute(surfaceEvent) == mir_surface_attrib_focus) { + ubuntuEvent->window->handleSurfaceFocusChange(mir_surface_event_get_attribute_value(surfaceEvent) == + mir_surface_focused); + } + break; + } + case mir_event_type_orientation: + dispatchOrientationEvent(ubuntuEvent->window->window(), mir_event_get_orientation_event(nativeEvent)); + break; + case mir_event_type_close_surface: + QWindowSystemInterface::handleCloseEvent(ubuntuEvent->window->window()); + break; + default: + DLOG("unhandled event type: %d", static_cast<int>(mir_event_get_type(nativeEvent))); + } +} + +void QMirClientInput::postEvent(QMirClientWindow *platformWindow, const MirEvent *event) +{ + QWindow *window = platformWindow->window(); + + QCoreApplication::postEvent(this, new QMirClientEvent( + platformWindow, event, mEventType)); + + if ((window->flags().testFlag(Qt::WindowTransparentForInput)) && window->parent()) { + QCoreApplication::postEvent(this, new QMirClientEvent( + static_cast<QMirClientWindow*>(platformWindow->QPlatformWindow::parent()), + event, mEventType)); + } +} + +void QMirClientInput::dispatchInputEvent(QWindow *window, const MirInputEvent *ev) +{ + switch (mir_input_event_get_type(ev)) + { + case mir_input_event_type_key: + dispatchKeyEvent(window, ev); + break; + case mir_input_event_type_touch: + dispatchTouchEvent(window, ev); + break; + case mir_input_event_type_pointer: + dispatchPointerEvent(window, ev); + break; + default: + break; + } +} + +void QMirClientInput::dispatchTouchEvent(QWindow *window, const MirInputEvent *ev) +{ + const MirTouchEvent *tev = mir_input_event_get_touch_event(ev); + + // FIXME(loicm) Max pressure is device specific. That one is for the Samsung Galaxy Nexus. That + // needs to be fixed as soon as the compat input lib adds query support. + const float kMaxPressure = 1.28; + const QRect kWindowGeometry = window->geometry(); + QList<QWindowSystemInterface::TouchPoint> touchPoints; + + + // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left + // as Qt::TouchPointMoved + const unsigned int kPointerCount = mir_touch_event_point_count(tev); + for (unsigned int i = 0; i < kPointerCount; ++i) { + QWindowSystemInterface::TouchPoint touchPoint; + + const float kX = mir_touch_event_axis_value(tev, i, mir_touch_axis_x) + kWindowGeometry.x(); + const float kY = mir_touch_event_axis_value(tev, i, mir_touch_axis_y) + kWindowGeometry.y(); // see bug lp:1346633 workaround comments elsewhere + const float kW = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_major); + const float kH = mir_touch_event_axis_value(tev, i, mir_touch_axis_touch_minor); + const float kP = mir_touch_event_axis_value(tev, i, mir_touch_axis_pressure); + touchPoint.id = mir_touch_event_id(tev, i); + touchPoint.normalPosition = QPointF(kX / kWindowGeometry.width(), kY / kWindowGeometry.height()); + touchPoint.area = QRectF(kX - (kW / 2.0), kY - (kH / 2.0), kW, kH); + touchPoint.pressure = kP / kMaxPressure; + + MirTouchAction touch_action = mir_touch_event_action(tev, i); + switch (touch_action) + { + case mir_touch_action_down: + touchPoint.state = Qt::TouchPointPressed; + break; + case mir_touch_action_up: + touchPoint.state = Qt::TouchPointReleased; + break; + case mir_touch_action_change: + default: + touchPoint.state = Qt::TouchPointMoved; + } + + touchPoints.append(touchPoint); + } + + ulong timestamp = mir_input_event_get_event_time(ev) / 1000000; + QWindowSystemInterface::handleTouchEvent(window, timestamp, + mTouchDevice, touchPoints); +} + +static uint32_t translateKeysym(uint32_t sym, char *string, size_t size) +{ + Q_UNUSED(size); + string[0] = '\0'; + + if (sym >= XKB_KEY_F1 && sym <= XKB_KEY_F35) + return Qt::Key_F1 + (int(sym) - XKB_KEY_F1); + + for (int i = 0; KeyTable[i]; i += 2) { + if (sym == KeyTable[i]) + return KeyTable[i + 1]; + } + + string[0] = sym; + string[1] = '\0'; + return toupper(sym); +} + +namespace +{ +Qt::KeyboardModifiers qt_modifiers_from_mir(MirInputEventModifiers modifiers) +{ + Qt::KeyboardModifiers q_modifiers = Qt::NoModifier; + if (modifiers & mir_input_event_modifier_shift) { + q_modifiers |= Qt::ShiftModifier; + } + if (modifiers & mir_input_event_modifier_ctrl) { + q_modifiers |= Qt::ControlModifier; + } + if (modifiers & mir_input_event_modifier_alt) { + q_modifiers |= Qt::AltModifier; + } + if (modifiers & mir_input_event_modifier_meta) { + q_modifiers |= Qt::MetaModifier; + } + return q_modifiers; +} +} + +void QMirClientInput::dispatchKeyEvent(QWindow *window, const MirInputEvent *event) +{ + const MirKeyboardEvent *key_event = mir_input_event_get_keyboard_event(event); + + ulong timestamp = mir_input_event_get_event_time(event) / 1000000; + xkb_keysym_t xk_sym = mir_keyboard_event_key_code(key_event); + + // Key modifier and unicode index mapping. + auto modifiers = qt_modifiers_from_mir(mir_keyboard_event_modifiers(key_event)); + + MirKeyboardAction action = mir_keyboard_event_action(key_event); + QEvent::Type keyType = action == mir_keyboard_action_up + ? QEvent::KeyRelease : QEvent::KeyPress; + + char s[2]; + int sym = translateKeysym(xk_sym, s, sizeof(s)); + QString text = QString::fromLatin1(s); + + bool is_auto_rep = action == mir_keyboard_action_repeat; + + QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext(); + if (context) { + QKeyEvent qKeyEvent(keyType, sym, modifiers, text, is_auto_rep); + qKeyEvent.setTimestamp(timestamp); + if (context->filterEvent(&qKeyEvent)) { + DLOG("key event filtered out by input context"); + return; + } + } + + QWindowSystemInterface::handleKeyEvent(window, timestamp, keyType, sym, modifiers, text, is_auto_rep); +} + +namespace +{ +Qt::MouseButtons extract_buttons(const MirPointerEvent *pev) +{ + Qt::MouseButtons buttons = Qt::NoButton; + if (mir_pointer_event_button_state(pev, mir_pointer_button_primary)) + buttons |= Qt::LeftButton; + if (mir_pointer_event_button_state(pev, mir_pointer_button_secondary)) + buttons |= Qt::RightButton; + if (mir_pointer_event_button_state(pev, mir_pointer_button_tertiary)) + buttons |= Qt::MidButton; + + // TODO: Should mir back and forward buttons exist? + // should they be Qt::X button 1 and 2? + return buttons; +} +} + +void QMirClientInput::dispatchPointerEvent(QWindow *window, const MirInputEvent *ev) +{ + auto timestamp = mir_input_event_get_event_time(ev) / 1000000; + + auto pev = mir_input_event_get_pointer_event(ev); + auto modifiers = qt_modifiers_from_mir(mir_pointer_event_modifiers(pev)); + auto buttons = extract_buttons(pev); + + auto local_point = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x), + mir_pointer_event_axis_value(pev, mir_pointer_axis_y)); + + QWindowSystemInterface::handleMouseEvent(window, timestamp, local_point, local_point /* Should we omit global point instead? */, + buttons, modifiers); +} + +#if (LOG_EVENTS != 0) +static const char* nativeOrientationDirectionToStr(MirOrientation orientation) +{ + switch (orientation) { + case mir_orientation_normal: + return "Normal"; + break; + case mir_orientation_left: + return "Left"; + break; + case mir_orientation_inverted: + return "Inverted"; + break; + case mir_orientation_right: + return "Right"; + break; + default: + return "INVALID!"; + } +} +#endif + +void QMirClientInput::dispatchOrientationEvent(QWindow *window, const MirOrientationEvent *event) +{ + MirOrientation mir_orientation = mir_orientation_event_get_direction(event); + #if (LOG_EVENTS != 0) + // Orientation event logging. + LOG("ORIENTATION direction: %s", nativeOrientationDirectionToStr(mir_orientation)); + #endif + + if (!window->screen()) { + DLOG("Window has no associated screen, dropping orientation event"); + return; + } + + OrientationChangeEvent::Orientation orientation; + switch (mir_orientation) { + case mir_orientation_normal: + orientation = OrientationChangeEvent::TopUp; + break; + case mir_orientation_left: + orientation = OrientationChangeEvent::LeftUp; + break; + case mir_orientation_inverted: + orientation = OrientationChangeEvent::TopDown; + break; + case mir_orientation_right: + orientation = OrientationChangeEvent::RightUp; + break; + default: + DLOG("No such orientation %d", mir_orientation); + return; + } + + // Dispatch orientation event to [Platform]Screen, as that is where Qt reads it. Screen will handle + // notifying Qt of the actual orientation change - done to prevent multiple Windows each creating + // an identical orientation change event and passing it directly to Qt. + // [Platform]Screen can also factor in the native orientation. + QCoreApplication::postEvent(static_cast<QMirClientScreen*>(window->screen()->handle()), + new OrientationChangeEvent(OrientationChangeEvent::mType, orientation)); +} + diff --git a/src/plugins/platforms/mirclient/qmirclientinput.h b/src/plugins/platforms/mirclient/qmirclientinput.h new file mode 100644 index 0000000000..c987d18c12 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientinput.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2014-2015 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMIRCLIENTINPUT_H +#define QMIRCLIENTINPUT_H + +// Qt +#include <qpa/qwindowsysteminterface.h> + +#include <mir_toolkit/mir_client_library.h> + +class QMirClientClientIntegration; +class QMirClientWindow; + +class QMirClientInput : public QObject +{ + Q_OBJECT + +public: + QMirClientInput(QMirClientClientIntegration* integration); + virtual ~QMirClientInput(); + + // QObject methods. + void customEvent(QEvent* event) override; + + void postEvent(QMirClientWindow* window, const MirEvent *event); + QMirClientClientIntegration* integration() const { return mIntegration; } + +protected: + void dispatchKeyEvent(QWindow *window, const MirInputEvent *event); + void dispatchPointerEvent(QWindow *window, const MirInputEvent *event); + void dispatchTouchEvent(QWindow *window, const MirInputEvent *event); + void dispatchInputEvent(QWindow *window, const MirInputEvent *event); + + void dispatchOrientationEvent(QWindow* window, const MirOrientationEvent *event); + +private: + QMirClientClientIntegration* mIntegration; + QTouchDevice* mTouchDevice; + const QByteArray mEventFilterType; + const QEvent::Type mEventType; +}; + +#endif // QMIRCLIENTINPUT_H diff --git a/src/plugins/platforms/mirclient/qmirclientintegration.cpp b/src/plugins/platforms/mirclient/qmirclientintegration.cpp new file mode 100644 index 0000000000..a234f4eac6 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientintegration.cpp @@ -0,0 +1,264 @@ +/**************************************************************************** +** +** Copyright (C) 2014-2015 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +// Qt +#include <QGuiApplication> +#include <private/qguiapplication_p.h> +#include <qpa/qplatformnativeinterface.h> +#include <qpa/qplatforminputcontextfactory_p.h> +#include <qpa/qplatforminputcontext.h> +#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> +#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> +#include <QOpenGLContext> + +// Local +#include "qmirclientbackingstore.h" +#include "qmirclientclipboard.h" +#include "qmirclientglcontext.h" +#include "qmirclientinput.h" +#include "qmirclientintegration.h" +#include "qmirclientlogging.h" +#include "qmirclientnativeinterface.h" +#include "qmirclientscreen.h" +#include "qmirclienttheme.h" +#include "qmirclientwindow.h" + +// platform-api +#include <ubuntu/application/lifecycle_delegate.h> +#include <ubuntu/application/id.h> +#include <ubuntu/application/options.h> + +static void resumedCallback(const UApplicationOptions *options, void* context) +{ + Q_UNUSED(options) + Q_UNUSED(context) + DASSERT(context != NULL); + QCoreApplication::postEvent(QCoreApplication::instance(), + new QEvent(QEvent::ApplicationActivate)); +} + +static void aboutToStopCallback(UApplicationArchive *archive, void* context) +{ + Q_UNUSED(archive) + DASSERT(context != NULL); + QMirClientClientIntegration* integration = static_cast<QMirClientClientIntegration*>(context); + integration->inputContext()->hideInputPanel(); + QCoreApplication::postEvent(QCoreApplication::instance(), + new QEvent(QEvent::ApplicationDeactivate)); +} + +QMirClientClientIntegration::QMirClientClientIntegration() + : QPlatformIntegration() + , mNativeInterface(new QMirClientNativeInterface) + , mFontDb(new QGenericUnixFontDatabase) + , mServices(new QMirClientPlatformServices) + , mClipboard(new QMirClientClipboard) + , mScaleFactor(1.0) +{ + setupOptions(); + setupDescription(); + + // Create new application instance + mInstance = u_application_instance_new_from_description_with_options(mDesc, mOptions); + + if (mInstance == nullptr) + qFatal("QMirClientClientIntegration: connection to Mir server failed. Check that a Mir server is\n" + "running, and the correct socket is being used and is accessible. The shell may have\n" + "rejected the incoming connection, so check its log file"); + + // Create default screen. + mScreen = new QMirClientScreen(u_application_instance_get_mir_connection(mInstance)); + screenAdded(mScreen); + + // Initialize input. + if (qEnvironmentVariableIsEmpty("QTUBUNTU_NO_INPUT")) { + mInput = new QMirClientInput(this); + mInputContext = QPlatformInputContextFactory::create(); + } else { + mInput = nullptr; + mInputContext = nullptr; + } + + // compute the scale factor + const int defaultGridUnit = 8; + int gridUnit = defaultGridUnit; + QByteArray gridUnitString = qgetenv("GRID_UNIT_PX"); + if (!gridUnitString.isEmpty()) { + bool ok; + gridUnit = gridUnitString.toInt(&ok); + if (!ok) { + gridUnit = defaultGridUnit; + } + } + mScaleFactor = static_cast<qreal>(gridUnit) / defaultGridUnit; +} + +QMirClientClientIntegration::~QMirClientClientIntegration() +{ + delete mInput; + delete mInputContext; + delete mScreen; + delete mServices; +} + +QPlatformServices *QMirClientClientIntegration::services() const +{ + return mServices; +} + +void QMirClientClientIntegration::setupOptions() +{ + QStringList args = QCoreApplication::arguments(); + int argc = args.size() + 1; + char **argv = new char*[argc]; + for (int i = 0; i < argc - 1; i++) + argv[i] = qstrdup(args.at(i).toLocal8Bit()); + argv[argc - 1] = nullptr; + + mOptions = u_application_options_new_from_cmd_line(argc - 1, argv); + + for (int i = 0; i < argc; i++) + delete [] argv[i]; + delete [] argv; +} + +void QMirClientClientIntegration::setupDescription() +{ + mDesc = u_application_description_new(); + UApplicationId* id = u_application_id_new_from_stringn("QtUbuntu", 8); + u_application_description_set_application_id(mDesc, id); + + UApplicationLifecycleDelegate* delegate = u_application_lifecycle_delegate_new(); + u_application_lifecycle_delegate_set_application_resumed_cb(delegate, &resumedCallback); + u_application_lifecycle_delegate_set_application_about_to_stop_cb(delegate, &aboutToStopCallback); + u_application_lifecycle_delegate_set_context(delegate, this); + u_application_description_set_application_lifecycle_delegate(mDesc, delegate); +} + +QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* window) const +{ + return const_cast<QMirClientClientIntegration*>(this)->createPlatformWindow(window); +} + +QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* window) +{ + QPlatformWindow* platformWindow = new QMirClientWindow( + window, mClipboard, static_cast<QMirClientScreen*>(mScreen), mInput, u_application_instance_get_mir_connection(mInstance)); + platformWindow->requestActivateWindow(); + return platformWindow; +} + +bool QMirClientClientIntegration::hasCapability(QPlatformIntegration::Capability cap) const +{ + switch (cap) { + case ThreadedPixmaps: + return true; + break; + + case OpenGL: + return true; + break; + + case ThreadedOpenGL: + if (qEnvironmentVariableIsEmpty("QTUBUNTU_NO_THREADED_OPENGL")) { + return true; + } else { + DLOG("ubuntumirclient: disabled threaded OpenGL"); + return false; + } + break; + + default: + return QPlatformIntegration::hasCapability(cap); + } +} + +QAbstractEventDispatcher *QMirClientClientIntegration::createEventDispatcher() const +{ + return createUnixEventDispatcher(); +} + +QPlatformBackingStore* QMirClientClientIntegration::createPlatformBackingStore(QWindow* window) const +{ + return new QMirClientBackingStore(window); +} + +QPlatformOpenGLContext* QMirClientClientIntegration::createPlatformOpenGLContext( + QOpenGLContext* context) const +{ + return const_cast<QMirClientClientIntegration*>(this)->createPlatformOpenGLContext(context); +} + +QPlatformOpenGLContext* QMirClientClientIntegration::createPlatformOpenGLContext( + QOpenGLContext* context) +{ + return new QMirClientOpenGLContext(static_cast<QMirClientScreen*>(context->screen()->handle()), + static_cast<QMirClientOpenGLContext*>(context->shareHandle())); +} + +QStringList QMirClientClientIntegration::themeNames() const +{ + return QStringList(QMirClientTheme::name); +} + +QPlatformTheme* QMirClientClientIntegration::createPlatformTheme(const QString& name) const +{ + Q_UNUSED(name); + return new QMirClientTheme; +} + +QVariant QMirClientClientIntegration::styleHint(StyleHint hint) const +{ + switch (hint) { + case QPlatformIntegration::StartDragDistance: { + // default is 10 pixels (see QPlatformTheme::defaultThemeHint) + return 10.0 * mScaleFactor; + } + case QPlatformIntegration::PasswordMaskDelay: { + // return time in milliseconds - 1 second + return QVariant(1000); + } + default: + break; + } + return QPlatformIntegration::styleHint(hint); +} + +QPlatformClipboard* QMirClientClientIntegration::clipboard() const +{ + return mClipboard.data(); +} diff --git a/src/plugins/platforms/mirclient/qmirclientintegration.h b/src/plugins/platforms/mirclient/qmirclientintegration.h new file mode 100644 index 0000000000..2960209691 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientintegration.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMIRCLIENTINTEGRATION_H +#define QMIRCLIENTINTEGRATION_H + +#include <qpa/qplatformintegration.h> +#include <QSharedPointer> + +#include "qmirclientplatformservices.h" + +// platform-api +#include <ubuntu/application/description.h> +#include <ubuntu/application/instance.h> + +class QMirClientClipboard; +class QMirClientInput; +class QMirClientScreen; + +class QMirClientClientIntegration : public QPlatformIntegration { +public: + QMirClientClientIntegration(); + virtual ~QMirClientClientIntegration(); + + // QPlatformIntegration methods. + bool hasCapability(QPlatformIntegration::Capability cap) const override; + QAbstractEventDispatcher *createEventDispatcher() const override; + QPlatformNativeInterface* nativeInterface() const override { return mNativeInterface; } + QPlatformBackingStore* createPlatformBackingStore(QWindow* window) const override; + QPlatformOpenGLContext* createPlatformOpenGLContext(QOpenGLContext* context) const override; + QPlatformFontDatabase* fontDatabase() const override { return mFontDb; } + QStringList themeNames() const override; + QPlatformTheme* createPlatformTheme(const QString& name) const override; + QVariant styleHint(StyleHint hint) const override; + QPlatformServices *services() const override; + QPlatformWindow* createPlatformWindow(QWindow* window) const override; + QPlatformInputContext* inputContext() const override { return mInputContext; } + QPlatformClipboard* clipboard() const override; + + QPlatformOpenGLContext* createPlatformOpenGLContext(QOpenGLContext* context); + QPlatformWindow* createPlatformWindow(QWindow* window); + QMirClientScreen* screen() const { return mScreen; } + +private: + void setupOptions(); + void setupDescription(); + + QPlatformNativeInterface* mNativeInterface; + QPlatformFontDatabase* mFontDb; + + QMirClientPlatformServices* mServices; + + QMirClientScreen* mScreen; + QMirClientInput* mInput; + QPlatformInputContext* mInputContext; + QSharedPointer<QMirClientClipboard> mClipboard; + qreal mScaleFactor; + + // Platform API stuff + UApplicationOptions* mOptions; + UApplicationDescription* mDesc; + UApplicationInstance* mInstance; +}; + +#endif // QMIRCLIENTINTEGRATION_H diff --git a/src/plugins/platforms/mirclient/qmirclientlogging.h b/src/plugins/platforms/mirclient/qmirclientlogging.h new file mode 100644 index 0000000000..80914d28b9 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientlogging.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMIRCLIENTLOGGING_H +#define QMIRCLIENTLOGGING_H + +// Logging and assertion macros. +#define LOG(...) qDebug(__VA_ARGS__) +#define LOG_IF(cond,...) do { if (cond) qDebug(__VA_ARGS__); } while (0) +#define ASSERT(cond) ((!(cond)) ? qt_assert(#cond,__FILE__,__LINE__) : qt_noop()) +#define NOT_REACHED() qt_assert("Not reached!",__FILE__,__LINE__) + +// Logging and assertion macros are compiled out for release builds. +#if !defined(QT_NO_DEBUG) +#define DLOG(...) LOG(__VA_ARGS__) +#define DLOG_IF(cond,...) LOG_IF((cond), __VA_ARGS__) +#define DASSERT(cond) ASSERT((cond)) +#define DNOT_REACHED() NOT_REACHED() +#else +#define DLOG(...) qt_noop() +#define DLOG_IF(cond,...) qt_noop() +#define DASSERT(cond) qt_noop() +#define DNOT_REACHED() qt_noop() +#endif + +#endif // QMIRCLIENTLOGGING_H diff --git a/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp b/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp new file mode 100644 index 0000000000..a0bb932df3 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +// Qt +#include <private/qguiapplication_p.h> +#include <QtGui/qopenglcontext.h> +#include <QtGui/qscreen.h> +#include <QtCore/QMap> + +// Local +#include "qmirclientnativeinterface.h" +#include "qmirclientscreen.h" +#include "qmirclientglcontext.h" + +class QMirClientResourceMap : public QMap<QByteArray, QMirClientNativeInterface::ResourceType> +{ +public: + QMirClientResourceMap() + : QMap<QByteArray, QMirClientNativeInterface::ResourceType>() { + insert("egldisplay", QMirClientNativeInterface::EglDisplay); + insert("eglcontext", QMirClientNativeInterface::EglContext); + insert("nativeorientation", QMirClientNativeInterface::NativeOrientation); + insert("display", QMirClientNativeInterface::Display); + } +}; + +Q_GLOBAL_STATIC(QMirClientResourceMap, ubuntuResourceMap) + +QMirClientNativeInterface::QMirClientNativeInterface() + : mGenericEventFilterType(QByteArrayLiteral("Event")) + , mNativeOrientation(nullptr) +{ +} + +QMirClientNativeInterface::~QMirClientNativeInterface() +{ + delete mNativeOrientation; + mNativeOrientation = nullptr; +} + +void* QMirClientNativeInterface::nativeResourceForContext( + const QByteArray& resourceString, QOpenGLContext* context) +{ + if (!context) + return nullptr; + + const QByteArray kLowerCaseResource = resourceString.toLower(); + + if (!ubuntuResourceMap()->contains(kLowerCaseResource)) + return nullptr; + + const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource); + + if (kResourceType == QMirClientNativeInterface::EglContext) + return static_cast<QMirClientOpenGLContext*>(context->handle())->eglContext(); + else + return nullptr; +} + +void* QMirClientNativeInterface::nativeResourceForWindow(const QByteArray& resourceString, QWindow* window) +{ + const QByteArray kLowerCaseResource = resourceString.toLower(); + if (!ubuntuResourceMap()->contains(kLowerCaseResource)) + return NULL; + const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource); + if (kResourceType == QMirClientNativeInterface::EglDisplay) { + if (window) { + return static_cast<QMirClientScreen*>(window->screen()->handle())->eglDisplay(); + } else { + return static_cast<QMirClientScreen*>( + QGuiApplication::primaryScreen()->handle())->eglDisplay(); + } + } else if (kResourceType == QMirClientNativeInterface::NativeOrientation) { + // Return the device's native screen orientation. + if (window) { + QMirClientScreen *ubuntuScreen = static_cast<QMirClientScreen*>(window->screen()->handle()); + mNativeOrientation = new Qt::ScreenOrientation(ubuntuScreen->nativeOrientation()); + } else { + QPlatformScreen *platformScreen = QGuiApplication::primaryScreen()->handle(); + mNativeOrientation = new Qt::ScreenOrientation(platformScreen->nativeOrientation()); + } + return mNativeOrientation; + } else { + return NULL; + } +} + +void* QMirClientNativeInterface::nativeResourceForScreen(const QByteArray& resourceString, QScreen* screen) +{ + const QByteArray kLowerCaseResource = resourceString.toLower(); + if (!ubuntuResourceMap()->contains(kLowerCaseResource)) + return NULL; + const ResourceType kResourceType = ubuntuResourceMap()->value(kLowerCaseResource); + if (kResourceType == QMirClientNativeInterface::Display) { + if (!screen) + screen = QGuiApplication::primaryScreen(); + return static_cast<QMirClientScreen*>(screen->handle())->eglNativeDisplay(); + } else + return NULL; +} diff --git a/src/plugins/platforms/mirclient/qmirclientnativeinterface.h b/src/plugins/platforms/mirclient/qmirclientnativeinterface.h new file mode 100644 index 0000000000..84f03bb915 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientnativeinterface.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMIRCLIENTNATIVEINTERFACE_H +#define QMIRCLIENTNATIVEINTERFACE_H + +#include <qpa/qplatformnativeinterface.h> + +class QMirClientNativeInterface : public QPlatformNativeInterface { +public: + enum ResourceType { EglDisplay, EglContext, NativeOrientation, Display }; + + QMirClientNativeInterface(); + ~QMirClientNativeInterface(); + + // QPlatformNativeInterface methods. + void* nativeResourceForContext(const QByteArray& resourceString, + QOpenGLContext* context) override; + void* nativeResourceForWindow(const QByteArray& resourceString, + QWindow* window) override; + void* nativeResourceForScreen(const QByteArray& resourceString, + QScreen* screen) override; + + // New methods. + const QByteArray& genericEventFilterType() const { return mGenericEventFilterType; } + +private: + const QByteArray mGenericEventFilterType; + Qt::ScreenOrientation* mNativeOrientation; +}; + +#endif // QMIRCLIENTNATIVEINTERFACE_H diff --git a/src/plugins/platforms/mirclient/qmirclientorientationchangeevent_p.h b/src/plugins/platforms/mirclient/qmirclientorientationchangeevent_p.h new file mode 100644 index 0000000000..24d7307faa --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientorientationchangeevent_p.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMIRCLIENTORIENTATIONCHANGEEVENT_P_H +#define QMIRCLIENTORIENTATIONCHANGEEVENT_P_H + +#include <QEvent> +#include "qmirclientlogging.h" + +class OrientationChangeEvent : public QEvent { +public: + enum Orientation { + Undefined = 0, + TopUp, + TopDown, + LeftUp, + RightUp, + FaceUp, + FaceDown + }; + + OrientationChangeEvent(QEvent::Type type, Orientation orientation) + : QEvent(type) + , mOrientation(orientation) + { + } + + static const QEvent::Type mType; + Orientation mOrientation; +}; + +#endif // QMIRCLIENTORIENTATIONCHANGEEVENT_P_H diff --git a/src/plugins/platforms/mirclient/qmirclientplatformservices.cpp b/src/plugins/platforms/mirclient/qmirclientplatformservices.cpp new file mode 100644 index 0000000000..d0260c79d3 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientplatformservices.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qmirclientplatformservices.h" + +#include <QUrl> + +#include <ubuntu/application/url_dispatcher/service.h> +#include <ubuntu/application/url_dispatcher/session.h> + +bool QMirClientPlatformServices::openUrl(const QUrl &url) +{ + return callDispatcher(url); +} + +bool QMirClientPlatformServices::openDocument(const QUrl &url) +{ + return callDispatcher(url); +} + +bool QMirClientPlatformServices::callDispatcher(const QUrl &url) +{ + UAUrlDispatcherSession* session = ua_url_dispatcher_session(); + if (!session) + return false; + + ua_url_dispatcher_session_open(session, url.toEncoded().constData(), NULL, NULL); + + free(session); + + // We are returning true here because the other option + // is spawning a nested event loop and wait for the + // callback. But there is no guarantee on how fast + // the callback is going to be so we prefer to avoid the + // nested event loop. Long term plan is improve Qt API + // to support an async openUrl + return true; +} diff --git a/src/plugins/platforms/mirclient/qmirclientplatformservices.h b/src/plugins/platforms/mirclient/qmirclientplatformservices.h new file mode 100644 index 0000000000..64a0432d06 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientplatformservices.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMIRCLIENTPLATFORMSERVICES_H +#define QMIRCLIENTPLATFORMSERVICES_H + +#include <qpa/qplatformservices.h> +#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h> +#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h> + +class QMirClientPlatformServices : public QPlatformServices { +public: + bool openUrl(const QUrl &url) override; + bool openDocument(const QUrl &url) override; + +private: + bool callDispatcher(const QUrl &url); +}; + +#endif // QMIRCLIENTPLATFORMSERVICES_H diff --git a/src/plugins/platforms/mirclient/qmirclientplugin.cpp b/src/plugins/platforms/mirclient/qmirclientplugin.cpp new file mode 100644 index 0000000000..43d913f8d2 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientplugin.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qmirclientplugin.h" +#include "qmirclientintegration.h" + +QStringList QMirClientIntegrationPlugin::keys() const +{ + QStringList list; + list << "mirclient"; + return list; +} + +QPlatformIntegration* QMirClientIntegrationPlugin::create(const QString &system, + const QStringList &) +{ + if (system.toLower() == "mirclient") { +#ifdef PLATFORM_API_TOUCH + setenv("UBUNTU_PLATFORM_API_BACKEND", "touch_mirclient", 1); +#else + setenv("UBUNTU_PLATFORM_API_BACKEND", "desktop_mirclient", 1); +#endif + return new QMirClientClientIntegration; + } else { + return 0; + } +} diff --git a/src/plugins/platforms/mirclient/qmirclientplugin.h b/src/plugins/platforms/mirclient/qmirclientplugin.h new file mode 100644 index 0000000000..a6f1a1081a --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientplugin.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMIRCLIENTPLUGIN_H +#define QMIRCLIENTPLUGIN_H + +#include <qpa/qplatformintegrationplugin.h> + +class QMirClientIntegrationPlugin : public QPlatformIntegrationPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "mirclient.json") + +public: + QStringList keys() const; + QPlatformIntegration* create(const QString&, const QStringList&); +}; + +#endif // QMIRCLIENTPLUGIN_H diff --git a/src/plugins/platforms/mirclient/qmirclientscreen.cpp b/src/plugins/platforms/mirclient/qmirclientscreen.cpp new file mode 100644 index 0000000000..5c4b1cd0d6 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientscreen.cpp @@ -0,0 +1,296 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <mir_toolkit/mir_client_library.h> + +// Qt +#include <QCoreApplication> +#include <QtCore/qmath.h> +#include <QScreen> +#include <QThread> +#include <qpa/qwindowsysteminterface.h> +#include <QtPlatformSupport/private/qeglconvenience_p.h> + +// local +#include "qmirclientscreen.h" +#include "qmirclientlogging.h" +#include "qmirclientorientationchangeevent_p.h" + +#include "memory" + +static const int kSwapInterval = 1; + +#if !defined(QT_NO_DEBUG) + +static const char *orientationToStr(Qt::ScreenOrientation orientation) { + switch (orientation) { + case Qt::PrimaryOrientation: + return "primary"; + case Qt::PortraitOrientation: + return "portrait"; + case Qt::LandscapeOrientation: + return "landscape"; + case Qt::InvertedPortraitOrientation: + return "inverted portrait"; + case Qt::InvertedLandscapeOrientation: + return "inverted landscape"; + default: + return "INVALID!"; + } +} + +static void printEglConfig(EGLDisplay display, EGLConfig config) { + DASSERT(display != EGL_NO_DISPLAY); + DASSERT(config != nullptr); + static const struct { const EGLint attrib; const char* name; } kAttribs[] = { + { EGL_BUFFER_SIZE, "EGL_BUFFER_SIZE" }, + { EGL_ALPHA_SIZE, "EGL_ALPHA_SIZE" }, + { EGL_BLUE_SIZE, "EGL_BLUE_SIZE" }, + { EGL_GREEN_SIZE, "EGL_GREEN_SIZE" }, + { EGL_RED_SIZE, "EGL_RED_SIZE" }, + { EGL_DEPTH_SIZE, "EGL_DEPTH_SIZE" }, + { EGL_STENCIL_SIZE, "EGL_STENCIL_SIZE" }, + { EGL_CONFIG_CAVEAT, "EGL_CONFIG_CAVEAT" }, + { EGL_CONFIG_ID, "EGL_CONFIG_ID" }, + { EGL_LEVEL, "EGL_LEVEL" }, + { EGL_MAX_PBUFFER_HEIGHT, "EGL_MAX_PBUFFER_HEIGHT" }, + { EGL_MAX_PBUFFER_PIXELS, "EGL_MAX_PBUFFER_PIXELS" }, + { EGL_MAX_PBUFFER_WIDTH, "EGL_MAX_PBUFFER_WIDTH" }, + { EGL_NATIVE_RENDERABLE, "EGL_NATIVE_RENDERABLE" }, + { EGL_NATIVE_VISUAL_ID, "EGL_NATIVE_VISUAL_ID" }, + { EGL_NATIVE_VISUAL_TYPE, "EGL_NATIVE_VISUAL_TYPE" }, + { EGL_SAMPLES, "EGL_SAMPLES" }, + { EGL_SAMPLE_BUFFERS, "EGL_SAMPLE_BUFFERS" }, + { EGL_SURFACE_TYPE, "EGL_SURFACE_TYPE" }, + { EGL_TRANSPARENT_TYPE, "EGL_TRANSPARENT_TYPE" }, + { EGL_TRANSPARENT_BLUE_VALUE, "EGL_TRANSPARENT_BLUE_VALUE" }, + { EGL_TRANSPARENT_GREEN_VALUE, "EGL_TRANSPARENT_GREEN_VALUE" }, + { EGL_TRANSPARENT_RED_VALUE, "EGL_TRANSPARENT_RED_VALUE" }, + { EGL_BIND_TO_TEXTURE_RGB, "EGL_BIND_TO_TEXTURE_RGB" }, + { EGL_BIND_TO_TEXTURE_RGBA, "EGL_BIND_TO_TEXTURE_RGBA" }, + { EGL_MIN_SWAP_INTERVAL, "EGL_MIN_SWAP_INTERVAL" }, + { EGL_MAX_SWAP_INTERVAL, "EGL_MAX_SWAP_INTERVAL" }, + { -1, NULL } + }; + const char* string = eglQueryString(display, EGL_VENDOR); + LOG("EGL vendor: %s", string); + string = eglQueryString(display, EGL_VERSION); + LOG("EGL version: %s", string); + string = eglQueryString(display, EGL_EXTENSIONS); + LOG("EGL extensions: %s", string); + LOG("EGL configuration attibutes:"); + for (int index = 0; kAttribs[index].attrib != -1; index++) { + EGLint value; + if (eglGetConfigAttrib(display, config, kAttribs[index].attrib, &value)) + LOG(" %s: %d", kAttribs[index].name, static_cast<int>(value)); + } +} +#endif + + +const QEvent::Type OrientationChangeEvent::mType = + static_cast<QEvent::Type>(QEvent::registerEventType()); + +static const MirDisplayOutput *find_active_output( + const MirDisplayConfiguration *conf) +{ + const MirDisplayOutput *output = NULL; + for (uint32_t d = 0; d < conf->num_outputs; d++) + { + const MirDisplayOutput *out = conf->outputs + d; + + if (out->used && + out->connected && + out->num_modes && + out->current_mode < out->num_modes) + { + output = out; + break; + } + } + + return output; +} + +QMirClientScreen::QMirClientScreen(MirConnection *connection) + : mFormat(QImage::Format_RGB32) + , mDepth(32) + , mSurfaceFormat() + , mEglDisplay(EGL_NO_DISPLAY) + , mEglConfig(nullptr) +{ + // Initialize EGL. + ASSERT(eglBindAPI(EGL_OPENGL_ES_API) == EGL_TRUE); + + mEglNativeDisplay = mir_connection_get_egl_native_display(connection); + ASSERT((mEglDisplay = eglGetDisplay(mEglNativeDisplay)) != EGL_NO_DISPLAY); + ASSERT(eglInitialize(mEglDisplay, nullptr, nullptr) == EGL_TRUE); + + // Configure EGL buffers format. + mSurfaceFormat.setRedBufferSize(8); + mSurfaceFormat.setGreenBufferSize(8); + mSurfaceFormat.setBlueBufferSize(8); + mSurfaceFormat.setAlphaBufferSize(8); + mSurfaceFormat.setDepthBufferSize(24); + mSurfaceFormat.setStencilBufferSize(8); + if (!qEnvironmentVariableIsEmpty("QTUBUNTU_MULTISAMPLE")) { + mSurfaceFormat.setSamples(4); + DLOG("ubuntumirclient: setting MSAA to 4 samples"); + } +#ifdef QTUBUNTU_USE_OPENGL + mSurfaceFormat.setRenderableType(QSurfaceFormat::OpenGL); +#else + mSurfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES); +#endif + mEglConfig = q_configFromGLFormat(mEglDisplay, mSurfaceFormat, true); + + #if !defined(QT_NO_DEBUG) + printEglConfig(mEglDisplay, mEglConfig); + #endif + + // Set vblank swap interval. + int swapInterval = kSwapInterval; + QByteArray swapIntervalString = qgetenv("QTUBUNTU_SWAPINTERVAL"); + if (!swapIntervalString.isEmpty()) { + bool ok; + swapInterval = swapIntervalString.toInt(&ok); + if (!ok) + swapInterval = kSwapInterval; + } + DLOG("ubuntumirclient: setting swap interval to %d", swapInterval); + eglSwapInterval(mEglDisplay, swapInterval); + + // Get screen resolution. + auto configDeleter = [](MirDisplayConfiguration *config) { mir_display_config_destroy(config); }; + using configUp = std::unique_ptr<MirDisplayConfiguration, decltype(configDeleter)>; + configUp displayConfig(mir_connection_create_display_config(connection), configDeleter); + ASSERT(displayConfig != nullptr); + + auto const displayOutput = find_active_output(displayConfig.get()); + ASSERT(displayOutput != nullptr); + + const MirDisplayMode *mode = &displayOutput->modes[displayOutput->current_mode]; + const int kScreenWidth = mode->horizontal_resolution; + const int kScreenHeight = mode->vertical_resolution; + DASSERT(kScreenWidth > 0 && kScreenHeight > 0); + + DLOG("ubuntumirclient: screen resolution: %dx%d", kScreenWidth, kScreenHeight); + + mGeometry = QRect(0, 0, kScreenWidth, kScreenHeight); + + DLOG("QQMirClientScreen::QQMirClientScreen (this=%p)", this); + + // Set the default orientation based on the initial screen dimmensions. + mNativeOrientation = (mGeometry.width() >= mGeometry.height()) ? Qt::LandscapeOrientation : Qt::PortraitOrientation; + + // If it's a landscape device (i.e. some tablets), start in landscape, otherwise portrait + mCurrentOrientation = (mNativeOrientation == Qt::LandscapeOrientation) ? Qt::LandscapeOrientation : Qt::PortraitOrientation; +} + +QMirClientScreen::~QMirClientScreen() +{ + eglTerminate(mEglDisplay); +} + +void QMirClientScreen::customEvent(QEvent* event) { + DASSERT(QThread::currentThread() == thread()); + + OrientationChangeEvent* oReadingEvent = static_cast<OrientationChangeEvent*>(event); + switch (oReadingEvent->mOrientation) { + case OrientationChangeEvent::LeftUp: { + mCurrentOrientation = (screen()->primaryOrientation() == Qt::LandscapeOrientation) ? + Qt::InvertedPortraitOrientation : Qt::LandscapeOrientation; + break; + } + case OrientationChangeEvent::TopUp: { + mCurrentOrientation = (screen()->primaryOrientation() == Qt::LandscapeOrientation) ? + Qt::LandscapeOrientation : Qt::PortraitOrientation; + break; + } + case OrientationChangeEvent::RightUp: { + mCurrentOrientation = (screen()->primaryOrientation() == Qt::LandscapeOrientation) ? + Qt::PortraitOrientation : Qt::InvertedLandscapeOrientation; + break; + } + case OrientationChangeEvent::TopDown: { + mCurrentOrientation = (screen()->primaryOrientation() == Qt::LandscapeOrientation) ? + Qt::InvertedLandscapeOrientation : Qt::InvertedPortraitOrientation; + break; + } + default: { + DLOG("QMirClientScreen::customEvent - Unknown orientation."); + return; + } + } + + // Raise the event signal so that client apps know the orientation changed + DLOG("QMirClientScreen::customEvent - handling orientation change to %s", orientationToStr(mCurrentOrientation)); + QWindowSystemInterface::handleScreenOrientationChange(screen(), mCurrentOrientation); +} + +void QMirClientScreen::handleWindowSurfaceResize(int windowWidth, int windowHeight) +{ + if ((windowWidth > windowHeight && mGeometry.width() < mGeometry.height()) + || (windowWidth < windowHeight && mGeometry.width() > mGeometry.height())) { + + // The window aspect ratio differ's from the screen one. This means that + // unity8 has rotated the window in its scene. + // As there's no way to express window rotation in Qt's API, we have + // Flip QScreen's dimensions so that orientation properties match + // (primaryOrientation particularly). + // FIXME: This assumes a phone scenario. Won't work, or make sense, + // on the desktop + + QRect currGeometry = mGeometry; + mGeometry.setWidth(currGeometry.height()); + mGeometry.setHeight(currGeometry.width()); + + DLOG("QMirClientScreen::handleWindowSurfaceResize - new screen geometry (w=%d, h=%d)", + mGeometry.width(), mGeometry.height()); + QWindowSystemInterface::handleScreenGeometryChange(screen(), + mGeometry /* newGeometry */, + mGeometry /* newAvailableGeometry */); + + if (mGeometry.width() < mGeometry.height()) { + mCurrentOrientation = Qt::PortraitOrientation; + } else { + mCurrentOrientation = Qt::LandscapeOrientation; + } + DLOG("QMirClientScreen::handleWindowSurfaceResize - new orientation %s",orientationToStr(mCurrentOrientation)); + QWindowSystemInterface::handleScreenOrientationChange(screen(), mCurrentOrientation); + } +} diff --git a/src/plugins/platforms/mirclient/qmirclientscreen.h b/src/plugins/platforms/mirclient/qmirclientscreen.h new file mode 100644 index 0000000000..5d9325354f --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientscreen.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMIRCLIENTSCREEN_H +#define QMIRCLIENTSCREEN_H + +#include <qpa/qplatformscreen.h> +#include <QSurfaceFormat> +#include <EGL/egl.h> + +struct MirConnection; + +class QMirClientScreen : public QObject, public QPlatformScreen +{ + Q_OBJECT +public: + QMirClientScreen(MirConnection *connection); + virtual ~QMirClientScreen(); + + // QPlatformScreen methods. + QImage::Format format() const override { return mFormat; } + int depth() const override { return mDepth; } + QRect geometry() const override { return mGeometry; } + QRect availableGeometry() const override { return mGeometry; } + Qt::ScreenOrientation nativeOrientation() const override { return mNativeOrientation; } + Qt::ScreenOrientation orientation() const override { return mNativeOrientation; } + + // New methods. + QSurfaceFormat surfaceFormat() const { return mSurfaceFormat; } + EGLDisplay eglDisplay() const { return mEglDisplay; } + EGLConfig eglConfig() const { return mEglConfig; } + EGLNativeDisplayType eglNativeDisplay() const { return mEglNativeDisplay; } + void handleWindowSurfaceResize(int width, int height); + + // QObject methods. + void customEvent(QEvent* event); + +private: + QRect mGeometry; + Qt::ScreenOrientation mNativeOrientation; + Qt::ScreenOrientation mCurrentOrientation; + QImage::Format mFormat; + int mDepth; + QSurfaceFormat mSurfaceFormat; + EGLDisplay mEglDisplay; + EGLConfig mEglConfig; + EGLNativeDisplayType mEglNativeDisplay; +}; + +#endif // QMIRCLIENTSCREEN_H diff --git a/src/plugins/platforms/mirclient/qmirclienttheme.cpp b/src/plugins/platforms/mirclient/qmirclienttheme.cpp new file mode 100644 index 0000000000..c15da23945 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclienttheme.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qmirclienttheme.h" + +#include <QtCore/QVariant> + +const char *QMirClientTheme::name = "ubuntu"; + +QMirClientTheme::QMirClientTheme() +{ +} + +QMirClientTheme::~QMirClientTheme() +{ +} + +QVariant QMirClientTheme::themeHint(ThemeHint hint) const +{ + if (hint == QPlatformTheme::SystemIconThemeName) { + QByteArray iconTheme = qgetenv("QTUBUNTU_ICON_THEME"); + if (iconTheme.isEmpty()) { + return QVariant(QStringLiteral("ubuntu-mobile")); + } else { + return QVariant(QString(iconTheme)); + } + } else { + return QGenericUnixTheme::themeHint(hint); + } +} diff --git a/src/plugins/platforms/mirclient/qmirclienttheme.h b/src/plugins/platforms/mirclient/qmirclienttheme.h new file mode 100644 index 0000000000..8f330395a0 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclienttheme.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMIRCLIENTTHEME_H +#define QMIRCLIENTTHEME_H + +#include <QtPlatformSupport/private/qgenericunixthemes_p.h> + +class QMirClientTheme : public QGenericUnixTheme +{ +public: + static const char* name; + QMirClientTheme(); + virtual ~QMirClientTheme(); + + // From QPlatformTheme + QVariant themeHint(ThemeHint hint) const override; +}; + +#endif // QMIRCLIENTTHEME_H diff --git a/src/plugins/platforms/mirclient/qmirclientwindow.cpp b/src/plugins/platforms/mirclient/qmirclientwindow.cpp new file mode 100644 index 0000000000..f3fd1e756d --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientwindow.cpp @@ -0,0 +1,452 @@ +/**************************************************************************** +** +** Copyright (C) 2014-2015 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +// Local +#include "qmirclientclipboard.h" +#include "qmirclientinput.h" +#include "qmirclientwindow.h" +#include "qmirclientscreen.h" +#include "qmirclientlogging.h" + +// Qt +#include <qpa/qwindowsysteminterface.h> +#include <qpa/qwindowsysteminterface.h> +#include <QMutex> +#include <QMutexLocker> +#include <QSize> +#include <QtMath> + +// Platform API +#include <ubuntu/application/instance.h> + +#include <EGL/egl.h> + +#define IS_OPAQUE_FLAG 1 + +namespace +{ +MirSurfaceState qtWindowStateToMirSurfaceState(Qt::WindowState state) +{ + switch (state) { + case Qt::WindowNoState: + return mir_surface_state_restored; + + case Qt::WindowFullScreen: + return mir_surface_state_fullscreen; + + case Qt::WindowMaximized: + return mir_surface_state_maximized; + + case Qt::WindowMinimized: + return mir_surface_state_minimized; + + default: + LOG("Unexpected Qt::WindowState: %d", state); + return mir_surface_state_restored; + } +} + +#if !defined(QT_NO_DEBUG) +const char *qtWindowStateToStr(Qt::WindowState state) +{ + switch (state) { + case Qt::WindowNoState: + return "NoState"; + + case Qt::WindowFullScreen: + return "FullScreen"; + + case Qt::WindowMaximized: + return "Maximized"; + + case Qt::WindowMinimized: + return "Minimized"; + + default: + return "!?"; + } +} +#endif + +} // anonymous namespace + +class QMirClientWindowPrivate +{ +public: + void createEGLSurface(EGLNativeWindowType nativeWindow); + void destroyEGLSurface(); + int panelHeight(); + + QMirClientScreen* screen; + EGLSurface eglSurface; + WId id; + QMirClientInput* input; + Qt::WindowState state; + MirConnection *connection; + MirSurface* surface; + QSize bufferSize; + QMutex mutex; + QSharedPointer<QMirClientClipboard> clipboard; +}; + +static void eventCallback(MirSurface* surface, const MirEvent *event, void* context) +{ + (void) surface; + DASSERT(context != NULL); + QMirClientWindow* platformWindow = static_cast<QMirClientWindow*>(context); + platformWindow->priv()->input->postEvent(platformWindow, event); +} + +static void surfaceCreateCallback(MirSurface* surface, void* context) +{ + DASSERT(context != NULL); + QMirClientWindow* platformWindow = static_cast<QMirClientWindow*>(context); + platformWindow->priv()->surface = surface; + + mir_surface_set_event_handler(surface, eventCallback, context); +} + +QMirClientWindow::QMirClientWindow(QWindow* w, QSharedPointer<QMirClientClipboard> clipboard, QMirClientScreen* screen, + QMirClientInput* input, MirConnection* connection) + : QObject(nullptr), QPlatformWindow(w) +{ + DASSERT(screen != NULL); + + d = new QMirClientWindowPrivate; + d->screen = screen; + d->eglSurface = EGL_NO_SURFACE; + d->input = input; + d->state = window()->windowState(); + d->connection = connection; + d->clipboard = clipboard; + + static int id = 1; + d->id = id++; + + // Use client geometry if set explicitly, use available screen geometry otherwise. + QPlatformWindow::setGeometry(window()->geometry() != screen->geometry() ? + window()->geometry() : screen->availableGeometry()); + createWindow(); + DLOG("QMirClientWindow::QMirClientWindow (this=%p, w=%p, screen=%p, input=%p)", this, w, screen, input); +} + +QMirClientWindow::~QMirClientWindow() +{ + DLOG("QMirClientWindow::~QMirClientWindow"); + d->destroyEGLSurface(); + + mir_surface_release_sync(d->surface); + + delete d; +} + +void QMirClientWindowPrivate::createEGLSurface(EGLNativeWindowType nativeWindow) +{ + DLOG("QMirClientWindowPrivate::createEGLSurface (this=%p, nativeWindow=%p)", + this, reinterpret_cast<void*>(nativeWindow)); + + eglSurface = eglCreateWindowSurface(screen->eglDisplay(), screen->eglConfig(), + nativeWindow, nullptr); + + DASSERT(eglSurface != EGL_NO_SURFACE); +} + +void QMirClientWindowPrivate::destroyEGLSurface() +{ + DLOG("QMirClientWindowPrivate::destroyEGLSurface (this=%p)", this); + if (eglSurface != EGL_NO_SURFACE) { + eglDestroySurface(screen->eglDisplay(), eglSurface); + eglSurface = EGL_NO_SURFACE; + } +} + +// FIXME - in order to work around https://bugs.launchpad.net/mir/+bug/1346633 +// we need to guess the panel height (3GU + 2DP) +int QMirClientWindowPrivate::panelHeight() +{ + const int defaultGridUnit = 8; + int gridUnit = defaultGridUnit; + QByteArray gridUnitString = qgetenv("GRID_UNIT_PX"); + if (!gridUnitString.isEmpty()) { + bool ok; + gridUnit = gridUnitString.toInt(&ok); + if (!ok) { + gridUnit = defaultGridUnit; + } + } + qreal densityPixelRatio = static_cast<qreal>(gridUnit) / defaultGridUnit; + return gridUnit * 3 + qFloor(densityPixelRatio) * 2; +} + +namespace +{ +static MirPixelFormat +mir_choose_default_pixel_format(MirConnection *connection) +{ + MirPixelFormat format[mir_pixel_formats]; + unsigned int nformats; + + mir_connection_get_available_surface_formats(connection, + format, mir_pixel_formats, &nformats); + + return format[0]; +} +} + +void QMirClientWindow::createWindow() +{ + DLOG("QMirClientWindow::createWindow (this=%p)", this); + + // FIXME: remove this remnant of an old platform-api enum - needs ubuntu-keyboard update + const int SCREEN_KEYBOARD_ROLE = 7; + // Get surface role and flags. + QVariant roleVariant = window()->property("role"); + int role = roleVariant.isValid() ? roleVariant.toUInt() : 1; // 1 is the default role for apps. + QVariant opaqueVariant = window()->property("opaque"); + uint flags = opaqueVariant.isValid() ? + opaqueVariant.toUInt() ? static_cast<uint>(IS_OPAQUE_FLAG) : 0 : 0; + + // FIXME(loicm) Opaque flag is forced for now for non-system sessions (applications) for + // performance reasons. + flags |= static_cast<uint>(IS_OPAQUE_FLAG); + + const QByteArray title = (!window()->title().isNull()) ? window()->title().toUtf8() : "Window 1"; // legacy title + const int panelHeight = d->panelHeight(); + +#if !defined(QT_NO_DEBUG) + LOG("panelHeight: '%d'", panelHeight); + LOG("role: '%d'", role); + LOG("flags: '%s'", (flags & static_cast<uint>(1)) ? "Opaque" : "NotOpaque"); + LOG("title: '%s'", title.constData()); +#endif + + // Get surface geometry. + QRect geometry; + if (d->state == Qt::WindowFullScreen) { + printf("QMirClientWindow - fullscreen geometry\n"); + geometry = screen()->geometry(); + } else if (d->state == Qt::WindowMaximized) { + printf("QMirClientWindow - maximized geometry\n"); + geometry = screen()->availableGeometry(); + /* + * FIXME: Autopilot relies on being able to convert coordinates relative of the window + * into absolute screen coordinates. Mir does not allow this, see bug lp:1346633 + * Until there's a correct way to perform this transformation agreed, this horrible hack + * guesses the transformation heuristically. + * + * Assumption: this method only used on phone devices! + */ + geometry.setY(panelHeight); + } else { + printf("QMirClientWindow - regular geometry\n"); + geometry = this->geometry(); + geometry.setY(panelHeight); + } + + DLOG("[ubuntumirclient QPA] creating surface at (%d, %d) with size (%d, %d) with title '%s'\n", + geometry.x(), geometry.y(), geometry.width(), geometry.height(), title.data()); + + MirSurfaceSpec *spec; + if (role == SCREEN_KEYBOARD_ROLE) + { + spec = mir_connection_create_spec_for_input_method(d->connection, geometry.width(), + geometry.height(), mir_choose_default_pixel_format(d->connection)); + } + else + { + spec = mir_connection_create_spec_for_normal_surface(d->connection, geometry.width(), + geometry.height(), mir_choose_default_pixel_format(d->connection)); + } + mir_surface_spec_set_name(spec, title.data()); + + // Create platform window + mir_wait_for(mir_surface_create(spec, surfaceCreateCallback, this)); + mir_surface_spec_release(spec); + + DASSERT(d->surface != NULL); + d->createEGLSurface((EGLNativeWindowType)mir_buffer_stream_get_egl_native_window(mir_surface_get_buffer_stream(d->surface))); + + if (d->state == Qt::WindowFullScreen) { + // TODO: We could set this on creation once surface spec supports it (mps already up) + mir_wait_for(mir_surface_set_state(d->surface, mir_surface_state_fullscreen)); + } + + // Window manager can give us a final size different from what we asked for + // so let's check what we ended up getting + { + MirSurfaceParameters parameters; + mir_surface_get_parameters(d->surface, ¶meters); + + geometry.setWidth(parameters.width); + geometry.setHeight(parameters.height); + } + + DLOG("[ubuntumirclient QPA] created surface has size (%d, %d)", + geometry.width(), geometry.height()); + + // Assume that the buffer size matches the surface size at creation time + d->bufferSize = geometry.size(); + + // Tell Qt about the geometry. + QWindowSystemInterface::handleGeometryChange(window(), geometry); + QPlatformWindow::setGeometry(geometry); +} + +void QMirClientWindow::moveResize(const QRect& rect) +{ + (void) rect; + // TODO: Not yet supported by mir. +} + +void QMirClientWindow::handleSurfaceResize(int width, int height) +{ + QMutexLocker(&d->mutex); + LOG("QMirClientWindow::handleSurfaceResize(width=%d, height=%d)", width, height); + + // The current buffer size hasn't actually changed. so just render on it and swap + // buffers in the hope that the next buffer will match the surface size advertised + // in this event. + // But since this event is processed by a thread different from the one that swaps + // buffers, you can never know if this information is already outdated as there's + // no synchronicity whatsoever between the processing of resize events and the + // consumption of buffers. + if (d->bufferSize.width() != width || d->bufferSize.height() != height) { + QWindowSystemInterface::handleExposeEvent(window(), geometry()); + QWindowSystemInterface::flushWindowSystemEvents(); + } +} + +void QMirClientWindow::handleSurfaceFocusChange(bool focused) +{ + LOG("QMirClientWindow::handleSurfaceFocusChange(focused=%s)", focused ? "true" : "false"); + QWindow *activatedWindow = focused ? window() : nullptr; + + // System clipboard contents might have changed while this window was unfocused and wihtout + // this process getting notified about it because it might have been suspended (due to + // application lifecycle policies), thus unable to listen to any changes notified through + // D-Bus. + // Therefore let's ensure we are up to date with the system clipboard now that we are getting + // focused again. + if (focused) { + d->clipboard->requestDBusClipboardContents(); + } + + QWindowSystemInterface::handleWindowActivated(activatedWindow, Qt::ActiveWindowFocusReason); +} + +void QMirClientWindow::setWindowState(Qt::WindowState state) +{ + QMutexLocker(&d->mutex); + DLOG("QMirClientWindow::setWindowState (this=%p, %s)", this, qtWindowStateToStr(state)); + + if (state == d->state) + return; + + // TODO: Perhaps we should check if the states are applied? + mir_wait_for(mir_surface_set_state(d->surface, qtWindowStateToMirSurfaceState(state))); + d->state = state; +} + +void QMirClientWindow::setGeometry(const QRect& rect) +{ + DLOG("QMirClientWindow::setGeometry (this=%p)", this); + + bool doMoveResize; + + { + QMutexLocker(&d->mutex); + QPlatformWindow::setGeometry(rect); + doMoveResize = d->state != Qt::WindowFullScreen && d->state != Qt::WindowMaximized; + } + + if (doMoveResize) { + moveResize(rect); + } +} + +void QMirClientWindow::setVisible(bool visible) +{ + QMutexLocker(&d->mutex); + DLOG("QMirClientWindow::setVisible (this=%p, visible=%s)", this, visible ? "true" : "false"); + + if (visible) { + mir_wait_for(mir_surface_set_state(d->surface, qtWindowStateToMirSurfaceState(d->state))); + + QWindowSystemInterface::handleExposeEvent(window(), QRect()); + QWindowSystemInterface::flushWindowSystemEvents(); + } else { + // TODO: Use the new mir_surface_state_hidden state instead of mir_surface_state_minimized. + // Will have to change qtmir and unity8 for that. + mir_wait_for(mir_surface_set_state(d->surface, mir_surface_state_minimized)); + } +} + +void* QMirClientWindow::eglSurface() const +{ + return d->eglSurface; +} + +WId QMirClientWindow::winId() const +{ + return d->id; +} + +void QMirClientWindow::onBuffersSwapped_threadSafe(int newBufferWidth, int newBufferHeight) +{ + QMutexLocker(&d->mutex); + + bool sizeKnown = newBufferWidth > 0 && newBufferHeight > 0; + + if (sizeKnown && (d->bufferSize.width() != newBufferWidth || + d->bufferSize.height() != newBufferHeight)) { + + DLOG("QMirClientWindow::onBuffersSwapped_threadSafe - buffer size changed from (%d,%d) to (%d,%d)", + d->bufferSize.width(), d->bufferSize.height(), newBufferWidth, newBufferHeight); + + d->bufferSize.rwidth() = newBufferWidth; + d->bufferSize.rheight() = newBufferHeight; + + QRect newGeometry; + + newGeometry = geometry(); + newGeometry.setWidth(d->bufferSize.width()); + newGeometry.setHeight(d->bufferSize.height()); + + QPlatformWindow::setGeometry(newGeometry); + QWindowSystemInterface::handleGeometryChange(window(), newGeometry, QRect()); + } +} diff --git a/src/plugins/platforms/mirclient/qmirclientwindow.h b/src/plugins/platforms/mirclient/qmirclientwindow.h new file mode 100644 index 0000000000..f342669544 --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientwindow.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2014-2015 Canonical, Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef QMIRCLIENTWINDOW_H +#define QMIRCLIENTWINDOW_H + +#include <qpa/qplatformwindow.h> +#include <QSharedPointer> + +#include <mir_toolkit/mir_client_library.h> + +class QMirClientClipboard; +class QMirClientInput; +class QMirClientScreen; +class QMirClientWindowPrivate; + +class QMirClientWindow : public QObject, public QPlatformWindow +{ + Q_OBJECT +public: + QMirClientWindow(QWindow *w, QSharedPointer<QMirClientClipboard> clipboard, QMirClientScreen *screen, + QMirClientInput *input, MirConnection *mir_connection); + virtual ~QMirClientWindow(); + + // QPlatformWindow methods. + WId winId() const override; + void setGeometry(const QRect&) override; + void setWindowState(Qt::WindowState state) override; + void setVisible(bool visible) override; + + // New methods. + void* eglSurface() const; + void handleSurfaceResize(int width, int height); + void handleSurfaceFocusChange(bool focused); + void onBuffersSwapped_threadSafe(int newBufferWidth, int newBufferHeight); + + QMirClientWindowPrivate* priv() { return d; } + +private: + void createWindow(); + void moveResize(const QRect& rect); + + QMirClientWindowPrivate *d; +}; + +#endif // QMIRCLIENTWINDOW_H diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro index 22d443733e..43bb04e318 100644 --- a/src/plugins/platforms/platforms.pro +++ b/src/plugins/platforms/platforms.pro @@ -40,3 +40,5 @@ contains(QT_CONFIG, linuxfb): SUBDIRS += linuxfb haiku { SUBDIRS += haiku } + +contains(QT_CONFIG, mirclient): SUBDIRS += mirclient diff --git a/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.cpp b/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.cpp index e5c853dad8..04e264860e 100644 --- a/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.cpp +++ b/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.cpp @@ -124,4 +124,25 @@ void QQnxAbstractVirtualKeyboard::setLocale(const QLocale &locale) emit localeChanged(locale); } +QQnxAbstractVirtualKeyboard::EnterKeyType + QQnxAbstractVirtualKeyboard::qtEnterKeyTypeToQnx(Qt::EnterKeyType type) +{ + switch (type) { + case Qt::EnterKeyDone: + return Done; + case Qt::EnterKeyGo: + return Go; + case Qt::EnterKeyNext: + return Next; + case Qt::EnterKeySearch: + return Search; + case Qt::EnterKeySend: + return Send; + case Qt::EnterKeyDefault: + case Qt::EnterKeyReturn: + case Qt::EnterKeyPrevious: // unsupported + return DefaultReturn; + } +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.h b/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.h index 8bf8313000..2fa2ed7291 100644 --- a/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.h +++ b/src/plugins/platforms/qnx/qqnxabstractvirtualkeyboard.h @@ -74,6 +74,8 @@ public: KeyboardMode keyboardMode() const { return m_keyboardMode; } EnterKeyType enterKeyType() const { return m_enterKeyType; } + static EnterKeyType qtEnterKeyTypeToQnx(Qt::EnterKeyType type); + Q_SIGNALS: void heightChanged(int height); void visibilityChanged(bool visible); diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp b/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp index 3506de4bc0..ed0db82685 100644 --- a/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp +++ b/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp @@ -1384,13 +1384,17 @@ void QQnxInputContext::setFocusObject(QObject *object) if (hasSession()) dispatchFocusLossEvent(); } else { - QInputMethodQueryEvent query(Qt::ImHints); + QInputMethodQueryEvent query(Qt::ImHints | Qt::ImEnterKeyType); QCoreApplication::sendEvent(object, &query); int inputHints = query.value(Qt::ImHints).toInt(); + Qt::EnterKeyType qtEnterKeyType = Qt::EnterKeyType(query.value(Qt::ImEnterKeyType).toInt()); dispatchFocusGainEvent(inputHints); m_virtualKeyboard.setInputHints(inputHints); + m_virtualKeyboard.setEnterKeyType( + QQnxAbstractVirtualKeyboard::qtEnterKeyTypeToQnx(qtEnterKeyType) + ); if (!m_inputPanelVisible) showInputPanel(); diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp index 91ecffa2aa..3860cdf0db 100644 --- a/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp +++ b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp @@ -172,11 +172,15 @@ void QQnxInputContext::setFocusObject(QObject *object) if (m_inputPanelVisible) hideInputPanel(); } else { - QInputMethodQueryEvent query(Qt::ImHints); + QInputMethodQueryEvent query(Qt::ImHints | Qt::ImEnterKeyType); QCoreApplication::sendEvent(object, &query); int inputHints = query.value(Qt::ImHints).toInt(); + Qt::EnterKeyType qtEnterKeyType = Qt::EnterKeyType(query.value(Qt::ImEnterKeyType).toInt()); m_virtualKeyboard.setInputHints(inputHints); + m_virtualKeyboard.setEnterKeyType( + QQnxAbstractVirtualKeyboard::qtEnterKeyTypeToQnx(qtEnterKeyType) + ); if (!m_inputPanelVisible) showInputPanel(); diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp index 071bab7920..1c825dbbdd 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.cpp +++ b/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -95,7 +95,6 @@ #include <private/qsimpledrag_p.h> #include <QtCore/QDebug> -#include <QtCore/QHash> #include <errno.h> diff --git a/src/plugins/platforms/windows/openglblacklists/default.json b/src/plugins/platforms/windows/openglblacklists/default.json index 23607523bd..b00c9df408 100644 --- a/src/plugins/platforms/windows/openglblacklists/default.json +++ b/src/plugins/platforms/windows/openglblacklists/default.json @@ -17,6 +17,31 @@ "features": [ "disable_desktopgl" ] - } + }, + { + "id": 2, + "description": "Intel Q965/Q963 - GMA 3000 has insufficient support of opengl and directx", + "vendor_id": "0x8086", + "device_id": [ "0x2992" ], + "os": { + "type": "win" + }, + "features": [ + "disable_desktopgl", + "disable_angle" + ] + }, + { + "id": 3, + "description": "No OpenGL on Intel G33/G31 (QTBUG-47522)", + "vendor_id": "0x8086", + "device_id": [ "0x29C2" ], + "os": { + "type": "win" + }, + "features": [ + "disable_desktopgl" + ] + } ] } diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp index 16c278d9df..3f19e4401a 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -35,10 +35,10 @@ #include "qwindowswindow.h" #include "qwindowsnativeimage.h" #include "qwindowscontext.h" -#include "qwindowsscaling.h" #include <QtGui/QWindow> #include <QtGui/QPainter> +#include <private/qhighdpiscaling_p.h> #include <QtCore/QDebug> @@ -68,10 +68,12 @@ QPaintDevice *QWindowsBackingStore::paintDevice() return &m_image->image(); } -void QWindowsBackingStore::flushDp(QWindow *window, const QRect &br, const QPoint &offset) +void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, + const QPoint &offset) { Q_ASSERT(window); + const QRect br = region.boundingRect(); if (QWindowsContext::verbose > 1) qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << window << offset << br; QWindowsWindow *rw = QWindowsWindow::baseWindowOf(window); @@ -81,9 +83,8 @@ void QWindowsBackingStore::flushDp(QWindow *window, const QRect &br, const QPoin const Qt::WindowFlags flags = window->flags(); if ((flags & Qt::FramelessWindowHint) && QWindowsWindow::setWindowLayered(rw->handle(), flags, hasAlpha, rw->opacity()) && hasAlpha) { // Windows with alpha: Use blend function to update. - const QMargins marginsDP = rw->frameMarginsDp(); - const QRect r = rw->geometryDp() + marginsDP; - const QPoint frameOffset(marginsDP.left(), marginsDP.top()); + QRect r = QHighDpi::toNativePixels(window->frameGeometry(), window); + QPoint frameOffset(QHighDpi::toNativePixels(QPoint(window->frameMargins().left(), window->frameMargins().top()), window)); QRect dirtyRect = br.translated(offset + frameOffset); SIZE size = {r.width(), r.height()}; @@ -127,15 +128,14 @@ void QWindowsBackingStore::flushDp(QWindow *window, const QRect &br, const QPoin } } -void QWindowsBackingStore::resize(const QSize &sizeDip, const QRegion ®ionDip) +void QWindowsBackingStore::resize(const QSize &size, const QRegion ®ion) { - const QSize size = sizeDip * QWindowsScaling::factor(); if (m_image.isNull() || m_image->image().size() != size) { #ifndef QT_NO_DEBUG_OUTPUT if (QWindowsContext::verbose && lcQpaBackingStore().isDebugEnabled()) { qCDebug(lcQpaBackingStore) - << __FUNCTION__ << ' ' << window() << ' ' << size << ' ' << sizeDip << ' ' - << regionDip << " from: " << (m_image.isNull() ? QSize() : m_image->image().size()); + << __FUNCTION__ << ' ' << window() << ' ' << size << ' ' << region + << " from: " << (m_image.isNull() ? QSize() : m_image->image().size()); } #endif const QImage::Format format = window()->format().hasAlpha() ? @@ -144,10 +144,10 @@ void QWindowsBackingStore::resize(const QSize &sizeDip, const QRegion ®ionDip QWindowsNativeImage *oldwni = m_image.data(); QWindowsNativeImage *newwni = new QWindowsNativeImage(size.width(), size.height(), format); - if (oldwni && !regionDip.isEmpty()) { + if (oldwni && !region.isEmpty()) { const QImage &oldimg(oldwni->image()); QImage &newimg(newwni->image()); - QRegion staticRegion = QWindowsScaling::mapToNative(regionDip); + QRegion staticRegion(region); staticRegion &= QRect(0, 0, oldimg.width(), oldimg.height()); staticRegion &= QRect(0, 0, newimg.width(), newimg.height()); QPainter painter(&newimg); @@ -156,38 +156,36 @@ void QWindowsBackingStore::resize(const QSize &sizeDip, const QRegion ®ionDip painter.drawImage(rect, oldimg, rect); } - if (QWindowsScaling::isActive()) - newwni->setDevicePixelRatio(QWindowsScaling::factor()); m_image.reset(newwni); } } Q_GUI_EXPORT void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset); -bool QWindowsBackingStore::scroll(const QRegion &areaDip, int dxDip, int dyDip) +bool QWindowsBackingStore::scroll(const QRegion &area, int dx, int dy) { if (m_image.isNull() || m_image->image().isNull()) return false; - const QPoint dp = QPoint(dxDip, dyDip) * QWindowsScaling::factor(); - const QVector<QRect> rects = areaDip.rects(); + const QVector<QRect> rects = area.rects(); + const QPoint offset(dx, dy); for (int i = 0; i < rects.size(); ++i) - qt_scrollRectInImage(m_image->image(), QWindowsScaling::mapToNative(rects.at(i)), dp); + qt_scrollRectInImage(m_image->image(), rects.at(i), offset); return true; } -void QWindowsBackingStore::beginPaint(const QRegion ®ionDip) +void QWindowsBackingStore::beginPaint(const QRegion ®ion) { if (QWindowsContext::verbose > 1) - qCDebug(lcQpaBackingStore) <<__FUNCTION__ << regionDip; + qCDebug(lcQpaBackingStore) <<__FUNCTION__ << region; if (m_image->image().hasAlphaChannel()) { QPainter p(&m_image->image()); p.setCompositionMode(QPainter::CompositionMode_Source); const QColor blank = Qt::transparent; - foreach (const QRect &r, regionDip.rects()) - p.fillRect(QWindowsScaling::mapToNative(r), blank); + foreach (const QRect &r, region.rects()) + p.fillRect(r, blank); } } diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.h b/src/plugins/platforms/windows/qwindowsbackingstore.h index 41ad29babc..4badcf1b09 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.h +++ b/src/plugins/platforms/windows/qwindowsbackingstore.h @@ -35,7 +35,6 @@ #define QWINDOWSBACKINGSTORE_H #include "qtwindows_additional.h" -#include "qwindowsscaling.h" #include <qpa/qplatformbackingstore.h> #include <QtCore/QScopedPointer> @@ -53,12 +52,7 @@ public: ~QWindowsBackingStore(); QPaintDevice *paintDevice() Q_DECL_OVERRIDE; - void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE - { - flushDp(window, QWindowsScaling::mapToNative(region.boundingRect()), - offset * QWindowsScaling::factor()); - } - void flushDp(QWindow *window, const QRect &boundingRect, const QPoint &offset); + void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; void resize(const QSize &size, const QRegion &r) Q_DECL_OVERRIDE; bool scroll(const QRegion &area, int dx, int dy) Q_DECL_OVERRIDE; void beginPaint(const QRegion &) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 3f355db607..717adcc47f 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -51,7 +51,6 @@ #endif #include "qwindowsscreen.h" #include "qwindowstheme.h" -#include "qwindowsscaling.h" #include <QtGui/QWindow> #include <qpa/qwindowsysteminterface.h> @@ -1232,9 +1231,7 @@ bool QWindowsContext::handleContextMenuEvent(QWindow *window, const MSG &msg) } } - QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, - pos / QWindowsScaling::factor(), - globalPos / QWindowsScaling::factor(), + QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, pos, globalPos, QWindowsKeyMapper::queryKeyboardModifiers()); return true; } diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index 5f443f2675..1fbef61029 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -36,7 +36,6 @@ #include "qwindowscontext.h" #include "qwindowswindow.h" #include "qwindowsscreen.h" -#include "qwindowsscaling.h" #include <QtGui/QBitmap> #include <QtGui/QImage> @@ -646,13 +645,12 @@ QWindowsCursor::CursorState QWindowsCursor::cursorState() QPoint QWindowsCursor::pos() const { - return mousePosition() / QWindowsScaling::factor(); + return mousePosition(); } void QWindowsCursor::setPos(const QPoint &pos) { - const QPoint posDp = pos * QWindowsScaling::factor(); - SetCursorPos(posDp.x() , posDp.y()); + SetCursorPos(pos.x() , pos.y()); } /*! diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 03438e3ee2..d24cba3c68 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -33,7 +33,7 @@ #include "qwindowsdrag.h" #include "qwindowscontext.h" -#include "qwindowsscaling.h" +#include "qwindowsscreen.h" #ifndef QT_NO_CLIPBOARD # include "qwindowsclipboard.h" #endif @@ -43,7 +43,6 @@ #include "qwindowswindow.h" #include "qwindowsmousehandler.h" #include "qwindowscursor.h" -#include "qwindowsscaling.h" #include <QtGui/QMouseEvent> #include <QtGui/QPixmap> @@ -52,6 +51,7 @@ #include <QtGui/QGuiApplication> #include <qpa/qwindowsysteminterface_p.h> #include <QtGui/private/qguiapplication_p.h> +#include <QtGui/private/qhighdpiscaling_p.h> #include <QtCore/QDebug> #include <QtCore/QBuffer> @@ -280,6 +280,13 @@ QDebug operator<<(QDebug d, const QWindowsOleDropSource::CursorEntry &e) } #endif // !QT_NO_DEBUG_OUTPUT +static qreal dragScaleFactor() +{ + const QWindowsScreenManager &screenManager = QWindowsContext::instance()->screenManager(); + const QWindowsScreen *screen = screenManager.screenAtDp(QWindowsCursor::mousePosition()); + return screen ? QHighDpiScaling::factor(screen) : qreal(1); +} + /*! \brief Blend custom pixmap with cursors. */ @@ -289,19 +296,22 @@ void QWindowsOleDropSource::createCursors() const QDrag *drag = m_drag->currentDrag(); const QPixmap pixmap = drag->pixmap(); const bool hasPixmap = !pixmap.isNull(); - const int scaleFactor = QWindowsScaling::factor(); - const QSize pixmapSizeDp = pixmap.size() * scaleFactor; + + const qreal scaleFactor = dragScaleFactor(); const bool scalePixmap = hasPixmap && m_mode != TouchDrag // Touch drag: pixmap is shown in a separate QWindow, which will be scaled. && (scaleFactor != 1 && scaleFactor != qRound(pixmap.devicePixelRatio())); - const QPixmap drawPixmap = scalePixmap - ? pixmap.scaled(pixmapSizeDp, Qt::KeepAspectRatio, Qt::SmoothTransformation) : pixmap; - + const QPixmap scaledPixmap = scalePixmap + ? pixmap.scaled((QSizeF(pixmap.size()) * scaleFactor).toSize(), + Qt::KeepAspectRatio, Qt::SmoothTransformation) + : pixmap; Qt::DropAction actions[] = { Qt::MoveAction, Qt::CopyAction, Qt::LinkAction, Qt::IgnoreAction }; int actionCount = int(sizeof(actions) / sizeof(actions[0])); if (!hasPixmap) --actionCount; // No Qt::IgnoreAction unless pixmap - const QPoint hotSpot = drag->hotSpot() * scaleFactor; + const QPoint hotSpot = scalePixmap + ? (QPointF(drag->hotSpot()) * scaleFactor).toPoint() + : drag->hotSpot(); for (int cnum = 0; cnum < actionCount; ++cnum) { const Qt::DropAction action = actions[cnum]; QPixmap cursorPixmap = drag->dragCursor(action); @@ -321,14 +331,14 @@ void QWindowsOleDropSource::createCursors() if (hasPixmap) { const int x1 = qMin(-hotSpot.x(), 0); - const int x2 = qMax(pixmapSizeDp.width() - hotSpot.x(), cursorPixmap.width()); + const int x2 = qMax(scaledPixmap.width() - hotSpot.x(), cursorPixmap.width()); const int y1 = qMin(-hotSpot.y(), 0); - const int y2 = qMax(pixmapSizeDp.height() - hotSpot.y(), cursorPixmap.height()); + const int y2 = qMax(scaledPixmap.height() - hotSpot.y(), cursorPixmap.height()); QPixmap newCursor(x2 - x1 + 1, y2 - y1 + 1); newCursor.fill(Qt::transparent); QPainter p(&newCursor); const QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y())); - p.drawPixmap(pmDest, drawPixmap); + p.drawPixmap(pmDest, scaledPixmap); p.drawPixmap(qMax(0, hotSpot.x()),qMax(0, hotSpot.y()), cursorPixmap); newPixmap = newCursor; newHotSpot = QPoint(qMax(0, hotSpot.x()), qMax(0, hotSpot.y())); @@ -454,7 +464,7 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect) if (!m_touchDragWindow) m_touchDragWindow = new QWindowsDragCursorWindow; m_touchDragWindow->setPixmap(e.pixmap); - m_touchDragWindow->setFramePosition((QWindowsCursor::mousePosition() - e.hotSpot) / QWindowsScaling::factor()); + m_touchDragWindow->setFramePosition(QWindowsCursor::mousePosition() - e.hotSpot); if (!m_touchDragWindow->isVisible()) m_touchDragWindow->show(); break; @@ -530,9 +540,7 @@ void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState, QGuiApplicationPrivate::mouse_buttons = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState); const QPlatformDragQtResponse response = - QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), - m_lastPoint / QWindowsScaling::factor(), - actions); + QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), m_lastPoint, actions); m_answerRect = response.answerRect(); const Qt::DropAction action = response.acceptedAction(); @@ -625,9 +633,8 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, const QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(), - m_lastPoint / QWindowsScaling::factor(), + m_lastPoint, translateToQDragDropActions(*pdwEffect)); - if (response.isAccepted()) { const Qt::DropAction action = response.acceptedAction(); if (action == Qt::MoveAction || action == Qt::TargetMoveAction) { diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index 68e38dc4a6..554a6c8b4c 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -36,7 +36,6 @@ #include "qwindowswindow.h" #include "qwindowsintegration.h" #include "qwindowsmousehandler.h" -#include "qwindowsscaling.h" #include <QtCore/QDebug> #include <QtCore/QObject> @@ -254,10 +253,9 @@ void QWindowsInputContext::cursorRectChanged() if (!m_compositionContext.hwnd) return; const QInputMethod *inputMethod = QGuiApplication::inputMethod(); - const QRect cursorRectangleDip = inputMethod->cursorRectangle().toRect(); - if (!cursorRectangleDip.isValid()) + const QRect cursorRectangle = inputMethod->cursorRectangle().toRect(); + if (!cursorRectangle.isValid()) return; - const QRect cursorRectangle = QWindowsScaling::mapToNative(cursorRectangleDip); qCDebug(lcQpaInputMethods) << __FUNCTION__<< cursorRectangle; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 79df6ce720..bbb1f68a52 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -33,7 +33,6 @@ ****************************************************************************/ #include "qwindowsintegration.h" -#include "qwindowsscaling.h" #include "qwindowswindow.h" #include "qwindowscontext.h" #include "qwindowsopenglcontext.h" @@ -64,6 +63,7 @@ # include "qwindowssessionmanager.h" #endif #include <QtGui/private/qguiapplication_p.h> +#include <QtGui/private/qhighdpiscaling_p.h> #include <QtGui/qpa/qplatforminputcontextfactory_p.h> #include <QtCore/private/qeventdispatcher_win_p.h> @@ -223,12 +223,8 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList ¶mL m_context.setProcessDpiAwareness(dpiAwareness); dpiAwarenessSet = true; } - // Determine suitable scale factor, don't mix Windows and Qt scaling - if (dpiAwareness != QtWindows::ProcessDpiUnaware) - QWindowsScaling::setFactor(QWindowsScaling::determineUiScaleFactor()); qCDebug(lcQpaWindows) - << __FUNCTION__ << "DpiAwareness=" << dpiAwareness <<",Scaling=" - << QWindowsScaling::factor(); + << __FUNCTION__ << "DpiAwareness=" << dpiAwareness; QTouchDevice *touchDevice = m_context.touchDevice(); if (touchDevice) { @@ -268,10 +264,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 @@ -307,7 +302,7 @@ QWindowsWindowData QWindowsIntegration::createWindowData(QWindow *window) const { QWindowsWindowData requested; requested.flags = window->flags(); - requested.geometry = QWindowsScaling::mapToNative(window->geometry()); + requested.geometry = QHighDpi::toNativePixels(window->geometry(), window); // Apply custom margins (see QWindowsWindow::setCustomMargins())). const QVariant customMarginsV = window->property("_q_windowsCustomMargins"); if (customMarginsV.isValid()) @@ -327,7 +322,7 @@ QWindowsWindowData QWindowsIntegration::createWindowData(QWindow *window) const window->setFlags(obtained.flags); // Trigger geometry change signals of QWindow. if ((obtained.flags & Qt::Desktop) != Qt::Desktop && requested.geometry != obtained.geometry) - QWindowSystemInterface::handleGeometryChange(window, QWindowsScaling::mapFromNative(obtained.geometry)); + QWindowSystemInterface::handleGeometryChange(window, obtained.geometry); } return obtained; diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index d47c7df9e0..3636bb7893 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -35,12 +35,12 @@ #include "qwindowscontext.h" #include "qwindowswindow.h" #include "qwindowsguieventdispatcher.h" -#include "qwindowsscaling.h" #include "qwindowsinputcontext.h" #include <QtGui/QWindow> #include <qpa/qwindowsysteminterface.h> #include <private/qguiapplication_p.h> +#include <private/qhighdpiscaling_p.h> #include <QtGui/QKeyEvent> #if defined(WM_APPCOMMAND) @@ -792,10 +792,12 @@ static void showSystemMenu(QWindow* w) #undef enabled #undef disabled #endif // !Q_OS_WINCE - const QPoint topLeft = topLevel->geometry().topLeft() * QWindowsScaling::factor(); + const QPoint pos = QHighDpi::toNativePixels(topLevel->geometry().topLeft(), topLevel); const int ret = TrackPopupMenuEx(menu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD, - topLeft.x(), topLeft.y(), topLevelHwnd, 0); + pos.x(), pos.y(), + topLevelHwnd, + 0); if (ret) qWindowsWndProc(topLevelHwnd, WM_SYSCOMMAND, ret, 0); } diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index e6b80f2b93..200eb11855 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -211,10 +211,8 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, const QPoint globalPosition = winEventPosition; const QPoint clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition); const Qt::MouseButtons buttons = QWindowsMouseHandler::queryMouseButtons(); - QWindowSystemInterface::handleFrameStrutMouseEvent(window, - clientPosition / QWindowsScaling::factor(), - globalPosition / QWindowsScaling::factor(), - buttons, + QWindowSystemInterface::handleFrameStrutMouseEvent(window, clientPosition, + globalPosition, buttons, QWindowsKeyMapper::queryKeyboardModifiers(), source); return false; // Allow further event processing (dragging of windows). @@ -279,7 +277,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, // ChildWindowFromPointEx() may not find the Qt window (failing with ERROR_ACCESS_DENIED) if (!currentWindowUnderMouse) { const QRect clientRect(QPoint(0, 0), window->size()); - if (clientRect.contains(winEventPosition / QWindowsScaling::factor())) + if (clientRect.contains(winEventPosition)) currentWindowUnderMouse = window; } @@ -366,10 +364,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, m_windowUnderMouse = currentWindowUnderMouse; } - QWindowSystemInterface::handleMouseEvent(window, - winEventPosition / QWindowsScaling::factor(), - globalPosition / QWindowsScaling::factor(), - buttons, + QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons, QWindowsKeyMapper::queryKeyboardModifiers(), source); m_previousCaptureWindow = hasCapture ? window : 0; @@ -404,11 +399,9 @@ static void redirectWheelEvent(QWindow *window, const QPoint &globalPos, int del } if (handleEvent) { - const QPoint posDip = QWindowsGeometryHint::mapFromGlobal(receiver, globalPos) / QWindowsScaling::factor(); QWindowSystemInterface::handleWheelEvent(receiver, - posDip, globalPos / QWindowsScaling::factor(), - delta / QWindowsScaling::factor(), - orientation, mods); + QWindowsGeometryHint::mapFromGlobal(receiver, globalPos), + globalPos, delta, orientation, mods); } } @@ -494,7 +487,6 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND, Q_ASSERT(QWindowsContext::user32dll.getTouchInputInfo); QWindowsContext::user32dll.getTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT)); - const qreal screenPosFactor = 0.01 / qreal(QWindowsScaling::factor()); for (int i = 0; i < winTouchPointCount; ++i) { const TOUCHINPUT &winTouchInput = winTouchInputs[i]; int id = m_touchInputIDToTouchPointID.value(winTouchInput.dwID, -1); @@ -508,9 +500,9 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND, if (m_lastTouchPositions.contains(id)) touchPoint.normalPosition = m_lastTouchPositions.value(id); - const QPointF screenPos = QPointF(winTouchInput.x, winTouchInput.y) * screenPosFactor; + const QPointF screenPos = QPointF(winTouchInput.x, winTouchInput.y) / qreal(100.); if (winTouchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA) - touchPoint.area.setSize(QSizeF(winTouchInput.cxContact, winTouchInput.cyContact) * screenPosFactor); + touchPoint.area.setSize(QSizeF(winTouchInput.cxContact, winTouchInput.cyContact) / qreal(100.)); touchPoint.area.moveCenter(screenPos); QPointF normalPosition = QPointF(screenPos.x() / screenGeometry.width(), screenPos.y() / screenGeometry.height()); diff --git a/src/plugins/platforms/windows/qwindowsnativeimage.h b/src/plugins/platforms/windows/qwindowsnativeimage.h index 6f9ce93ef0..80a1de1ea5 100644 --- a/src/plugins/platforms/windows/qwindowsnativeimage.h +++ b/src/plugins/platforms/windows/qwindowsnativeimage.h @@ -57,8 +57,6 @@ public: HDC hdc() const { return m_hdc; } - void setDevicePixelRatio(qreal scaleFactor) { m_image.setDevicePixelRatio(scaleFactor); } - static QImage::Format systemFormat(); private: diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp index 810fddbca7..52e83395d1 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.cpp +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -224,7 +224,7 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::detectSupportedRenderers(c #elif defined(Q_OS_WINCE) return QWindowsOpenGLTester::Gles; #else - QOpenGLConfig::Gpu qgpu = QOpenGLConfig::Gpu::fromDevice(gpu.vendorId, gpu.deviceId, gpu.driverVersion); + QOpenGLConfig::Gpu qgpu = QOpenGLConfig::Gpu::fromDevice(gpu.vendorId, gpu.deviceId, gpu.driverVersion, gpu.description); SupportedRenderersCache *srCache = supportedRenderersCache(); SupportedRenderersCache::const_iterator it = srCache->find(qgpu); if (it != srCache->cend()) @@ -250,19 +250,19 @@ QWindowsOpenGLTester::Renderers QWindowsOpenGLTester::detectSupportedRenderers(c qCDebug(lcQpaGl) << "GPU features:" << features; if (features.contains(QStringLiteral("disable_desktopgl"))) { // Qt-specific - qCWarning(lcQpaGl) << "Disabling Desktop GL: " << gpu; + qCDebug(lcQpaGl) << "Disabling Desktop GL: " << gpu; result &= ~QWindowsOpenGLTester::DesktopGl; } if (features.contains(QStringLiteral("disable_angle"))) { // Qt-specific keyword - qCWarning(lcQpaGl) << "Disabling ANGLE: " << gpu; + qCDebug(lcQpaGl) << "Disabling ANGLE: " << gpu; result &= ~QWindowsOpenGLTester::GlesMask; } else { if (features.contains(QStringLiteral("disable_d3d11"))) { // standard keyword - qCWarning(lcQpaGl) << "Disabling D3D11: " << gpu; + qCDebug(lcQpaGl) << "Disabling D3D11: " << gpu; result &= ~QWindowsOpenGLTester::AngleRendererD3d11; } if (features.contains(QStringLiteral("disable_d3d9"))) { // Qt-specific - qCWarning(lcQpaGl) << "Disabling D3D9: " << gpu; + qCDebug(lcQpaGl) << "Disabling D3D9: " << gpu; result &= ~QWindowsOpenGLTester::AngleRendererD3d9; } } diff --git a/src/plugins/platforms/windows/qwindowsopengltester.h b/src/plugins/platforms/windows/qwindowsopengltester.h index 748885542d..3cd8bf4d4b 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.h +++ b/src/plugins/platforms/windows/qwindowsopengltester.h @@ -36,7 +36,7 @@ #include <QtCore/QByteArray> #include <QtCore/QFlags> -#include <private/qversionnumber_p.h> +#include <QtCore/qversionnumber.h> QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsscaling.cpp b/src/plugins/platforms/windows/qwindowsscaling.cpp deleted file mode 100644 index 6ab7f254fd..0000000000 --- a/src/plugins/platforms/windows/qwindowsscaling.cpp +++ /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$ -** -****************************************************************************/ - -#include "qwindowsscaling.h" -#include "qwindowsscreen.h" - -#include <QtCore/QDebug> -#include <QtCore/QCoreApplication> - -QT_BEGIN_NAMESPACE - -/*! - \class QWindowsScaling - \brief Windows scaling utilities - - \internal - \ingroup qt-lighthouse-win -*/ - -int QWindowsScaling::m_factor = 1; - -static const char devicePixelRatioEnvVar[] = "QT_DEVICE_PIXEL_RATIO"; - -// Suggest a scale factor by checking monitor sizes. -int QWindowsScaling::determineUiScaleFactor() -{ - if (!qEnvironmentVariableIsSet(devicePixelRatioEnvVar)) - return 1; - const QByteArray envDevicePixelRatioEnv = qgetenv(devicePixelRatioEnvVar); - // Auto: Suggest a scale factor by checking monitor resolution. - if (envDevicePixelRatioEnv == "auto") { - const int maxResolution = QWindowsScreen::maxMonitorHorizResolution(); - return maxResolution > 180 ? maxResolution / 96 : 1; - } - // Get factor from environment - bool ok = false; - const int envFactor = envDevicePixelRatioEnv.toInt(&ok); - return ok && envFactor > 0 ? envFactor : 1; -} - -QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsscaling.h b/src/plugins/platforms/windows/qwindowsscaling.h deleted file mode 100644 index 39e554bbe2..0000000000 --- a/src/plugins/platforms/windows/qwindowsscaling.h +++ /dev/null @@ -1,106 +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 QWINDOWSSCALING_H -#define QWINDOWSSCALING_H - -#include <QtGui/QRegion> -#include <QtCore/QVector> -#include <QtCore/QRect> - -QT_BEGIN_NAMESPACE - -enum -#if defined(Q_COMPILER_CLASS_ENUM) || defined(Q_CC_MSVC) - : int -#endif -{ QWINDOWSIZE_MAX = 16777215 }; - -class QWindowsScaling { -public: - static bool isActive() { return m_factor > 1; } - static int factor() { return m_factor; } - static void setFactor(int factor) { m_factor = factor; } - static int determineUiScaleFactor(); - - // Scaling helpers for size constraints. - static int mapToNativeConstrained(int qt) - { return m_factor != 1 && qt > 0 && qt < QWINDOWSIZE_MAX ? qt * m_factor : qt; } - - static int mapFromNativeConstrained(int dp) - { return m_factor != 1 && dp > 0 && dp < QWINDOWSIZE_MAX ? dp / m_factor : dp; } - - static QSize mapToNativeConstrained(const QSize &qt) - { return QSize(mapToNativeConstrained(qt.width()), mapToNativeConstrained(qt.height())); } - - static QRect mapToNative(const QRect &qRect) - { - return QRect(qRect.x() * m_factor, qRect.y() * m_factor, qRect.width() * m_factor, qRect.height() * m_factor); - } - - static QRect mapFromNative(const QRect &dp) - { - return isActive() ? - QRect(dp.x() / m_factor, dp.y() / m_factor, (dp.width() + 1) / m_factor, (dp.height() + 1) / m_factor) : - dp; - } - - static QRegion mapToNative(const QRegion ®ionQt) - { - if (!QWindowsScaling::isActive() || regionQt.isEmpty()) - return regionQt; - - QRegion result; - foreach (const QRect &rectQt, regionQt.rects()) - result += QWindowsScaling::mapToNative(rectQt); - return result; - } - - static QRegion mapFromNative(const QRegion ®ionDp) - { - if (!QWindowsScaling::isActive() || regionDp.isEmpty()) - return regionDp; - - QRegion result; - foreach (const QRect &rectDp, regionDp.rects()) - result += QWindowsScaling::mapFromNative(rectDp); - return result; - } - -private: - static int m_factor; -}; - -QT_END_NAMESPACE - -#endif // QWINDOWSSCALING_H diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 7756c77001..391735a035 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -43,6 +43,7 @@ #include <QtGui/QPixmap> #include <QtGui/QGuiApplication> #include <qpa/qwindowsysteminterface.h> +#include <private/qhighdpiscaling_p.h> #include <QtGui/QScreen> #include <QtCore/QDebug> @@ -218,36 +219,14 @@ QWindowsScreen::QWindowsScreen(const QWindowsScreenData &data) : { } -BOOL QT_WIN_CALLBACK monitorResolutionEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p) -{ - QWindowsScreenData data; - if (monitorData(hMonitor, &data)) { - int *maxHorizResolution = reinterpret_cast<int *>(p); - const int horizResolution = qRound(data.dpi.first); - if (horizResolution > *maxHorizResolution) - *maxHorizResolution = horizResolution; - } - return TRUE; -} - -int QWindowsScreen::maxMonitorHorizResolution() -{ - int result = 0; - EnumDisplayMonitors(0, 0, monitorResolutionEnumCallback, (LPARAM)&result); - return result; -} - Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0); -QPixmap QWindowsScreen::grabWindow(WId window, int qX, int qY, int qWidth, int qHeight) const +QPixmap QWindowsScreen::grabWindow(WId window, int x, int y, int width, int height) const { RECT r; HWND hwnd = window ? (HWND)window : GetDesktopWindow(); GetClientRect(hwnd, &r); - const int x = qX * QWindowsScaling::factor(); - const int y = qY * QWindowsScaling::factor(); - int width = qWidth * QWindowsScaling::factor(); - int height = qHeight * QWindowsScaling::factor(); + if (width < 0) width = r.right - r.left; if (height < 0) height = r.bottom - r.top; @@ -271,10 +250,6 @@ QPixmap QWindowsScreen::grabWindow(WId window, int qX, int qY, int qWidth, int q DeleteObject(bitmap); ReleaseDC(0, display_dc); - if (QWindowsScaling::isActive()) { - const qreal factor = 1.0 / qreal(QWindowsScaling::factor()); - return pixmap.transformed(QTransform::fromScale(factor, factor)); - } return pixmap; } @@ -285,7 +260,7 @@ QPixmap QWindowsScreen::grabWindow(WId window, int qX, int qY, int qWidth, int q QWindow *QWindowsScreen::topLevelAt(const QPoint &point) const { QWindow *result = 0; - if (QWindow *child = QWindowsScreen::windowAt(point * QWindowsScaling::factor(), CWP_SKIPINVISIBLE)) + if (QWindow *child = QWindowsScreen::windowAt(point, CWP_SKIPINVISIBLE)) result = QWindowsWindow::topLevelOf(child); qCDebug(lcQpaWindows) <<__FUNCTION__ << point << result; return result; @@ -313,6 +288,12 @@ QWindowsScreen *QWindowsScreen::screenOf(const QWindow *w) return 0; } +qreal QWindowsScreen::pixelDensity() const +{ + const qreal physicalDpi = m_data.geometry.width() / m_data.physicalSizeMM.width() * qreal(25.4); + return qRound(physicalDpi / 96); +} + /*! \brief Determine siblings in a virtual desktop system. @@ -542,7 +523,7 @@ void QWindowsScreenManager::clearScreens() const QWindowsScreen *QWindowsScreenManager::screenAtDp(const QPoint &p) const { foreach (QWindowsScreen *scr, m_screens) { - if (scr->geometryDp().contains(p)) + if (scr->geometry().contains(p)) return scr; } return Q_NULLPTR; diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index 7352c45777..67e7ff644b 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -34,7 +34,6 @@ #ifndef QWINDOWSSCREEN_H #define QWINDOWSSCREEN_H -#include "qwindowsscaling.h" #include "qtwindowsglobal.h" #ifdef Q_OS_WINCE # include "qplatformfunctions_wince.h" @@ -82,16 +81,14 @@ public: static QWindowsScreen *screenOf(const QWindow *w = 0); - QRect geometryDp() const { return m_data.geometry; } - QRect geometry() const Q_DECL_OVERRIDE { return QWindowsScaling::mapFromNative(geometryDp()); } - QRect availableGeometryDp() const { return m_data.availableGeometry; } - QRect availableGeometry() const Q_DECL_OVERRIDE { return QWindowsScaling::mapFromNative(availableGeometryDp()); } + 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; } QImage::Format format() const Q_DECL_OVERRIDE { return m_data.format; } QSizeF physicalSize() const Q_DECL_OVERRIDE { return m_data.physicalSizeMM; } - QDpi logicalDpi() const Q_DECL_OVERRIDE - { return QDpi(m_data.dpi.first / QWindowsScaling::factor(), m_data.dpi.second / QWindowsScaling::factor()); } - qreal devicePixelRatio() const Q_DECL_OVERRIDE { return QWindowsScaling::factor(); } + QDpi logicalDpi() const Q_DECL_OVERRIDE { return m_data.dpi; } + qreal pixelDensity() const Q_DECL_OVERRIDE; + qreal devicePixelRatio() const Q_DECL_OVERRIDE { return 1.0; } qreal refreshRate() const Q_DECL_OVERRIDE { return m_data.refreshRateHz; } QString name() const Q_DECL_OVERRIDE { return m_data.name; } Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE { return m_data.orientation; } @@ -112,7 +109,6 @@ public: #endif // !QT_NO_CURSOR const QWindowsScreenData &data() const { return m_data; } - static int maxMonitorHorizResolution(); private: QWindowsScreenData m_data; diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp index 7b871be015..3951401273 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp +++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp @@ -32,7 +32,6 @@ ****************************************************************************/ #include "qwindowstabletsupport.h" -#include "qwindowsscaling.h" #ifndef QT_NO_TABLETEVENT @@ -55,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 @@ -343,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); @@ -371,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; @@ -399,8 +400,7 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() // in which case we snap the position to the mouse position. // It seems there is no way to find out the mode programmatically, the LOGCONTEXT orgX/Y/Ext // area is always the virtual desktop. - const QRect virtualDesktopArea - = QWindowsScaling::mapToNative(QGuiApplication::primaryScreen()->virtualGeometry()); + const QRect virtualDesktopArea = QGuiApplication::primaryScreen()->virtualGeometry(); qCDebug(lcQpaTablet) << __FUNCTION__ << "processing " << packetCount << "target:" << QGuiApplicationPrivate::tabletPressTarget; @@ -420,7 +420,7 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() QPoint globalPos = globalPosF.toPoint(); // Get Mouse Position and compare to tablet info - QPoint mouseLocation = QWindowsCursor::mousePosition(); + const QPoint mouseLocation = QWindowsCursor::mousePosition(); // Positions should be almost the same if we are in absolute // mode. If they are not, use the mouse location. @@ -475,9 +475,7 @@ bool QWindowsTabletSupport::translateTabletPacketEvent() << tiltY << "tanP:" << tangentialPressure << "rotation:" << rotation; } - const QPointF localPosDip = QPointF(localPos / QWindowsScaling::factor()); - const QPointF globalPosDip = globalPosF / qreal(QWindowsScaling::factor()); - QWindowSystemInterface::handleTabletEvent(target, localPosDip, globalPosDip, + 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/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index d3f67e9eaa..33c7ccfdce 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -43,7 +43,6 @@ #include "qwindowsintegration.h" #include "qt_windows.h" #include "qwindowsfontdatabase.h" -#include "qwindowsscaling.h" #ifdef Q_OS_WINCE # include "qplatformfunctions_wince.h" # include "winuser.h" @@ -68,6 +67,7 @@ #include <QtGui/QPainter> #include <QtGui/QPixmapCache> #include <qpa/qwindowsysteminterface.h> +#include <private/qhighdpiscaling_p.h> #include <private/qsystemlibrary_p.h> #include <algorithm> @@ -495,7 +495,8 @@ static QPixmap loadIconFromShell32(int resourceId, QSizeF size) QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const { - const int scaleFactor = QWindowsScaling::factor(); + const QScreen *primaryScreen = QGuiApplication::primaryScreen(); + const int scaleFactor = primaryScreen ? qRound(QHighDpiScaling::factor(primaryScreen)) : 1; const QSizeF pixmapSize = size * scaleFactor; int resourceId = -1; LPCTSTR iconName = 0; @@ -632,7 +633,7 @@ public: static FakePointer *create(T thing) { - return reinterpret_cast<FakePointer *>(thing); + return reinterpret_cast<FakePointer *>(qintptr(thing)); } T operator * () const @@ -720,6 +721,7 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s iconSize|SHGFI_SYSICONINDEX; #endif // Q_OS_WINCE unsigned long val = 0; +#if !defined(QT_NO_WINCE_SHELLSDK) if (cacheableDirIcon && useDefaultFolderIcon) { flags |= SHGFI_USEFILEATTRIBUTES; val = SHGetFileInfo(L"dummy", @@ -729,6 +731,7 @@ QPixmap QWindowsTheme::fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &s val = SHGetFileInfo(reinterpret_cast<const wchar_t *>(filePath.utf16()), 0, &info, sizeof(SHFILEINFO), flags); } +#endif // !QT_NO_WINCE_SHELLSDK // Even if GetFileInfo returns a valid result, hIcon can be empty in some cases if (val && info.hIcon) { diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 288f73cb8f..f9b34334df 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -36,7 +36,6 @@ #include "qwindowscontext.h" #include "qwindowsdrag.h" #include "qwindowsscreen.h" -#include "qwindowsscaling.h" #include "qwindowsintegration.h" #include "qwindowsopenglcontext.h" #ifdef QT_NO_CURSOR @@ -49,8 +48,9 @@ #include <QtGui/QRegion> #include <QtGui/QOpenGLContext> #include <private/qsystemlibrary_p.h> -#include <private/qwindow_p.h> +#include <private/qwindow_p.h> // QWINDOWSIZE_MAX #include <private/qguiapplication_p.h> +#include <private/qhighdpiscaling_p.h> #include <qpa/qwindowsysteminterface.h> #include <QtCore/QDebug> @@ -169,7 +169,7 @@ static QPoint windowPlacementOffset(HWND hwnd, const QPoint &point) const QWindowsScreen *screen = screenManager.screens().size() == 1 ? screenManager.screens().first() : screenManager.screenAtDp(point); if (screen) - return screen->availableGeometryDp().topLeft() - screen->geometryDp().topLeft(); + return screen->availableGeometry().topLeft() - screen->geometry().topLeft(); #else Q_UNUSED(hwnd) Q_UNUSED(point) @@ -608,9 +608,7 @@ QWindowsWindowData const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w); - const QRect geometryDip = QWindowsScaling::mapFromNative(data.geometry); - QRect fixedGeometryDip = QPlatformWindow::initialGeometry(w, geometryDip, defaultWindowWidth, defaultWindowHeight); - const QRect rect = fixedGeometryDip != geometryDip ? QWindowsScaling::mapToNative(fixedGeometryDip) : data.geometry; + const QRect rect = QPlatformWindow::initialGeometry(w, data.geometry, defaultWindowWidth, defaultWindowHeight); if (title.isEmpty() && (result.flags & Qt::WindowTitleHint)) title = topLevel ? qAppName() : w->objectName(); @@ -706,6 +704,20 @@ void WindowCreationData::initialize(const QWindow *w, HWND hwnd, bool frameChang } } + +// Scaling helpers for size constraints. +static QSize toNativeSizeConstrained(QSize dip, const QWindow *w) +{ + if (QHighDpiScaling::isActive()) { + const qreal factor = QHighDpiScaling::factor(w); + if (dip.width() > 0 && dip.width() < QWINDOWSIZE_MAX) + dip.rwidth() *= factor; + if (dip.height() > 0 && dip.height() < QWINDOWSIZE_MAX) + dip.rheight() *= factor; + } + return dip; +} + /*! \class QWindowsGeometryHint \brief Stores geometry constraints and provides utility functions. @@ -718,8 +730,8 @@ void WindowCreationData::initialize(const QWindow *w, HWND hwnd, bool frameChang */ QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w, const QMargins &cm) : - minimumSize(QWindowsScaling::mapToNativeConstrained(w->minimumSize())), - maximumSize(QWindowsScaling::mapToNativeConstrained(w->maximumSize())), + minimumSize(toNativeSizeConstrained(w->minimumSize(), w)), + maximumSize(toNativeSizeConstrained(w->maximumSize(), w)), customMargins(cm) { } @@ -953,8 +965,7 @@ void QWindowsWindow::fireExpose(const QRegion ®ion, bool force) clearFlag(Exposed); else setFlag(Exposed); - QWindowSystemInterface::handleExposeEvent(window(), - QWindowsScaling::mapFromNative(region)); + QWindowSystemInterface::handleExposeEvent(window(), region); } static inline QWindow *findTransientChild(const QWindow *parent) @@ -1134,7 +1145,7 @@ bool QWindowsWindow::isEmbedded(const QPlatformWindow *parentWindow) const return m_data.embedded; } -QPoint QWindowsWindow::mapToGlobalDp(const QPoint &pos) const +QPoint QWindowsWindow::mapToGlobal(const QPoint &pos) const { if (m_data.hwnd) return QWindowsGeometryHint::mapToGlobal(m_data.hwnd, pos); @@ -1142,7 +1153,7 @@ QPoint QWindowsWindow::mapToGlobalDp(const QPoint &pos) const return pos; } -QPoint QWindowsWindow::mapFromGlobalDp(const QPoint &pos) const +QPoint QWindowsWindow::mapFromGlobal(const QPoint &pos) const { if (m_data.hwnd) return QWindowsGeometryHint::mapFromGlobal(m_data.hwnd, pos); @@ -1323,22 +1334,22 @@ static QRect normalFrameGeometry(HWND hwnd) return QRect(); } -QRect QWindowsWindow::normalGeometryDp() const +QRect QWindowsWindow::normalGeometry() const { // Check for fake 'fullscreen' mode. const bool fakeFullScreen = m_savedFrameGeometry.isValid() && window()->windowState() == Qt::WindowFullScreen; const QRect frame = fakeFullScreen ? m_savedFrameGeometry : normalFrameGeometry(m_data.hwnd); - const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : frameMarginsDp(); + const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : frameMargins(); return frame.isValid() ? frame.marginsRemoved(margins) : frame; } -void QWindowsWindow::setGeometryDp(const QRect &rectIn) +void QWindowsWindow::setGeometry(const QRect &rectIn) { QRect rect = rectIn; // This means it is a call from QWindow::setFramePosition() and // the coordinates include the frame (size is still the contents rectangle). if (QWindowsGeometryHint::positionIncludesFrame(window())) { - const QMargins margins = frameMarginsDp(); + const QMargins margins = frameMargins(); rect.moveTopLeft(rect.topLeft() + QPoint(margins.left(), margins.top())); } if (m_windowState == Qt::WindowMinimized) @@ -1407,9 +1418,8 @@ void QWindowsWindow::handleGeometryChange() return; const QRect previousGeometry = m_data.geometry; m_data.geometry = geometry_sys(); - const QRect geometryDip = QWindowsScaling::mapFromNative(m_data.geometry); - QPlatformWindow::setGeometry(geometryDip); - QWindowSystemInterface::handleGeometryChange(window(), geometryDip); + QPlatformWindow::setGeometry(m_data.geometry); + QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry); // QTBUG-32121: OpenGL/normal windows (with exception of ANGLE) do not receive // expose events when shrinking, synthesize. if (!testFlag(OpenGL_ES2) && isExposed() @@ -1417,7 +1427,7 @@ void QWindowsWindow::handleGeometryChange() fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), true); } if (previousGeometry.topLeft() != m_data.geometry.topLeft()) { - QPlatformScreen *newScreen = screenForGeometry(geometryDip); + QPlatformScreen *newScreen = screenForGeometry(m_data.geometry); if (newScreen != screen()) QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); } @@ -1429,7 +1439,7 @@ void QWindowsWindow::handleGeometryChange() void QWindowsWindow::setGeometry_sys(const QRect &rect) const { - const QMargins margins = frameMarginsDp(); + const QMargins margins = frameMargins(); const QRect frameGeometry = rect + margins; qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << window() @@ -1468,7 +1478,7 @@ QRect QWindowsWindow::frameGeometry_sys() const QRect QWindowsWindow::geometry_sys() const { - return frameGeometry_sys().marginsRemoved(frameMarginsDp()); + return frameGeometry_sys().marginsRemoved(frameMargins()); } /*! @@ -1540,7 +1550,7 @@ void QWindowsWindow::setWindowFlags(Qt::WindowFlags flags) { qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window() << "\n from: " << m_data.flags << "\n to: " << flags; - const QRect oldGeometry = geometryDp(); + const QRect oldGeometry = geometry(); if (m_data.flags != flags) { m_data.flags = flags; if (m_data.hwnd) { @@ -1626,8 +1636,9 @@ void QWindowsWindow::setWindowState(Qt::WindowState state) bool QWindowsWindow::isFullScreen_sys() const { - return window()->isTopLevel() - && geometry_sys() == QWindowsScaling::mapToNative(window()->screen()->geometry()); + const QWindow *w = window(); + return w->isTopLevel() + && geometry_sys() == QHighDpi::toNativePixels(w->screen()->geometry(), w); } /*! @@ -1697,15 +1708,14 @@ 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 rDip = screen->geometry(); - const QRect r = QWindowsScaling::mapToNative(rDip); + const QRect r = QHighDpi::toNativePixels(screen->geometry(), window()); const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE; const bool wasSync = testFlag(SynchronousGeometryChangeEvent); setFlag(SynchronousGeometryChangeEvent); SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf); if (!wasSync) clearFlag(SynchronousGeometryChangeEvent); - QWindowSystemInterface::handleGeometryChange(window(), rDip); + QWindowSystemInterface::handleGeometryChange(window(), r); QWindowSystemInterface::flushWindowSystemEvents(); } else if (newState != Qt::WindowMinimized) { // Restore saved state. @@ -1804,7 +1814,7 @@ void QWindowsWindow::propagateSizeHints() qCDebug(lcQpaWindows) << __FUNCTION__ << this << window(); } -bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &marginsDp) +bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &margins) { #ifndef Q_OS_WINCE if (!qWindow->isTopLevel()) // Implement hasHeightForWidth(). @@ -1812,26 +1822,19 @@ bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow * WINDOWPOS *windowPos = reinterpret_cast<WINDOWPOS *>(message->lParam); if ((windowPos->flags & (SWP_NOCOPYBITS | SWP_NOSIZE))) return false; - const QRect suggestedFrameGeometryDp(windowPos->x, windowPos->y, - windowPos->cx, windowPos->cy); - const qreal factor = QWindowsScaling::factor(); - const QRect suggestedGeometryDp = suggestedFrameGeometryDp - marginsDp; - const QRectF suggestedGeometry = QRectF(QPointF(suggestedGeometryDp.topLeft()) / factor, - QSizeF(suggestedGeometryDp.size()) / factor); - const QRectF correctedGeometryF = - qt_window_private(const_cast<QWindow *>(qWindow))->closestAcceptableGeometry(suggestedGeometry); + const QRect suggestedFrameGeometry(windowPos->x, windowPos->y, + windowPos->cx, windowPos->cy); + const QRect suggestedGeometry = suggestedFrameGeometry - margins; + const QRectF correctedGeometryF = qWindow->handle()->windowClosestAcceptableGeometry(suggestedGeometry); if (!correctedGeometryF.isValid()) return false; - const QRect correctedFrameGeometryDp - = QRectF(correctedGeometryF.topLeft() * factor, - correctedGeometryF.size() * factor).toRect() - + marginsDp; - if (correctedFrameGeometryDp == suggestedFrameGeometryDp) + const QRect correctedFrameGeometry = correctedGeometryF.toRect() + margins; + if (correctedFrameGeometry == suggestedFrameGeometry) return false; - windowPos->x = correctedFrameGeometryDp.left(); - windowPos->y = correctedFrameGeometryDp.top(); - windowPos->cx = correctedFrameGeometryDp.width(); - windowPos->cy = correctedFrameGeometryDp.height(); + windowPos->x = correctedFrameGeometry.left(); + windowPos->y = correctedFrameGeometry.top(); + windowPos->cx = correctedFrameGeometry.width(); + windowPos->cy = correctedFrameGeometry.height(); return true; #else // !Q_OS_WINCE Q_UNUSED(message) @@ -1841,11 +1844,11 @@ bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow * bool QWindowsWindow::handleGeometryChanging(MSG *message) const { - const QMargins marginsDp = window()->isTopLevel() ? frameMarginsDp() : QMargins(); - return QWindowsWindow::handleGeometryChangingMessage(message, window(), marginsDp); + const QMargins margins = window()->isTopLevel() ? frameMargins() : QMargins(); + return QWindowsWindow::handleGeometryChangingMessage(message, window(), margins); } -QMargins QWindowsWindow::frameMarginsDp() const +QMargins QWindowsWindow::frameMargins() const { // Frames are invalidated by style changes (window state, flags). // As they are also required for geometry calculations in resize @@ -1892,17 +1895,17 @@ static inline void addRectToWinRegion(const QRect &rect, HRGN *winRegion) } } -static HRGN qRegionToWinRegion(const QRegion ®ionDip) +static HRGN qRegionToWinRegion(const QRegion ®ion) { - const QVector<QRect> rects = regionDip.rects(); + const QVector<QRect> rects = region.rects(); if (rects.isEmpty()) return NULL; const int rectCount = rects.size(); if (rectCount == 1) - return createRectRegion(QWindowsScaling::mapToNative(regionDip.boundingRect())); - HRGN hRegion = createRectRegion(QWindowsScaling::mapToNative(rects.front())); + return createRectRegion(region.boundingRect()); + HRGN hRegion = createRectRegion(rects.front()); for (int i = 1; i < rectCount; ++i) - addRectToWinRegion(QWindowsScaling::mapToNative(rects.at(i)), &hRegion); + addRectToWinRegion(rects.at(i), &hRegion); return hRegion; } @@ -1916,7 +1919,7 @@ void QWindowsWindow::setMask(const QRegion ®ion) // Mask is in client area coordinates, so offset it in case we have a frame if (window()->isTopLevel()) { - const QMargins margins = frameMarginsDp(); + const QMargins margins = frameMargins(); OffsetRgn(winRegion, margins.left(), margins.top()); } @@ -2053,23 +2056,23 @@ bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *re || (m_data.flags & Qt::FramelessWindowHint)) { return false; } - const QSize minimumSize = QWindowsScaling::mapToNativeConstrained(w->minimumSize()); + const QSize minimumSize = w->minimumSize(); if (minimumSize.isEmpty()) return false; - const QSize maximumSize = QWindowsScaling::mapToNativeConstrained(w->maximumSize()); + const QSize maximumSize = w->maximumSize(); const bool fixedWidth = minimumSize.width() == maximumSize.width(); const bool fixedHeight = minimumSize.height() == maximumSize.height(); if (!fixedWidth && !fixedHeight) return false; - const QPoint localPos = mapFromGlobalDp(globalPos); - const QSize size = w->size() * QWindowsScaling::factor(); + const QPoint localPos = w->mapFromGlobal(QHighDpi::fromNativePixels(globalPos, w)); + const QSize size = w->size(); if (fixedHeight) { if (localPos.y() >= size.height()) { *result = HTBORDER; // Unspecified border, no resize cursor. return true; } if (localPos.y() < 0) { - const QMargins margins = frameMarginsDp(); + const QMargins margins = frameMargins(); const int topResizeBarPos = margins.left() - margins.top(); if (localPos.y() < topResizeBarPos) { *result = HTCAPTION; // Extend caption over top resize bar, let's user move the window. @@ -2245,10 +2248,6 @@ void QWindowsWindow::setWindowIcon(const QIcon &icon) The property can be set using QPlatformNativeInterface::setWindowProperty() or, before platform window creation, by setting a dynamic property on the QWindow (see QWindowsIntegration::createPlatformWindow()). - - Note: The function uses (unscaled) device pixels since the QWizard also - uses AdjustWindowRect() and using device independent pixels would introduce - rounding errors. */ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins) diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index fff90b4b11..d96022e3a5 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -38,7 +38,6 @@ #ifdef Q_OS_WINCE # include "qplatformfunctions_wince.h" #endif -#include "qwindowsscaling.h" #include "qwindowscursor.h" #include <qpa/qplatformwindow.h> @@ -145,28 +144,18 @@ public: ~QWindowsWindow(); QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_format; } - void setGeometryDp(const QRect &rectIn); - void setGeometry(const QRect &rect) Q_DECL_OVERRIDE - { setGeometryDp(QWindowsScaling::mapToNative(rect)); } - QRect geometryDp() const { return m_data.geometry; } - QRect geometry() const Q_DECL_OVERRIDE - { return QWindowsScaling::mapFromNative(geometryDp()); } - QRect normalGeometryDp() const; - QRect normalGeometry() const Q_DECL_OVERRIDE - { return QWindowsScaling::mapFromNative(normalGeometryDp()); } - qreal devicePixelRatio() const Q_DECL_OVERRIDE - { return qreal(QWindowsScaling::factor()); } + void setGeometry(const QRect &rect) Q_DECL_OVERRIDE; + QRect geometry() const Q_DECL_OVERRIDE { return m_data.geometry; } + QRect normalGeometry() const Q_DECL_OVERRIDE; + void setVisible(bool visible) Q_DECL_OVERRIDE; bool isVisible() const; bool isExposed() const Q_DECL_OVERRIDE { return testFlag(Exposed); } bool isActive() const Q_DECL_OVERRIDE; bool isEmbedded(const QPlatformWindow *parentWindow) const Q_DECL_OVERRIDE; - QPoint mapToGlobalDp(const QPoint &pos) const; - QPoint mapToGlobal(const QPoint &pos) const Q_DECL_OVERRIDE - { return mapToGlobalDp(pos * QWindowsScaling::factor()) / QWindowsScaling::factor(); } - QPoint mapFromGlobalDp(const QPoint &pos) const; - QPoint mapFromGlobal(const QPoint &pos) const Q_DECL_OVERRIDE - { return mapFromGlobalDp(pos * QWindowsScaling::factor()) / QWindowsScaling::factor(); } + QPoint mapToGlobal(const QPoint &pos) const Q_DECL_OVERRIDE; + QPoint mapFromGlobal(const QPoint &pos) const Q_DECL_OVERRIDE; + void setWindowFlags(Qt::WindowFlags flags) Q_DECL_OVERRIDE; void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE; @@ -184,8 +173,7 @@ public: void propagateSizeHints() Q_DECL_OVERRIDE; static bool handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &marginsDp); bool handleGeometryChanging(MSG *message) const; - QMargins frameMarginsDp() const; - QMargins frameMargins() const Q_DECL_OVERRIDE { return frameMarginsDp() / QWindowsScaling::factor(); } + QMargins frameMargins() const Q_DECL_OVERRIDE; void setOpacity(qreal level) Q_DECL_OVERRIDE; void setMask(const QRegion ®ion) Q_DECL_OVERRIDE; @@ -196,7 +184,7 @@ public: bool setMouseGrabEnabled(bool grab) Q_DECL_OVERRIDE; inline bool hasMouseCapture() const { return GetCapture() == m_data.hwnd; } - bool startSystemResize(const QPoint &, Qt::Corner corner) Q_DECL_OVERRIDE; + bool startSystemResize(const QPoint &pos, Qt::Corner corner) Q_DECL_OVERRIDE; void setFrameStrutEventsEnabled(bool enabled); bool frameStrutEventsEnabled() const { return testFlag(FrameStrutEventsEnabled); } diff --git a/src/plugins/platforms/windows/windows.pri b/src/plugins/platforms/windows/windows.pri index de901aaeb1..6e5789a86e 100644 --- a/src/plugins/platforms/windows/windows.pri +++ b/src/plugins/platforms/windows/windows.pri @@ -40,7 +40,6 @@ SOURCES += \ $$PWD/qwindowsservices.cpp \ $$PWD/qwindowsnativeimage.cpp \ $$PWD/qwindowsnativeinterface.cpp \ - $$PWD/qwindowsscaling.cpp \ $$PWD/qwindowsopengltester.cpp HEADERS += \ @@ -67,7 +66,6 @@ HEADERS += \ $$PWD/qplatformfunctions_wince.h \ $$PWD/qwindowsnativeimage.h \ $$PWD/qwindowsnativeinterface.h \ - $$PWD/qwindowsscaling.h \ $$PWD/qwindowsopengltester.h INCLUDEPATH += $$PWD diff --git a/src/plugins/platforms/winrt/qwinrtcursor.cpp b/src/plugins/platforms/winrt/qwinrtcursor.cpp index 94ce23bd2c..707f3bf0ba 100644 --- a/src/plugins/platforms/winrt/qwinrtcursor.cpp +++ b/src/plugins/platforms/winrt/qwinrtcursor.cpp @@ -36,11 +36,13 @@ #include "qwinrtcursor.h" #include "qwinrtscreen.h" +#include <private/qeventdispatcher_winrt_p.h> #include <QtCore/qfunctions_winrt.h> #include <QtGui/QGuiApplication> #include <QtGui/QScreen> +#include <functional> #include <wrl.h> #include <windows.ui.core.h> #include <windows.foundation.h> @@ -77,12 +79,17 @@ void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *window) { Q_D(QWinRTCursor); + HRESULT hr; ICoreWindow *coreWindow = static_cast<QWinRTScreen *>(window->screen()->handle())->coreWindow(); CoreCursorType type; switch (windowCursor ? windowCursor->shape() : Qt::ArrowCursor) { case Qt::BlankCursor: - coreWindow->put_PointerCursor(Q_NULLPTR); + hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow]() { + coreWindow->put_PointerCursor(Q_NULLPTR); + return S_OK; + }); + RETURN_VOID_IF_FAILED("Failed to set blank native cursor"); return; default: case Qt::OpenHandCursor: @@ -142,11 +149,13 @@ void QWinRTCursor::changeCursor(QCursor *windowCursor, QWindow *window) } ComPtr<ICoreCursor> cursor; - HRESULT hr = d->cursorFactory->CreateCursor(type, 0, &cursor); + hr = d->cursorFactory->CreateCursor(type, 0, &cursor); RETURN_VOID_IF_FAILED("Failed to create native cursor."); - hr = coreWindow->put_PointerCursor(cursor.Get()); - RETURN_VOID_IF_FAILED("Failed to set native cursor."); + hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow, &cursor]() { + return coreWindow->put_PointerCursor(cursor.Get()); + }); + RETURN_VOID_IF_FAILED("Failed to set native cursor"); } #endif // QT_NO_CURSOR @@ -154,8 +163,12 @@ QPoint QWinRTCursor::pos() const { ICoreWindow *coreWindow = static_cast<QWinRTScreen *>(QGuiApplication::primaryScreen()->handle())->coreWindow(); + HRESULT hr; Point point; - coreWindow->get_PointerPosition(&point); + hr = QEventDispatcherWinRT::runOnXamlThread([coreWindow, &point]() { + return coreWindow->get_PointerPosition(&point); + }); + RETURN_IF_FAILED("Failed to get native cursor position", QPoint()); return QPoint(point.X, point.Y); } diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.cpp b/src/plugins/platforms/winrt/qwinrteglcontext.cpp index 42ffe8f716..44aab266ca 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.cpp +++ b/src/plugins/platforms/winrt/qwinrteglcontext.cpp @@ -35,38 +35,131 @@ ****************************************************************************/ #include "qwinrteglcontext.h" +#include "qwinrtwindow.h" +#include <private/qeventdispatcher_winrt_p.h> +#include <functional> + +#include <EGL/egl.h> #define EGL_EGLEXT_PROTOTYPES -#include "EGL/eglext.h" +#include <EGL/eglext.h> + +#include <QOpenGLContext> +#include <QtPlatformSupport/private/qeglconvenience_p.h> QT_BEGIN_NAMESPACE -QWinRTEGLContext::QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface, EGLConfig config) - : QEGLPlatformContext(format, share, display, &config), m_eglSurface(surface) +class QWinRTEGLContextPrivate +{ +public: + QSurfaceFormat format; + EGLDisplay eglDisplay; + EGLConfig eglConfig; + EGLContext eglContext; + QHash<QPlatformSurface *, EGLSurface> surfaceForWindow; +}; + +QWinRTEGLContext::QWinRTEGLContext(QOpenGLContext *context) + : d_ptr(new QWinRTEGLContextPrivate) +{ + Q_D(QWinRTEGLContext); + d->format = context->format(); + d->format.setRenderableType(QSurfaceFormat::OpenGLES); +} + +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) + eglTerminate(d->eglDisplay); } -void QWinRTEGLContext::swapBuffers(QPlatformSurface *surface) +void QWinRTEGLContext::initialize() { -#ifdef Q_OS_WINPHONE - const QSize size = surface->surface()->size(); - eglPostSubBufferNV(eglDisplay(), eglSurfaceForPlatformSurface(surface), - 0, 0, size.width(), size.height()); -#else - eglSwapBuffers(eglDisplay(), eglSurfaceForPlatformSurface(surface)); -#endif + Q_D(QWinRTEGLContext); + + eglBindAPI(EGL_OPENGL_ES_API); + d->eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (d->eglDisplay == EGL_NO_DISPLAY) + qCritical("Failed to initialize EGL display: 0x%x", eglGetError()); + + if (!eglInitialize(d->eglDisplay, nullptr, nullptr)) + qCritical("Failed to initialize EGL: 0x%x", eglGetError()); + + d->eglConfig = q_configFromGLFormat(d->eglDisplay, d->format); + + const EGLint flags = d->format.testOption(QSurfaceFormat::DebugContext) + ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0; + const EGLint attributes[] = { + EGL_CONTEXT_CLIENT_VERSION, d->format.majorVersion(), + EGL_CONTEXT_MINOR_VERSION_KHR, d->format.minorVersion(), + EGL_CONTEXT_FLAGS_KHR, flags, + EGL_NONE + }; + d->eglContext = eglCreateContext(d->eglDisplay, d->eglConfig, nullptr, attributes); + if (d->eglContext == EGL_NO_CONTEXT) { + qWarning("QEGLPlatformContext: Failed to create context: %x", eglGetError()); + return; + } } -EGLSurface QWinRTEGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) +bool QWinRTEGLContext::makeCurrent(QPlatformSurface *windowSurface) { - if (surface->surface()->surfaceClass() == QSurface::Window) { - // All windows use the same surface - return m_eglSurface; - } else { - // TODO: return EGL surfaces for offscreen surfaces - qWarning("This plugin does not support offscreen surfaces."); - return EGL_NO_SURFACE; + 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); } + + const bool ok = eglMakeCurrent(d->eglDisplay, surface, surface, d->eglContext); + if (!ok) { + qWarning("QEGLPlatformContext: eglMakeCurrent failed: %x", eglGetError()); + return false; + } + + eglSwapInterval(d->eglDisplay, d->format.swapInterval()); + return true; +} + +void QWinRTEGLContext::doneCurrent() +{ + Q_D(const QWinRTEGLContext); + const bool ok = eglMakeCurrent(d->eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (!ok) + qWarning("QEGLPlatformContext: eglMakeCurrent failed: %x", eglGetError()); +} + +void QWinRTEGLContext::swapBuffers(QPlatformSurface *windowSurface) +{ + Q_D(QWinRTEGLContext); + Q_ASSERT(windowSurface->surface()->surfaceType() == QSurface::OpenGLSurface); + + eglSwapBuffers(d->eglDisplay, d->surfaceForWindow.value(windowSurface)); +} + +QSurfaceFormat QWinRTEGLContext::format() const +{ + Q_D(const QWinRTEGLContext); + return d->format; } QFunctionPointer QWinRTEGLContext::getProcAddress(const QByteArray &procName) @@ -221,7 +314,7 @@ QFunctionPointer QWinRTEGLContext::getProcAddress(const QByteArray &procName) if (i != standardFuncs.end()) return i.value(); - return QEGLPlatformContext::getProcAddress(procName); + return eglGetProcAddress(procName.constData()); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrteglcontext.h b/src/plugins/platforms/winrt/qwinrteglcontext.h index 958d623c4c..31a2124b03 100644 --- a/src/plugins/platforms/winrt/qwinrteglcontext.h +++ b/src/plugins/platforms/winrt/qwinrteglcontext.h @@ -37,23 +37,29 @@ #ifndef QWINDOWSEGLCONTEXT_H #define QWINDOWSEGLCONTEXT_H -#include <QtPlatformSupport/private/qeglplatformcontext_p.h> +#include <qpa/qplatformopenglcontext.h> QT_BEGIN_NAMESPACE -class QWinRTEGLContext : public QEGLPlatformContext +class QWinRTEGLContextPrivate; +class QWinRTEGLContext : public QPlatformOpenGLContext { public: - explicit QWinRTEGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display, EGLSurface surface, EGLConfig config); + explicit QWinRTEGLContext(QOpenGLContext *context); + ~QWinRTEGLContext(); - void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; - QFunctionPointer getProcAddress(const QByteArray &procName) Q_DECL_OVERRIDE; + void initialize() Q_DECL_OVERRIDE; + + bool makeCurrent(QPlatformSurface *windowSurface) Q_DECL_OVERRIDE; + void doneCurrent() Q_DECL_OVERRIDE; + void swapBuffers(QPlatformSurface *windowSurface) Q_DECL_OVERRIDE; -protected: - EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface); + QSurfaceFormat format() const Q_DECL_OVERRIDE; + QFunctionPointer getProcAddress(const QByteArray &procName) Q_DECL_OVERRIDE; private: - EGLSurface m_eglSurface; + QScopedPointer<QWinRTEGLContextPrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTEGLContext) }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp b/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp index 09edea52e7..c348faf015 100644 --- a/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp +++ b/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp @@ -39,13 +39,11 @@ #include <QtCore/QCoreApplication> #include <QtCore/QFile> -#ifdef QT_WINRT_USE_DWRITE #include <QtCore/QUuid> #include <QtGui/private/qfontengine_ft_p.h> #include <dwrite_1.h> #include <wrl.h> using namespace Microsoft::WRL; -#endif // QT_WINRT_USE_DWRITE QT_BEGIN_NAMESPACE @@ -122,9 +120,7 @@ QString QWinRTFontDatabase::fontDir() const const QString applicationDirPath = QCoreApplication::applicationDirPath(); fontDirectory = applicationDirPath + QLatin1String("/fonts"); if (!QFile::exists(fontDirectory)) { -#ifdef QT_WINRT_USE_DWRITE if (m_fontFamilies.isEmpty()) -#endif qWarning("No fonts directory found in application package."); fontDirectory = applicationDirPath; } @@ -132,8 +128,6 @@ QString QWinRTFontDatabase::fontDir() const return fontDirectory; } -#ifdef QT_WINRT_USE_DWRITE - QWinRTFontDatabase::~QWinRTFontDatabase() { foreach (IDWriteFontFile *fontFile, m_fonts.keys()) @@ -449,13 +443,4 @@ void QWinRTFontDatabase::releaseHandle(void *handle) QBasicFontDatabase::releaseHandle(handle); } -#else // QT_WINRT_USE_DWRITE - -QFont QWinRTFontDatabase::defaultFont() const -{ - return QFont(QFontDatabase().families().value(0)); -} - -#endif // !QT_WINRT_USE_DWRITE - QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtfontdatabase.h b/src/plugins/platforms/winrt/qwinrtfontdatabase.h index 7b3f402c13..a88092e432 100644 --- a/src/plugins/platforms/winrt/qwinrtfontdatabase.h +++ b/src/plugins/platforms/winrt/qwinrtfontdatabase.h @@ -39,26 +39,21 @@ #include <QtPlatformSupport/private/qbasicfontdatabase_p.h> -#ifdef QT_WINRT_USE_DWRITE struct IDWriteFontFile; struct IDWriteFontFamily; -#endif QT_BEGIN_NAMESPACE -#ifdef QT_WINRT_USE_DWRITE struct FontDescription { quint32 index; QByteArray uuid; }; -#endif class QWinRTFontDatabase : public QBasicFontDatabase { public: QString fontDir() const; -#ifdef QT_WINRT_USE_DWRITE ~QWinRTFontDatabase(); QFont defaultFont() const Q_DECL_OVERRIDE; bool fontsAlwaysScalable() const Q_DECL_OVERRIDE; @@ -69,7 +64,6 @@ public: private: QHash<IDWriteFontFile *, FontDescription> m_fonts; QHash<QString, IDWriteFontFamily *> m_fontFamilies; -#endif // QT_WINRT_USE_DWRITE }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.cpp b/src/plugins/platforms/winrt/qwinrtinputcontext.cpp index c94b53ef1c..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,141 +182,16 @@ void QWinRTInputContext::hideInputPanel() if (FAILED(hr)) return; - boolean success; - hr = inputPane->TryHide(&success); - if (FAILED(hr)) - qErrnoWarning(hr, "Failed to hide input panel."); -} - -#else // Q_OS_WINPHONE - -// IRawElementProviderSimple -HRESULT QWinRTInputContext::get_ProviderOptions(ProviderOptions *retVal) -{ - *retVal = ProviderOptions_ServerSideProvider|ProviderOptions_UseComThreading; - return S_OK; -} - -HRESULT QWinRTInputContext::GetPatternProvider(PATTERNID id, IUnknown **retVal) -{ - switch (id) { - case 10002: //UIA_ValuePatternId - return QueryInterface(__uuidof(IValueProvider), (void**)retVal); - break; - case 10014: //UIA_TextPatternId: - return QueryInterface(__uuidof(ITextProvider), (void**)retVal); - case 10029: //UIA_TextChildPatternId: - *retVal = nullptr; - break; - default: - qWarning("Unhandled pattern ID: %d", id); - break; - } - return S_OK; -} - -HRESULT QWinRTInputContext::GetPropertyValue(PROPERTYID idProp, VARIANT *retVal) -{ - switch (idProp) { - case 30003: //UIA_ControlTypePropertyId - retVal->vt = VT_I4; - retVal->lVal = 50025; //UIA_CustomControlTypeId - break; - case 30008: //UIA_IsKeyboardFocusablePropertyId - case 30009: //UIA_HasKeyboardFocusPropertyId - // These are probably never actually called - case 30016: //UIA_IsControlElementPropertyId - case 30017: //UIA_IsContentElementPropertyId - retVal->vt = VT_BOOL; - retVal->boolVal = VARIANT_TRUE; - break; - case 30019: //UIA_IsPasswordPropertyId - retVal->vt = VT_BOOL; - retVal->boolVal = VARIANT_FALSE; - break; - case 30020: //UIA_NativeWindowHandlePropertyId - retVal->vt = VT_PTR; - retVal->punkVal = m_screen->coreWindow(); - break; - } - return S_OK; -} - -HRESULT QWinRTInputContext::get_HostRawElementProvider(IRawElementProviderSimple **retVal) -{ - // Return the window's element provider - IInspectable *hostProvider; - HRESULT hr = m_screen->coreWindow()->get_AutomationHostProvider(&hostProvider); - if (SUCCEEDED(hr)) { - hr = hostProvider->QueryInterface(IID_PPV_ARGS(retVal)); - hostProvider->Release(); - } - return hr; -} - -// ITextProvider -HRESULT QWinRTInputContext::GetSelection(SAFEARRAY **) -{ - // To be useful, requires listening to the focus object for a selection change and raising an event - return S_OK; -} - -HRESULT QWinRTInputContext::GetVisibleRanges(SAFEARRAY **) -{ - // To be useful, requires listening to the focus object for a selection change and raising an event - return S_OK; -} - -HRESULT QWinRTInputContext::RangeFromChild(IRawElementProviderSimple *,ITextRangeProvider **) -{ - // To be useful, requires listening to the focus object for a selection change and raising an event - return S_OK; -} - -HRESULT QWinRTInputContext::RangeFromPoint(UiaPoint, ITextRangeProvider **) -{ - // To be useful, requires listening to the focus object for a selection change and raising an event - return S_OK; -} - -HRESULT QWinRTInputContext::get_DocumentRange(ITextRangeProvider **) -{ - // To be useful, requires listening to the focus object for a selection change and raising an event - return S_OK; -} - -HRESULT QWinRTInputContext::get_SupportedTextSelection(SupportedTextSelection *) -{ - // To be useful, requires listening to the focus object for a selection change and raising an event - return S_OK; -} - -// IValueProvider -HRESULT QWinRTInputContext::SetValue(LPCWSTR) -{ - // To be useful, requires listening to the focus object for a value change and raising an event - // May be useful for inputPanel autocomplete, etc. - return S_OK; -} - -HRESULT QWinRTInputContext::get_Value(BSTR *) -{ - // To be useful, requires listening to the focus object for a value change and raising an event - // May be useful for inputPanel autocomplete, etc. - return S_OK; -} - -HRESULT QWinRTInputContext::get_IsReadOnly(BOOL *isReadOnly) -{ - // isReadOnly dictates keyboard opening behavior when view is tapped. - // We need to decide if the user tapped within a control which is about to receive focus... - // Since this isn't possible (this function gets called before we receive the touch event), - // the most platform-aligned option is to show the keyboard if an editable item has focus, - // and close the keyboard if it is already open. - *isReadOnly = m_isInputPanelVisible || !inputMethodAccepted(); - return S_OK; + 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 +#endif // Q_OS_WINPHONE QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtinputcontext.h b/src/plugins/platforms/winrt/qwinrtinputcontext.h index ce7fbabf49..cc3bce435f 100644 --- a/src/plugins/platforms/winrt/qwinrtinputcontext.h +++ b/src/plugins/platforms/winrt/qwinrtinputcontext.h @@ -41,9 +41,6 @@ #include <QtCore/QRectF> #include <wrl.h> -#ifndef Q_OS_WINPHONE -# include <UIAutomationCore.h> -#endif namespace ABI { namespace Windows { @@ -63,11 +60,6 @@ QT_BEGIN_NAMESPACE class QWinRTScreen; class QWinRTInputContext : public QPlatformInputContext -#ifndef Q_OS_WINPHONE - , public Microsoft::WRL::RuntimeClass< - Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::WinRtClassicComMix>, - IRawElementProviderSimple, ITextProvider, IValueProvider> -#endif // !Q_OS_WINPHONE { public: explicit QWinRTInputContext(QWinRTScreen *); @@ -79,26 +71,7 @@ public: #ifdef Q_OS_WINPHONE void showInputPanel(); void hideInputPanel(); -#else // Q_OS_WINPHONE - // IRawElementProviderSimple - HRESULT __stdcall get_ProviderOptions(ProviderOptions *retVal); - HRESULT __stdcall GetPatternProvider(PATTERNID, IUnknown **); - HRESULT __stdcall GetPropertyValue(PROPERTYID idProp, VARIANT *retVal); - HRESULT __stdcall get_HostRawElementProvider(IRawElementProviderSimple **retVal); - - // ITextProvider - HRESULT __stdcall GetSelection(SAFEARRAY **); - HRESULT __stdcall GetVisibleRanges(SAFEARRAY **); - HRESULT __stdcall RangeFromChild(IRawElementProviderSimple *,ITextRangeProvider **); - HRESULT __stdcall RangeFromPoint(UiaPoint, ITextRangeProvider **); - HRESULT __stdcall get_DocumentRange(ITextRangeProvider **); - HRESULT __stdcall get_SupportedTextSelection(SupportedTextSelection *); - - // IValueProvider - HRESULT __stdcall SetValue(LPCWSTR); - HRESULT __stdcall get_Value(BSTR *); - HRESULT __stdcall get_IsReadOnly(BOOL *); -#endif // !Q_OS_WINPHONE +#endif private: HRESULT onShowing(ABI::Windows::UI::ViewManagement::IInputPane *, diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index 70ee6dbe6a..7079d46523 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -45,37 +45,138 @@ #include "qwinrtfontdatabase.h" #include "qwinrttheme.h" +#include <QtCore/QCoreApplication> +#include <QtGui/QSurface> #include <QtGui/QOpenGLContext> +#include <qfunctions_winrt.h> +#include <functional> #include <wrl.h> +#include <windows.ui.xaml.h> +#include <windows.applicationmodel.h> +#include <windows.applicationmodel.core.h> #include <windows.ui.core.h> #include <windows.ui.viewmanagement.h> -#include <Windows.ApplicationModel.core.h> +#include <windows.graphics.display.h> +#ifdef Q_OS_WINPHONE +# include <windows.phone.ui.input.h> +#endif using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::ApplicationModel; +using namespace ABI::Windows::ApplicationModel::Core; +using namespace ABI::Windows::UI; using namespace ABI::Windows::UI::Core; using namespace ABI::Windows::UI::ViewManagement; +using namespace ABI::Windows::Graphics::Display; using namespace ABI::Windows::ApplicationModel::Core; +#ifdef Q_OS_WINPHONE +using namespace ABI::Windows::Phone::UI::Input; +#endif + +typedef IEventHandler<IInspectable *> ResumeHandler; +typedef IEventHandler<SuspendingEventArgs *> SuspendHandler; +#ifdef Q_OS_WINPHONE +typedef IEventHandler<BackPressedEventArgs*> BackPressedHandler; +#endif QT_BEGIN_NAMESPACE -QWinRTIntegration::QWinRTIntegration() - : m_success(false) - , m_fontDatabase(new QWinRTFontDatabase) - , m_services(new QWinRTServices) +typedef HRESULT (__stdcall ICoreApplication::*CoreApplicationCallbackRemover)(EventRegistrationToken); +uint qHash(CoreApplicationCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } +#ifdef Q_OS_WINPHONE +typedef HRESULT (__stdcall IHardwareButtonsStatics::*HardwareButtonsCallbackRemover)(EventRegistrationToken); +uint qHash(HardwareButtonsCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } +#endif + +class QWinRTIntegrationPrivate +{ +public: + QPlatformFontDatabase *fontDatabase; + QPlatformServices *platformServices; + QWinRTScreen *mainScreen; + QScopedPointer<QWinRTInputContext> inputContext; + + ComPtr<ICoreApplication> application; + QHash<CoreApplicationCallbackRemover, EventRegistrationToken> applicationTokens; +#ifdef Q_OS_WINPHONE + ComPtr<IHardwareButtonsStatics> hardwareButtons; + QHash<HardwareButtonsCallbackRemover, EventRegistrationToken> buttonsTokens; +#endif +}; + +QWinRTIntegration::QWinRTIntegration() : d_ptr(new QWinRTIntegrationPrivate) { - m_screen = new QWinRTScreen; - screenAdded(m_screen); + Q_D(QWinRTIntegration); + + d->fontDatabase = new QWinRTFontDatabase; + + HRESULT hr; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), + IID_PPV_ARGS(&d->application)); + Q_ASSERT_SUCCEEDED(hr); + hr = d->application->add_Suspending(Callback<SuspendHandler>(this, &QWinRTIntegration::onSuspended).Get(), + &d->applicationTokens[&ICoreApplication::remove_Resuming]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->application->add_Resuming(Callback<ResumeHandler>(this, &QWinRTIntegration::onResume).Get(), + &d->applicationTokens[&ICoreApplication::remove_Resuming]); + Q_ASSERT_SUCCEEDED(hr); - m_success = true; +#ifdef Q_OS_WINPHONE + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(), + IID_PPV_ARGS(&d->hardwareButtons)); + Q_ASSERT_SUCCEEDED(hr); + hr = d->hardwareButtons->add_BackPressed(Callback<BackPressedHandler>(this, &QWinRTIntegration::onBackButtonPressed).Get(), + &d->buttonsTokens[&IHardwareButtonsStatics::remove_BackPressed]); + Q_ASSERT_SUCCEEDED(hr); +#endif // Q_OS_WINPHONE + + hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { + HRESULT hr; + ComPtr<Xaml::IWindowStatics> windowStatics; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Window).Get(), + IID_PPV_ARGS(&windowStatics)); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<Xaml::IWindow> window; + hr = windowStatics->get_Current(&window); + Q_ASSERT_SUCCEEDED(hr); + hr = window->Activate(); + Q_ASSERT_SUCCEEDED(hr); + + d->mainScreen = new QWinRTScreen(window.Get()); + d->inputContext.reset(new QWinRTInputContext(d->mainScreen)); + screenAdded(d->mainScreen); + return S_OK; + }); + Q_ASSERT_SUCCEEDED(hr); } QWinRTIntegration::~QWinRTIntegration() { + Q_D(QWinRTIntegration); + HRESULT hr; +#ifdef Q_OS_WINPHONE + for (QHash<HardwareButtonsCallbackRemover, EventRegistrationToken>::const_iterator i = d->buttonsTokens.begin(); i != d->buttonsTokens.end(); ++i) { + hr = (d->hardwareButtons.Get()->*i.key())(i.value()); + Q_ASSERT_SUCCEEDED(hr); + } +#endif + for (QHash<CoreApplicationCallbackRemover, EventRegistrationToken>::const_iterator i = d->applicationTokens.begin(); i != d->applicationTokens.end(); ++i) { + hr = (d->application.Get()->*i.key())(i.value()); + Q_ASSERT_SUCCEEDED(hr); + } + destroyScreen(d->mainScreen); Windows::Foundation::Uninitialize(); } +bool QWinRTIntegration::succeeded() const +{ + Q_D(const QWinRTIntegration); + return d->mainScreen; +} + QAbstractEventDispatcher *QWinRTIntegration::createEventDispatcher() const { return new QWinRTEventDispatcher; @@ -112,28 +213,31 @@ QPlatformBackingStore *QWinRTIntegration::createPlatformBackingStore(QWindow *wi QPlatformOpenGLContext *QWinRTIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { - QWinRTScreen *screen = static_cast<QWinRTScreen *>(context->screen()->handle()); - return new QWinRTEGLContext(context->format(), context->handle(), screen->eglDisplay(), screen->eglSurface(), screen->eglConfig()); + return new QWinRTEGLContext(context); } QPlatformFontDatabase *QWinRTIntegration::fontDatabase() const { - return m_fontDatabase; + Q_D(const QWinRTIntegration); + return d->fontDatabase; } QPlatformInputContext *QWinRTIntegration::inputContext() const { - return m_screen->inputContext(); + Q_D(const QWinRTIntegration); + return d->inputContext.data(); } QPlatformServices *QWinRTIntegration::services() const { - return m_services; + Q_D(const QWinRTIntegration); + return d->platformServices; } Qt::KeyboardModifiers QWinRTIntegration::queryKeyboardModifiers() const { - return m_screen->keyboardModifiers(); + Q_D(const QWinRTIntegration); + return d->mainScreen->keyboardModifiers(); } QStringList QWinRTIntegration::themeNames() const @@ -149,4 +253,45 @@ name) const return 0; } + +// System-level integration points + +#ifdef Q_OS_WINPHONE +HRESULT QWinRTIntegration::onBackButtonPressed(IInspectable *, IBackPressedEventArgs *args) +{ + Q_D(QWinRTIntegration); + + QKeyEvent backPress(QEvent::KeyPress, Qt::Key_Back, Qt::NoModifier); + QKeyEvent backRelease(QEvent::KeyRelease, Qt::Key_Back, Qt::NoModifier); + backPress.setAccepted(false); + backRelease.setAccepted(false); + + QWindow *window = d->mainScreen->topWindow(); + QObject *receiver = window ? static_cast<QObject *>(window) + : static_cast<QObject *>(QCoreApplication::instance()); + + // If the event is ignored, the app go to the background + QCoreApplication::sendEvent(receiver, &backPress); + QCoreApplication::sendEvent(receiver, &backRelease); + args->put_Handled(backPress.isAccepted() || backRelease.isAccepted()); + + return S_OK; +} +#endif // Q_OS_WINPHONE + +HRESULT QWinRTIntegration::onSuspended(IInspectable *, ISuspendingEventArgs *) +{ + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended); + QWindowSystemInterface::flushWindowSystemEvents(); + return S_OK; +} + +HRESULT QWinRTIntegration::onResume(IInspectable *, IInspectable *) +{ + // First the system invokes onResume and then changes + // the visibility of the screen to be active. + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationHidden); + return S_OK; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtintegration.h b/src/plugins/platforms/winrt/qwinrtintegration.h index bbd6c1e41b..0115e034b5 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.h +++ b/src/plugins/platforms/winrt/qwinrtintegration.h @@ -39,11 +39,33 @@ #include <qpa/qplatformintegration.h> +namespace ABI { + namespace Windows { + namespace ApplicationModel { + struct ISuspendingEventArgs; + } + namespace Foundation { + struct IAsyncAction; + } +#ifdef Q_OS_WINPHONE + namespace Phone { + namespace UI { + namespace Input { + struct IBackPressedEventArgs; + } + } + } +#endif + } +} +struct IAsyncInfo; +struct IInspectable; + QT_BEGIN_NAMESPACE class QAbstractEventDispatcher; -class QWinRTScreen; +class QWinRTIntegrationPrivate; class QWinRTIntegration : public QPlatformIntegration { private: @@ -53,10 +75,12 @@ public: static QWinRTIntegration *create() { - QWinRTIntegration *integration = new QWinRTIntegration; - return integration->m_success ? integration : 0; + QScopedPointer<QWinRTIntegration> integration(new QWinRTIntegration); + return integration->succeeded() ? integration.take() : nullptr; } + bool succeeded() const; + bool hasCapability(QPlatformIntegration::Capability cap) const; QVariant styleHint(StyleHint hint) const; @@ -71,11 +95,16 @@ public: QStringList themeNames() const; QPlatformTheme *createPlatformTheme(const QString &name) const; + private: - bool m_success; - QWinRTScreen *m_screen; - QPlatformFontDatabase *m_fontDatabase; - QPlatformServices *m_services; +#ifdef Q_OS_WINPHONE + HRESULT onBackButtonPressed(IInspectable *, ABI::Windows::Phone::UI::Input::IBackPressedEventArgs *args); +#endif + HRESULT onSuspended(IInspectable *, ABI::Windows::ApplicationModel::ISuspendingEventArgs *); + HRESULT onResume(IInspectable *, IInspectable *); + + QScopedPointer<QWinRTIntegrationPrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTIntegration) }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index 1d36bb31f6..2a7cbaa159 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -36,26 +36,18 @@ #include "qwinrtscreen.h" -#define EGL_EGLEXT_PROTOTYPES -#include <EGL/eglext.h> -#include <d3d11.h> -#include <dxgi1_2.h> -#ifndef Q_OS_WINPHONE -#include <dxgi1_3.h> -#endif - #include "qwinrtbackingstore.h" #include "qwinrtinputcontext.h" #include "qwinrtcursor.h" -#include "qwinrteglcontext.h" +#include <private/qeventdispatcher_winrt_p.h> #include <QtGui/QSurfaceFormat> #include <QtGui/QGuiApplication> -#include <QtPlatformSupport/private/qeglconvenience_p.h> #include <qpa/qwindowsysteminterface.h> #include <QtCore/qt_windows.h> #include <QtCore/qfunctions_winrt.h> +#include <functional> #include <wrl.h> #include <windows.system.h> #include <Windows.Applicationmodel.h> @@ -64,12 +56,10 @@ #include <windows.ui.h> #include <windows.ui.core.h> #include <windows.ui.input.h> +#include <windows.ui.xaml.h> #include <windows.ui.viewmanagement.h> #include <windows.graphics.display.h> #include <windows.foundation.h> -#ifdef Q_OS_WINPHONE -#include <windows.phone.ui.input.h> -#endif using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; @@ -77,17 +67,13 @@ using namespace ABI::Windows::ApplicationModel; using namespace ABI::Windows::ApplicationModel::Core; using namespace ABI::Windows::Foundation; using namespace ABI::Windows::System; +using namespace ABI::Windows::UI; using namespace ABI::Windows::UI::Core; using namespace ABI::Windows::UI::Input; using namespace ABI::Windows::UI::ViewManagement; using namespace ABI::Windows::Devices::Input; using namespace ABI::Windows::Graphics::Display; -#ifdef Q_OS_WINPHONE -using namespace ABI::Windows::Phone::UI::Input; -#endif -typedef IEventHandler<IInspectable*> ResumeHandler; -typedef IEventHandler<SuspendingEventArgs*> SuspendHandler; typedef ITypedEventHandler<CoreWindow*, WindowActivatedEventArgs*> ActivatedHandler; typedef ITypedEventHandler<CoreWindow*, CoreWindowEventArgs*> ClosedHandler; typedef ITypedEventHandler<CoreWindow*, CharacterReceivedEventArgs*> CharacterReceivedHandler; @@ -96,11 +82,7 @@ typedef ITypedEventHandler<CoreWindow*, KeyEventArgs*> KeyHandler; typedef ITypedEventHandler<CoreWindow*, PointerEventArgs*> PointerHandler; typedef ITypedEventHandler<CoreWindow*, WindowSizeChangedEventArgs*> SizeChangedHandler; typedef ITypedEventHandler<CoreWindow*, VisibilityChangedEventArgs*> VisibilityChangedHandler; -typedef ITypedEventHandler<CoreWindow*, AutomationProviderRequestedEventArgs*> AutomationProviderRequestedHandler; typedef ITypedEventHandler<DisplayInformation*, IInspectable*> DisplayInformationHandler; -#ifdef Q_OS_WINPHONE -typedef IEventHandler<BackPressedEventArgs*> BackPressedHandler; -#endif QT_BEGIN_NAMESPACE @@ -419,33 +401,26 @@ static inline Qt::Key qKeyFromCode(quint32 code, int mods) return static_cast<Qt::Key>(code & 0xff); } -typedef HRESULT (__stdcall ICoreApplication::*CoreApplicationCallbackRemover)(EventRegistrationToken); -uint qHash(CoreApplicationCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } typedef HRESULT (__stdcall ICoreWindow::*CoreWindowCallbackRemover)(EventRegistrationToken); 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 IHardwareButtonsStatics::*HardwareButtonsCallbackRemover)(EventRegistrationToken); -uint qHash(HardwareButtonsCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } -#endif class QWinRTScreenPrivate { public: - ComPtr<ICoreApplication> application; + QTouchDevice *touchDevice; ComPtr<ICoreWindow> coreWindow; + ComPtr<Xaml::IDependencyObject> canvas; + ComPtr<IApplicationView> view; ComPtr<IDisplayInformation> displayInformation; #ifdef Q_OS_WINPHONE - ComPtr<IHardwareButtonsStatics> hardwareButtons; -#endif + ComPtr<IStatusBar> statusBar; +#endif // Q_OS_WINPHONE QScopedPointer<QWinRTCursor> cursor; -#ifdef Q_OS_WINPHONE - QScopedPointer<QWinRTInputContext> inputContext; -#else - ComPtr<QWinRTInputContext> inputContext; -#endif + + QHash<quint32, QWindowSystemInterface::TouchPoint> touchPoints; QSizeF logicalSize; QSurfaceFormat surfaceFormat; @@ -458,68 +433,30 @@ public: #ifndef Q_OS_WINPHONE QHash<quint32, QPair<Qt::Key, QString>> activeKeys; #endif - QTouchDevice *touchDevice; - QHash<quint32, QWindowSystemInterface::TouchPoint> touchPoints; - EGLDisplay eglDisplay; - EGLSurface eglSurface; - EGLConfig eglConfig; - - QHash<CoreApplicationCallbackRemover, EventRegistrationToken> applicationTokens; QHash<CoreWindowCallbackRemover, EventRegistrationToken> windowTokens; QHash<DisplayCallbackRemover, EventRegistrationToken> displayTokens; -#ifdef Q_OS_WINPHONE - QHash<HardwareButtonsCallbackRemover, EventRegistrationToken> buttonsTokens; -#endif }; -QWinRTScreen::QWinRTScreen() +// To be called from the XAML thread +QWinRTScreen::QWinRTScreen(Xaml::IWindow *xamlWindow) : d_ptr(new QWinRTScreenPrivate) { Q_D(QWinRTScreen); d->orientation = Qt::PrimaryOrientation; d->touchDevice = Q_NULLPTR; - d->eglDisplay = EGL_NO_DISPLAY; - // Obtain the WinRT Application, view, and window HRESULT hr; - hr = RoGetActivationFactory(Wrappers::HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), - IID_PPV_ARGS(&d->application)); - Q_ASSERT_SUCCEEDED(hr); - hr = d->application->add_Suspending(Callback<SuspendHandler>(this, &QWinRTScreen::onSuspended).Get(), &d->applicationTokens[&ICoreApplication::remove_Resuming]); - Q_ASSERT_SUCCEEDED(hr); - hr = d->application->add_Resuming(Callback<ResumeHandler>(this, &QWinRTScreen::onResume).Get(), &d->applicationTokens[&ICoreApplication::remove_Resuming]); - Q_ASSERT_SUCCEEDED(hr); - - ComPtr<ICoreApplicationView> view; - hr = d->application->GetCurrentView(&view); - Q_ASSERT_SUCCEEDED(hr); - hr = view->get_CoreWindow(&d->coreWindow); + hr = xamlWindow->get_CoreWindow(&d->coreWindow); Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->Activate(); Q_ASSERT_SUCCEEDED(hr); -#ifdef Q_OS_WINPHONE - d->inputContext.reset(new QWinRTInputContext(this)); -#else - d->inputContext = Make<QWinRTInputContext>(this); -#endif - Rect rect; hr = d->coreWindow->get_Bounds(&rect); Q_ASSERT_SUCCEEDED(hr); d->logicalSize = QSizeF(rect.Width, rect.Height); - d->surfaceFormat.setAlphaBufferSize(0); - d->surfaceFormat.setRedBufferSize(8); - d->surfaceFormat.setGreenBufferSize(8); - d->surfaceFormat.setBlueBufferSize(8); - d->surfaceFormat.setDepthBufferSize(24); - d->surfaceFormat.setStencilBufferSize(8); - d->surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES); - d->surfaceFormat.setSamples(1); - d->surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); - hr = d->coreWindow->add_KeyDown(Callback<KeyHandler>(this, &QWinRTScreen::onKeyDown).Get(), &d->windowTokens[&ICoreWindow::remove_KeyDown]); Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->add_KeyUp(Callback<KeyHandler>(this, &QWinRTScreen::onKeyUp).Get(), &d->windowTokens[&ICoreWindow::remove_KeyUp]); @@ -538,24 +475,14 @@ QWinRTScreen::QWinRTScreen() 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]); Q_ASSERT_SUCCEEDED(hr); hr = d->coreWindow->add_VisibilityChanged(Callback<VisibilityChangedHandler>(this, &QWinRTScreen::onVisibilityChanged).Get(), &d->windowTokens[&ICoreWindow::remove_VisibilityChanged]); Q_ASSERT_SUCCEEDED(hr); - hr = d->coreWindow->add_AutomationProviderRequested(Callback<AutomationProviderRequestedHandler>(this, &QWinRTScreen::onAutomationProviderRequested).Get(), &d->windowTokens[&ICoreWindow::remove_AutomationProviderRequested]); - Q_ASSERT_SUCCEEDED(hr); -#ifdef Q_OS_WINPHONE - hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(), IID_PPV_ARGS(&d->hardwareButtons)); - Q_ASSERT_SUCCEEDED(hr); - hr = d->hardwareButtons->add_BackPressed(Callback<BackPressedHandler>(this, &QWinRTScreen::onBackButtonPressed).Get(), &d->buttonsTokens[&IHardwareButtonsStatics::remove_BackPressed]); - Q_ASSERT_SUCCEEDED(hr); -#endif // Q_OS_WINPHONE // Orientation handling ComPtr<IDisplayInformationStatics> displayInformationStatics; @@ -583,45 +510,43 @@ QWinRTScreen::QWinRTScreen() d->orientation = d->nativeOrientation; onOrientationChanged(Q_NULLPTR, Q_NULLPTR); - d->eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (d->eglDisplay == EGL_NO_DISPLAY) - qCritical("Failed to initialize EGL display: 0x%x", eglGetError()); - - if (!eglInitialize(d->eglDisplay, NULL, NULL)) - qCritical("Failed to initialize EGL: 0x%x", eglGetError()); - - // Check that the device properly supports depth/stencil rendering, and disable them if not - ComPtr<ID3D11Device> d3dDevice; - const EGLBoolean ok = eglQuerySurfacePointerANGLE(d->eglDisplay, EGL_NO_SURFACE, EGL_DEVICE_EXT, (void **)d3dDevice.GetAddressOf()); - if (ok && d3dDevice) { - ComPtr<IDXGIDevice> dxgiDevice; - hr = d3dDevice.As(&dxgiDevice); - if (SUCCEEDED(hr)) { - ComPtr<IDXGIAdapter> dxgiAdapter; - hr = dxgiDevice->GetAdapter(&dxgiAdapter); - if (SUCCEEDED(hr)) { - ComPtr<IDXGIAdapter2> dxgiAdapter2; - hr = dxgiAdapter.As(&dxgiAdapter2); - if (SUCCEEDED(hr)) { - DXGI_ADAPTER_DESC2 desc; - hr = dxgiAdapter2->GetDesc2(&desc); - if (SUCCEEDED(hr)) { - // The following GPUs do not render properly with depth/stencil - if ((desc.VendorId == 0x4d4f4351 && desc.DeviceId == 0x32303032)) { // Qualcomm Adreno 225 - d->surfaceFormat.setDepthBufferSize(-1); - d->surfaceFormat.setStencilBufferSize(-1); - } - } - } - } - } - } + ComPtr<IApplicationViewStatics2> applicationViewStatics; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_ApplicationView).Get(), + IID_PPV_ARGS(&applicationViewStatics)); + RETURN_VOID_IF_FAILED("Could not get ApplicationViewStatics"); + + hr = applicationViewStatics->GetForCurrentView(&d->view); + RETURN_VOID_IF_FAILED("Could not access currentView"); + + // Create a canvas and set it as the window content. Eventually, this should have its own method so multiple "screens" can be added + ComPtr<Xaml::Controls::ICanvas> canvas; + hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_UI_Xaml_Controls_Canvas).Get(), &canvas); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<Xaml::IFrameworkElement> frameworkElement; + hr = canvas.As(&frameworkElement); + Q_ASSERT_SUCCEEDED(hr); + hr = frameworkElement->put_Width(d->logicalSize.width()); + Q_ASSERT_SUCCEEDED(hr); + hr = frameworkElement->put_Height(d->logicalSize.height()); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<Xaml::IUIElement> uiElement; + hr = canvas.As(&uiElement); + Q_ASSERT_SUCCEEDED(hr); + hr = xamlWindow->put_Content(uiElement.Get()); + Q_ASSERT_SUCCEEDED(hr); + hr = canvas.As(&d->canvas); + Q_ASSERT_SUCCEEDED(hr); + + d->cursor.reset(new QWinRTCursor); - d->eglConfig = q_configFromGLFormat(d->eglDisplay, d->surfaceFormat); - d->surfaceFormat = q_glFormatFromConfig(d->eglDisplay, d->eglConfig, d->surfaceFormat); - d->eglSurface = eglCreateWindowSurface(d->eglDisplay, d->eglConfig, d->coreWindow.Get(), NULL); - if (d->eglSurface == EGL_NO_SURFACE) - qCritical("Failed to create EGL window surface: 0x%x", eglGetError()); +#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); +#endif // Q_OS_WINPHONE } QWinRTScreen::~QWinRTScreen() @@ -629,16 +554,20 @@ QWinRTScreen::~QWinRTScreen() Q_D(QWinRTScreen); // Unregister callbacks - for (QHash<CoreApplicationCallbackRemover, EventRegistrationToken>::const_iterator i = d->applicationTokens.begin(); i != d->applicationTokens.end(); ++i) - (d->application.Get()->*i.key())(i.value()); - for (QHash<CoreWindowCallbackRemover, EventRegistrationToken>::const_iterator i = d->windowTokens.begin(); i != d->windowTokens.end(); ++i) - (d->coreWindow.Get()->*i.key())(i.value()); - for (QHash<DisplayCallbackRemover, EventRegistrationToken>::const_iterator i = d->displayTokens.begin(); i != d->displayTokens.end(); ++i) - (d->displayInformation.Get()->*i.key())(i.value()); -#ifdef Q_OS_WINPHONE - for (QHash<HardwareButtonsCallbackRemover, EventRegistrationToken>::const_iterator i = d->buttonsTokens.begin(); i != d->buttonsTokens.end(); ++i) - (d->hardwareButtons.Get()->*i.key())(i.value()); -#endif + HRESULT hr; + hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { + HRESULT hr; + for (QHash<CoreWindowCallbackRemover, EventRegistrationToken>::const_iterator i = d->windowTokens.begin(); i != d->windowTokens.end(); ++i) { + hr = (d->coreWindow.Get()->*i.key())(i.value()); + Q_ASSERT_SUCCEEDED(hr); + } + for (QHash<DisplayCallbackRemover, EventRegistrationToken>::const_iterator i = d->displayTokens.begin(); i != d->displayTokens.end(); ++i) { + hr = (d->displayInformation.Get()->*i.key())(i.value()); + Q_ASSERT_SUCCEEDED(hr); + } + return hr; + }); + RETURN_VOID_IF_FAILED("Failed to unregister screen event callbacks"); } QRect QWinRTScreen::geometry() const @@ -657,12 +586,6 @@ QImage::Format QWinRTScreen::format() const return QImage::Format_ARGB32_Premultiplied; } -QSurfaceFormat QWinRTScreen::surfaceFormat() const -{ - Q_D(const QWinRTScreen); - return d->surfaceFormat; -} - QSizeF QWinRTScreen::physicalSize() const { Q_D(const QWinRTScreen); @@ -682,21 +605,9 @@ qreal QWinRTScreen::scaleFactor() const return d->scaleFactor; } -QWinRTInputContext *QWinRTScreen::inputContext() const -{ - Q_D(const QWinRTScreen); -#ifdef Q_OS_WINPHONE - return d->inputContext.data(); -#else - return d->inputContext.Get(); -#endif -} - QPlatformCursor *QWinRTScreen::cursor() const { Q_D(const QWinRTScreen); - if (!d->cursor) - const_cast<QWinRTScreenPrivate *>(d)->cursor.reset(new QWinRTCursor); return d->cursor.data(); } @@ -744,22 +655,10 @@ ICoreWindow *QWinRTScreen::coreWindow() const return d->coreWindow.Get(); } -EGLDisplay QWinRTScreen::eglDisplay() const +Xaml::IDependencyObject *QWinRTScreen::canvas() const { Q_D(const QWinRTScreen); - return d->eglDisplay; -} - -EGLSurface QWinRTScreen::eglSurface() const -{ - Q_D(const QWinRTScreen); - return d->eglSurface; -} - -EGLConfig QWinRTScreen::eglConfig() const -{ - Q_D(const QWinRTScreen); - return d->eglConfig; + return d->canvas.Get(); } QWindow *QWinRTScreen::topWindow() const @@ -773,6 +672,19 @@ void QWinRTScreen::addWindow(QWindow *window) Q_D(QWinRTScreen); if (window == topWindow()) return; + +#ifdef Q_OS_WINPHONE + if (d->statusBar && (window->flags() & Qt::WindowType_Mask) == Qt::Window) { + QEventDispatcherWinRT::runOnXamlThread([this, d]() { + HRESULT hr; + ComPtr<IAsyncAction> op; + hr = d->statusBar->HideAsync(&op); + Q_ASSERT_SUCCEEDED(hr); + return S_OK; + }); + } +#endif // Q_OS_WINPHONE + d->visibleWindows.prepend(window); QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); handleExpose(); @@ -809,6 +721,20 @@ void QWinRTScreen::lower(QWindow *window) handleExpose(); } +void QWinRTScreen::updateWindowTitle() +{ + Q_D(QWinRTScreen); + + QWindow *window = topWindow(); + if (!window) + return; + + const QString title = window->title(); + HStringReference titleRef(reinterpret_cast<LPCWSTR>(title.utf16()), title.length()); + HRESULT hr = d->view->put_Title(titleRef.Get()); + RETURN_VOID_IF_FAILED("Unable to set window title"); +} + void QWinRTScreen::handleExpose() { Q_D(QWinRTScreen); @@ -1055,17 +981,6 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) return S_OK; } -HRESULT QWinRTScreen::onAutomationProviderRequested(ICoreWindow *, IAutomationProviderRequestedEventArgs *args) -{ -#ifndef Q_OS_WINPHONE - Q_D(const QWinRTScreen); - args->put_AutomationProvider(d->inputContext.Get()); -#else - Q_UNUSED(args) -#endif - return S_OK; -} - HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs *) { Q_D(QWinRTScreen); @@ -1075,18 +990,14 @@ HRESULT QWinRTScreen::onSizeChanged(ICoreWindow *, IWindowSizeChangedEventArgs * hr = d->coreWindow->get_Bounds(&size); RETURN_OK_IF_FAILED("Failed to get window bounds"); QSizeF logicalSize = QSizeF(size.Width, size.Height); -#ifndef Q_OS_WINPHONE // This handler is called from orientation changed, in which case we should always update the size if (d->logicalSize == logicalSize) return S_OK; -#endif d->logicalSize = logicalSize; - if (d->eglDisplay) { - const QRect newGeometry = geometry(); - QWindowSystemInterface::handleScreenGeometryChange(screen(), newGeometry, newGeometry); - QPlatformScreen::resizeMaximizedWindows(); - handleExpose(); - } + const QRect newGeometry = geometry(); + QWindowSystemInterface::handleScreenGeometryChange(screen(), newGeometry, newGeometry); + QPlatformScreen::resizeMaximizedWindows(); + handleExpose(); return S_OK; } @@ -1110,31 +1021,6 @@ HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args return S_OK; } -HRESULT QWinRTScreen::onSuspended(IInspectable *, ISuspendingEventArgs *) -{ -#ifndef Q_OS_WINPHONE - Q_D(QWinRTScreen); - ComPtr<ID3D11Device> d3dDevice; - const EGLBoolean ok = eglQuerySurfacePointerANGLE(d->eglDisplay, EGL_NO_SURFACE, EGL_DEVICE_EXT, (void **)d3dDevice.GetAddressOf()); - if (ok && d3dDevice) { - ComPtr<IDXGIDevice3> dxgiDevice; - if (SUCCEEDED(d3dDevice.As(&dxgiDevice))) - dxgiDevice->Trim(); - } -#endif - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended); - QWindowSystemInterface::flushWindowSystemEvents(); - return S_OK; -} - -HRESULT QWinRTScreen::onResume(IInspectable *, IInspectable *) -{ - // First the system invokes onResume and then changes - // the visibility of the screen to be active. - QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationHidden); - return S_OK; -} - HRESULT QWinRTScreen::onClosed(ICoreWindow *, ICoreWindowEventArgs *) { foreach (QWindow *w, QGuiApplication::topLevelWindows()) @@ -1165,10 +1051,6 @@ HRESULT QWinRTScreen::onOrientationChanged(IDisplayInformation *, IInspectable * d->orientation = newOrientation; QWindowSystemInterface::handleScreenOrientationChange(screen(), d->orientation); } - -#ifdef Q_OS_WINPHONE // The size changed handler is ignored in favor of this callback - onSizeChanged(Q_NULLPTR, Q_NULLPTR); -#endif return S_OK; } @@ -1205,27 +1087,4 @@ HRESULT QWinRTScreen::onDpiChanged(IDisplayInformation *, IInspectable *) return S_OK; } -#ifdef Q_OS_WINPHONE -HRESULT QWinRTScreen::onBackButtonPressed(IInspectable *, IBackPressedEventArgs *args) -{ - Q_D(QWinRTScreen); - - QKeyEvent backPress(QEvent::KeyPress, Qt::Key_Back, Qt::NoModifier); - QKeyEvent backRelease(QEvent::KeyRelease, Qt::Key_Back, Qt::NoModifier); - backPress.setAccepted(false); - backRelease.setAccepted(false); - - QObject *receiver = d->visibleWindows.isEmpty() - ? static_cast<QObject *>(QGuiApplication::instance()) - : static_cast<QObject *>(d->visibleWindows.first()); - - // If the event is ignored, the app will suspend - QGuiApplication::sendEvent(receiver, &backPress); - QGuiApplication::sendEvent(receiver, &backRelease); - args->put_Handled(backPress.isAccepted() || backRelease.isAccepted()); - - 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 d34ce75748..796e6abb80 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.h +++ b/src/plugins/platforms/winrt/qwinrtscreen.h @@ -40,8 +40,6 @@ #include <qpa/qplatformscreen.h> #include <qpa/qwindowsysteminterface.h> -#include <EGL/egl.h> - namespace ABI { namespace Windows { namespace ApplicationModel { @@ -59,21 +57,16 @@ namespace ABI { struct IWindowActivatedEventArgs; struct IWindowSizeChangedEventArgs; } + namespace Xaml { + struct IDependencyObject; + struct IWindow; + } } namespace Graphics { namespace Display { struct IDisplayInformation; } } -#ifdef Q_OS_WINPHONE - namespace Phone { - namespace UI { - namespace Input { - struct IBackPressedEventArgs; - } - } - } -#endif } } struct IInspectable; @@ -81,23 +74,20 @@ struct IInspectable; QT_BEGIN_NAMESPACE class QTouchDevice; -class QWinRTEGLContext; class QWinRTCursor; class QWinRTInputContext; class QWinRTScreenPrivate; class QWinRTScreen : public QPlatformScreen { public: - explicit QWinRTScreen(); + explicit QWinRTScreen(ABI::Windows::UI::Xaml::IWindow *xamlWindow); ~QWinRTScreen(); QRect geometry() const; int depth() const; QImage::Format format() const; - QSurfaceFormat surfaceFormat() const; QSizeF physicalSize() const Q_DECL_OVERRIDE; QDpi logicalDpi() const Q_DECL_OVERRIDE; qreal scaleFactor() const; - QWinRTInputContext *inputContext() const; QPlatformCursor *cursor() const; Qt::KeyboardModifiers keyboardModifiers() const; @@ -110,10 +100,10 @@ public: void raise(QWindow *window); void lower(QWindow *window); + void updateWindowTitle(); + ABI::Windows::UI::Core::ICoreWindow *coreWindow() const; - EGLDisplay eglDisplay() const; // To opengl context - EGLSurface eglSurface() const; // To window - EGLConfig eglConfig() const; + ABI::Windows::UI::Xaml::IDependencyObject *canvas() const; private: void handleExpose(); @@ -127,20 +117,13 @@ private: HRESULT onSizeChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowSizeChangedEventArgs *); HRESULT onActivated(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IWindowActivatedEventArgs *); - HRESULT onSuspended(IInspectable *, ABI::Windows::ApplicationModel::ISuspendingEventArgs *); - HRESULT onResume(IInspectable *, IInspectable *); HRESULT onClosed(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::ICoreWindowEventArgs *); HRESULT onVisibilityChanged(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IVisibilityChangedEventArgs *); - HRESULT onAutomationProviderRequested(ABI::Windows::UI::Core::ICoreWindow *, ABI::Windows::UI::Core::IAutomationProviderRequestedEventArgs *); HRESULT onOrientationChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); HRESULT onDpiChanged(ABI::Windows::Graphics::Display::IDisplayInformation *, IInspectable *); -#ifdef Q_OS_WINPHONE - HRESULT onBackButtonPressed(IInspectable *, ABI::Windows::Phone::UI::Input::IBackPressedEventArgs *args); -#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 adc5dfb776..634d62ef24 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.cpp +++ b/src/plugins/platforms/winrt/qwinrtwindow.cpp @@ -36,47 +36,138 @@ #include "qwinrtwindow.h" #include "qwinrtscreen.h" +#include <private/qeventdispatcher_winrt_p.h> -#include <qpa/qwindowsysteminterface.h> +#include <EGL/egl.h> +#define EGL_EGLEXT_PROTOTYPES +#include <EGL/eglext.h> + +#include <qfunctions_winrt.h> #include <qpa/qplatformscreen.h> +#include <qpa/qwindowsysteminterface.h> #include <QtGui/QGuiApplication> -#include <QtGui/QWindow> #include <QtGui/QOpenGLContext> +#include <QtGui/QWindow> +#include <QtPlatformSupport/private/qeglconvenience_p.h> -#include <qfunctions_winrt.h> -#include <windows.ui.viewmanagement.h> +#include <functional> #include <wrl.h> +#include <windows.foundation.h> +#include <windows.foundation.collections.h> +#include <windows.ui.xaml.h> +#include <windows.ui.xaml.controls.h> +#include <windows.ui.viewmanagement.h> using namespace ABI::Windows::UI::ViewManagement; using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::UI; QT_BEGIN_NAMESPACE +class QWinRTWindowPrivate +{ +public: + QWinRTScreen *screen; + + QSurfaceFormat surfaceFormat; + QString windowTitle; + + ComPtr<Xaml::Controls::ISwapChainPanel> swapChainPanel; +}; + QWinRTWindow::QWinRTWindow(QWindow *window) : QPlatformWindow(window) - , m_screen(static_cast<QWinRTScreen*>(screen())) + , d_ptr(new QWinRTWindowPrivate) { + Q_D(QWinRTWindow); + + d->screen = static_cast<QWinRTScreen *>(screen()); setWindowFlags(window->flags()); setWindowState(window->windowState()); setWindowTitle(window->title()); handleContentOrientationChange(window->contentOrientation()); + + d->surfaceFormat.setAlphaBufferSize(0); + d->surfaceFormat.setRedBufferSize(8); + d->surfaceFormat.setGreenBufferSize(8); + d->surfaceFormat.setBlueBufferSize(8); + d->surfaceFormat.setDepthBufferSize(24); + d->surfaceFormat.setStencilBufferSize(8); + d->surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES); + d->surfaceFormat.setSamples(1); + d->surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer); + + HRESULT 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); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr<Xaml::IDependencyObject> canvas = d->screen->canvas(); + ComPtr<Xaml::Controls::IPanel> panel; + hr = canvas.As(&panel); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IVector<Xaml::UIElement *>> children; + hr = panel->get_Children(&children); + Q_ASSERT_SUCCEEDED(hr); + hr = children->Append(uiElement.Get()); + Q_ASSERT_SUCCEEDED(hr); + return S_OK; + }); + Q_ASSERT_SUCCEEDED(hr); + setGeometry(window->geometry()); } QWinRTWindow::~QWinRTWindow() { - m_screen->removeWindow(window()); + Q_D(QWinRTWindow); + + HRESULT hr; + hr = QEventDispatcherWinRT::runOnXamlThread([d]() { + HRESULT hr; + ComPtr<Xaml::IDependencyObject> canvas = d->screen->canvas(); + ComPtr<Xaml::Controls::IPanel> panel; + hr = canvas.As(&panel); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IVector<Xaml::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); + Q_ASSERT_SUCCEEDED(hr); + if (found) { + hr = children->RemoveAt(index); + Q_ASSERT_SUCCEEDED(hr); + } + return S_OK; + }); + RETURN_VOID_IF_FAILED("Failed to completely destroy window resources, likely because the application is shutting down"); } QSurfaceFormat QWinRTWindow::format() const { - return m_screen->surfaceFormat(); + Q_D(const QWinRTWindow); + return d->surfaceFormat; } bool QWinRTWindow::isActive() const { - return m_screen->topWindow() == window(); + Q_D(const QWinRTWindow); + return d->screen->topWindow() == window(); } bool QWinRTWindow::isExposed() const @@ -87,55 +178,70 @@ bool QWinRTWindow::isExposed() const void QWinRTWindow::setGeometry(const QRect &rect) { + Q_D(QWinRTWindow); + if (window()->isTopLevel()) { - QPlatformWindow::setGeometry(m_screen->geometry()); + QPlatformWindow::setGeometry(d->screen->geometry()); QWindowSystemInterface::handleGeometryChange(window(), geometry()); } else { QPlatformWindow::setGeometry(rect); QWindowSystemInterface::handleGeometryChange(window(), rect); } + + HRESULT hr; + hr = QEventDispatcherWinRT::runOnXamlThread([this, d]() { + HRESULT hr; + ComPtr<Xaml::IFrameworkElement> frameworkElement; + hr = d->swapChainPanel.As(&frameworkElement); + Q_ASSERT_SUCCEEDED(hr); + const QSizeF size = QSizeF(geometry().size()) / d->screen->scaleFactor(); + hr = frameworkElement->put_Width(size.width()); + Q_ASSERT_SUCCEEDED(hr); + hr = frameworkElement->put_Height(size.height()); + Q_ASSERT_SUCCEEDED(hr); + return S_OK; + }); + Q_ASSERT_SUCCEEDED(hr); } void QWinRTWindow::setVisible(bool visible) { + Q_D(QWinRTWindow); if (!window()->isTopLevel()) return; if (visible) - m_screen->addWindow(window()); + d->screen->addWindow(window()); else - m_screen->removeWindow(window()); + d->screen->removeWindow(window()); } void QWinRTWindow::setWindowTitle(const QString &title) { - ComPtr<IApplicationViewStatics2> statics; - HRESULT hr; - - hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_UI_ViewManagement_ApplicationView).Get(), - IID_PPV_ARGS(&statics)); - RETURN_VOID_IF_FAILED("Could not get ApplicationViewStatics"); - - ComPtr<IApplicationView> view; - hr = statics->GetForCurrentView(&view); - RETURN_VOID_IF_FAILED("Could not access currentView"); - - HStringReference str(reinterpret_cast<LPCWSTR>(title.utf16()), title.length()); - hr = view->put_Title(str.Get()); - RETURN_VOID_IF_FAILED("Unable to set window title"); + Q_D(QWinRTWindow); + d->windowTitle = title; + d->screen->updateWindowTitle(); } void QWinRTWindow::raise() { + Q_D(QWinRTWindow); if (!window()->isTopLevel()) return; - m_screen->raise(window()); + d->screen->raise(window()); } void QWinRTWindow::lower() { + Q_D(QWinRTWindow); if (!window()->isTopLevel()) return; - m_screen->lower(window()); + d->screen->lower(window()); +} + +WId QWinRTWindow::winId() const +{ + Q_D(const QWinRTWindow); + return WId(d->swapChainPanel.Get()); } qreal QWinRTWindow::devicePixelRatio() const diff --git a/src/plugins/platforms/winrt/qwinrtwindow.h b/src/plugins/platforms/winrt/qwinrtwindow.h index 3cfe346ab2..88c149b080 100644 --- a/src/plugins/platforms/winrt/qwinrtwindow.h +++ b/src/plugins/platforms/winrt/qwinrtwindow.h @@ -42,8 +42,7 @@ QT_BEGIN_NAMESPACE -class QWinRTScreen; - +class QWinRTWindowPrivate; class QWinRTWindow : public QPlatformWindow { public: @@ -59,10 +58,13 @@ public: void raise(); void lower(); + WId winId() const Q_DECL_OVERRIDE; + qreal devicePixelRatio() const Q_DECL_OVERRIDE; private: - QWinRTScreen *m_screen; + QScopedPointer<QWinRTWindowPrivate> d_ptr; + Q_DECLARE_PRIVATE(QWinRTWindow) }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro index 80429daeed..2718ea62bb 100644 --- a/src/plugins/platforms/winrt/winrt.pro +++ b/src/plugins/platforms/winrt/winrt.pro @@ -1,14 +1,6 @@ TARGET = qwinrt CONFIG -= precompile_header -# For Windows Phone 8 we have to deploy fonts together with the application as DirectWrite -# is not supported here. -winphone:equals(WINSDK_VER, 8.0): { - fonts.path = $$[QT_INSTALL_LIBS]/fonts - fonts.files = $$QT_SOURCE_TREE/lib/fonts/DejaVu*.ttf - INSTALLS += fonts -} - PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QWinRTIntegrationPlugin !equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - @@ -18,13 +10,8 @@ QT += core-private gui-private platformsupport-private DEFINES *= QT_NO_CAST_FROM_ASCII __WRL_NO_DEFAULT_LIB__ GL_GLEXT_PROTOTYPES -LIBS += $$QMAKE_LIBS_CORE - -!if(winphone:equals(WINSDK_VER, 8.0)) { - LIBS += -ldwrite - INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/freetype/include - DEFINES += QT_WINRT_USE_DWRITE -} +LIBS += $$QMAKE_LIBS_CORE -ldwrite +INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/freetype/include SOURCES = \ main.cpp \ @@ -60,9 +47,4 @@ HEADERS = \ qwinrttheme.h \ qwinrtwindow.h -winphone:equals(WINSDK_VER, 8.0): { - SOURCES -= qwinrtplatformmessagedialoghelper.cpp - HEADERS -= qwinrtplatformmessagedialoghelper.h -} - OTHER_FILES += winrt.json diff --git a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationfactory.cpp b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationfactory.cpp index 10411e72e2..508f5e82e6 100644 --- a/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationfactory.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/qxcbglintegrationfactory.cpp @@ -78,6 +78,7 @@ QStringList QXcbGlIntegrationFactory::keys(const QString &pluginPath) list.append(loader()->keyMap().values()); return list; #else + Q_UNUSED(pluginPath); return QStringList(); #endif } @@ -93,6 +94,9 @@ QXcbGlIntegration *QXcbGlIntegrationFactory::create(const QString &platform, con } if (QXcbGlIntegration *ret = loadIntegration(loader(), platform)) return ret; +#else + Q_UNUSED(platform); + Q_UNUSED(pluginPath); #endif return Q_NULLPTR; } diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp index 8b14fc7d70..37f01d4eed 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -188,16 +188,18 @@ void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share) Window window = 0; // Temporary window used to query OpenGL context if (config) { + const QByteArrayList glxExt = QByteArray(glXQueryExtensionsString(m_display, screen->screenNumber())).split(' '); + // Resolve entry point for glXCreateContextAttribsARB glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; - glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB"); + if (glxExt.contains("GLX_ARB_create_context")) + glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB"); - QList<QByteArray> glxExt = QByteArray(glXQueryExtensionsString(m_display, screen->screenNumber())).split(' '); - bool supportsProfiles = glxExt.contains("GLX_ARB_create_context_profile"); + const bool supportsProfiles = glxExt.contains("GLX_ARB_create_context_profile"); // Use glXCreateContextAttribsARB if available // Also, GL ES context creation requires GLX_EXT_create_context_es2_profile - if (glxExt.contains("GLX_ARB_create_context") && glXCreateContextAttribsARB != 0 + if (glXCreateContextAttribsARB != 0 && (m_format.renderableType() != QSurfaceFormat::OpenGLES || (supportsProfiles && glxExt.contains("GLX_EXT_create_context_es2_profile")))) { // Try to create an OpenGL context for each known OpenGL version in descending // order from the requested version. @@ -561,10 +563,12 @@ void (*QGLXContext::getProcAddress(const QByteArray &procName)) () if (!glXGetProcAddressARB) #endif { +#ifndef QT_NO_LIBRARY extern const QString qt_gl_library_name(); // QLibrary lib(qt_gl_library_name()); QLibrary lib(QLatin1String("GL")); glXGetProcAddressARB = (qt_glXGetProcAddressARB) lib.resolve("glXGetProcAddressARB"); +#endif } } resolved = true; diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index c0f5477f82..e62d515b62 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -49,6 +49,7 @@ #include <qdebug.h> #include <qpainter.h> #include <qscreen.h> +#include <QtGui/private/qhighdpiscaling_p.h> #include <qpa/qplatformgraphicsbuffer.h> #include <algorithm> @@ -313,14 +314,7 @@ void QXcbBackingStore::beginPaint(const QRegion ®ion) if (!m_image) return; - int dpr = int(m_image->image()->devicePixelRatio()); - const int windowDpr = int(window()->devicePixelRatio()); - if (windowDpr != dpr) { - resize(window()->size(), QRegion()); - dpr = int(m_image->image()->devicePixelRatio()); - } - - m_paintRegion = dpr == 1 ? region : QTransform::fromScale(dpr,dpr).map(region); + m_paintRegion = region; m_image->preparePaint(m_paintRegion); if (m_image->image()->hasAlphaChannel()) { @@ -369,18 +363,10 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin if (!m_image || m_image->size().isEmpty()) return; - const int dpr = int(window->devicePixelRatio()); - -#ifndef QT_NO_DEBUG - const int imageDpr = int(m_image->image()->devicePixelRatio()); - if (dpr != imageDpr) - qWarning() << "QXcbBackingStore::flush() wrong devicePixelRatio for backingstore image" << dpr << imageDpr; -#endif - - QSize imageSize = m_image->size() / dpr; //because we multiply with the DPR later + QSize imageSize = m_image->size(); QRegion clipped = region; - clipped &= QRect(0, 0, window->width(), window->height()); + clipped &= QRect(QPoint(), QHighDpi::toNativePixels(window->size(), window)); clipped &= QRect(0, 0, imageSize.width(), imageSize.height()).translated(-offset); QRect bounds = clipped.boundingRect(); @@ -398,8 +384,8 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin QVector<QRect> rects = clipped.rects(); for (int i = 0; i < rects.size(); ++i) { - QRect rect = QRect(rects.at(i).topLeft() * dpr, rects.at(i).size() * dpr); - m_image->put(platformWindow->xcb_window(), rect.topLeft(), rect.translated(offset * dpr)); + QRect rect = QRect(rects.at(i).topLeft(), rects.at(i).size()); + m_image->put(platformWindow->xcb_window(), rect.topLeft(), rect.translated(offset)); } Q_XCB_NOOP(connection()); @@ -430,9 +416,7 @@ void QXcbBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, c void QXcbBackingStore::resize(const QSize &size, const QRegion &) { - const int dpr = int(window()->devicePixelRatio()); - const QSize xSize = size * dpr; - if (m_image && xSize == m_image->size() && dpr == m_image->image()->devicePixelRatio()) + if (m_image && size == m_image->size()) return; Q_XCB_NOOP(connection()); @@ -445,13 +429,11 @@ void QXcbBackingStore::resize(const QSize &size, const QRegion &) QXcbWindow* win = static_cast<QXcbWindow *>(pw); delete m_image; - m_image = new QXcbShmImage(screen, xSize, win->depth(), win->imageFormat()); - m_image->image()->setDevicePixelRatio(dpr); + m_image = new QXcbShmImage(screen, size, win->depth(), win->imageFormat()); // Slow path for bgr888 VNC: Create an additional image, paint into that and // swap R and B while copying to m_image after each paint. if (win->imageNeedsRgbSwap()) { - m_rgbImage = QImage(xSize, win->imageFormat()); - m_rgbImage.setDevicePixelRatio(dpr); + m_rgbImage = QImage(size, win->imageFormat()); } Q_XCB_NOOP(connection()); } @@ -463,14 +445,12 @@ bool QXcbBackingStore::scroll(const QRegion &area, int dx, int dy) if (!m_image || m_image->image()->isNull()) return false; - const int dpr = int(m_image->image()->devicePixelRatio()); - QRegion xArea = dpr == 1 ? area : QTransform::fromScale(dpr,dpr).map(area); m_image->preparePaint(area); - QPoint delta(dx * dpr, dy * dpr); - const QVector<QRect> xRects = xArea.rects(); - for (int i = 0; i < xRects.size(); ++i) - qt_scrollRectInImage(*m_image->image(), xRects.at(i), delta); + QPoint delta(dx, dy); + const QVector<QRect> rects = area.rects(); + for (int i = 0; i < rects.size(); ++i) + qt_scrollRectInImage(*m_image->image(), rects.at(i), delta); return true; } diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index d2e08aecee..e612cff9a3 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -590,9 +590,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() @@ -2074,10 +2071,11 @@ bool QXcbConnection::xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *ev, int opCo } #endif // defined(XCB_USE_XINPUT2) -QXcbSystemTrayTracker *QXcbConnection::systemTrayTracker() +QXcbSystemTrayTracker *QXcbConnection::systemTrayTracker() const { if (!m_systemTrayTracker) { - if ( (m_systemTrayTracker = QXcbSystemTrayTracker::create(this)) ) { + QXcbConnection *self = const_cast<QXcbConnection *>(this); + if ((self->m_systemTrayTracker = QXcbSystemTrayTracker::create(self))) { connect(m_systemTrayTracker, SIGNAL(systemTrayWindowChanged(QScreen*)), QGuiApplication::platformNativeInterface(), SIGNAL(systemTrayWindowChanged(QScreen*))); } @@ -2085,6 +2083,22 @@ QXcbSystemTrayTracker *QXcbConnection::systemTrayTracker() return m_systemTrayTracker; } +bool QXcbConnection::xEmbedSystemTrayAvailable() +{ + if (!QGuiApplicationPrivate::platformIntegration()) + return false; + QXcbConnection *connection = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration())->defaultConnection(); + return connection->systemTrayTracker(); +} + +bool QXcbConnection::xEmbedSystemTrayVisualHasAlphaChannel() +{ + if (!QGuiApplicationPrivate::platformIntegration()) + return false; + QXcbConnection *connection = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration())->defaultConnection(); + return connection->systemTrayTracker() && connection->systemTrayTracker()->visualHasAlphaChannel(); +} + bool QXcbConnection::event(QEvent *e) { if (e->type() == QEvent::User + 1) { diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index a183a72353..4a0348aa0c 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -474,7 +474,9 @@ public: QXcbNativeInterface *nativeInterface() const { return m_nativeInterface; } - QXcbSystemTrayTracker *systemTrayTracker(); + QXcbSystemTrayTracker *systemTrayTracker() const; + static bool xEmbedSystemTrayAvailable(); + static bool xEmbedSystemTrayVisualHasAlphaChannel(); #ifdef XCB_USE_XINPUT2 void handleEnterEvent(const xcb_enter_notify_event_t *); diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index d7688be0ff..7a5480a8a5 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -562,10 +562,8 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo } QWindowSystemInterface::TouchPoint &touchPoint = dev->touchPoints[xiDeviceEvent->detail]; QXcbScreen* screen = platformWindow->xcbScreen(); - QPointF pos = screen->mapFromNative(QPointF(fixed1616ToReal(xiDeviceEvent->root_x), - fixed1616ToReal(xiDeviceEvent->root_y))); - qreal x = pos.x(); - qreal y = pos.y(); + qreal x = fixed1616ToReal(xiDeviceEvent->root_x); + qreal y = fixed1616ToReal(xiDeviceEvent->root_y); qreal nx = -1.0, ny = -1.0, d = 0.0; for (int i = 0; i < dev->xiDeviceInfo->num_classes; ++i) { XIAnyClassInfo *classinfo = dev->xiDeviceInfo->classes[i]; @@ -872,9 +870,8 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin } } if (!angleDelta.isNull()) { - const int dpr = int(platformWindow->devicePixelRatio()); - QPoint local(fixed1616ToReal(xiDeviceEvent->event_x)/dpr, fixed1616ToReal(xiDeviceEvent->event_y)/dpr); - QPoint global(fixed1616ToReal(xiDeviceEvent->root_x)/dpr, fixed1616ToReal(xiDeviceEvent->root_y)/dpr); + QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y)); + QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y)); Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods); if (modifiers & Qt::AltModifier) { std::swap(angleDelta.rx(), angleDelta.ry()); @@ -900,9 +897,8 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin angleDelta.setX(-120); } if (!angleDelta.isNull()) { - const int dpr = int(platformWindow->devicePixelRatio()); - QPoint local(fixed1616ToReal(xiDeviceEvent->event_x)/dpr, fixed1616ToReal(xiDeviceEvent->event_y)/dpr); - QPoint global(fixed1616ToReal(xiDeviceEvent->root_x)/dpr, fixed1616ToReal(xiDeviceEvent->root_y)/dpr); + QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y)); + QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y)); Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods); if (modifiers & Qt::AltModifier) std::swap(angleDelta.rx(), angleDelta.ry()); @@ -1024,9 +1020,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]); @@ -1035,9 +1030,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 @@ -1115,13 +1109,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/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp index bd880698e6..0cd9159052 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.cpp +++ b/src/plugins/platforms/xcb/qxcbcursor.cpp @@ -52,7 +52,7 @@ typedef char *(*PtrXcursorLibraryGetTheme)(void *); typedef int (*PtrXcursorLibrarySetTheme)(void *, const char *); typedef int (*PtrXcursorLibraryGetDefaultSize)(void *); -#ifdef XCB_USE_XLIB +#if defined(XCB_USE_XLIB) && !defined(QT_NO_LIBRARY) #include <X11/Xlib.h> enum { XCursorShape = CursorShape @@ -300,7 +300,7 @@ QXcbCursor::QXcbCursor(QXcbConnection *conn, QXcbScreen *screen) const char *cursorStr = "cursor"; xcb_open_font(xcb_connection(), cursorFont, strlen(cursorStr), cursorStr); -#ifdef XCB_USE_XLIB +#if defined(XCB_USE_XLIB) && !defined(QT_NO_LIBRARY) static bool function_ptrs_not_initialized = true; if (function_ptrs_not_initialized) { QLibrary xcursorLib(QLatin1String("Xcursor"), 1); @@ -491,7 +491,7 @@ xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape) return cursor; } -#ifdef XCB_USE_XLIB +#if defined(XCB_USE_XLIB) && !defined(QT_NO_LIBRARY) bool updateCursorTheme(void *dpy, const QByteArray &theme) { if (!ptrXcursorLibraryGetTheme || !ptrXcursorLibrarySetTheme) @@ -535,7 +535,7 @@ static xcb_cursor_t loadCursor(void *dpy, int cshape) } return cursor; } -#endif //XCB_USE_XLIB +#endif //XCB_USE_XLIB / QT_NO_LIBRARY xcb_cursor_t QXcbCursor::createFontCursor(int cshape) { @@ -544,7 +544,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape) xcb_cursor_t cursor = XCB_NONE; // Try Xcursor first -#ifdef XCB_USE_XLIB +#if defined(XCB_USE_XLIB) && !defined(QT_NO_LIBRARY) if (cshape >= 0 && cshape <= Qt::LastCursor) { void *dpy = connection()->xlib_display(); // special case for non-standard dnd-* cursors @@ -637,15 +637,14 @@ QPoint QXcbCursor::pos() const { QPoint p; queryPointer(connection(), 0, &p); - return m_screen->mapFromNative(p); + return p; } void QXcbCursor::setPos(const QPoint &pos) { - const QPoint xPos = m_screen->mapToNative(pos); xcb_window_t root = 0; queryPointer(connection(), &root, 0); - xcb_warp_pointer(xcb_connection(), XCB_NONE, root, 0, 0, 0, 0, xPos.x(), xPos.y()); + xcb_warp_pointer(xcb_connection(), XCB_NONE, root, 0, 0, 0, 0, pos.x(), pos.y()); xcb_flush(xcb_connection()); } diff --git a/src/plugins/platforms/xcb/qxcbcursor.h b/src/plugins/platforms/xcb/qxcbcursor.h index 7e5cdc6870..f4f6e61706 100644 --- a/src/plugins/platforms/xcb/qxcbcursor.h +++ b/src/plugins/platforms/xcb/qxcbcursor.h @@ -90,7 +90,7 @@ private: #ifndef QT_NO_CURSOR CursorHash m_cursorHash; #endif -#ifdef XCB_USE_XLIB +#if defined(XCB_USE_XLIB) && !defined(QT_NO_LIBRARY) static void cursorThemePropertyChanged(QXcbVirtualDesktop *screen, const QByteArray &name, const QVariant &property, diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index 1d13adf851..a3e646ed7a 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -51,6 +51,7 @@ #include <private/qshapedpixmapdndwindow_p.h> #include <private/qsimpledrag_p.h> +#include <private/qhighdpiscaling_p.h> QT_BEGIN_NAMESPACE @@ -71,12 +72,16 @@ QT_BEGIN_NAMESPACE const int xdnd_version = 5; +static inline xcb_window_t xcb_window(QPlatformWindow *w) +{ + return static_cast<QXcbWindow *>(w)->xcb_window(); +} + static inline xcb_window_t xcb_window(QWindow *w) { return static_cast<QXcbWindow *>(w->handle())->xcb_window(); } - static xcb_window_t xdndProxy(QXcbConnection *c, xcb_window_t w) { xcb_window_t proxy = XCB_NONE; @@ -297,15 +302,8 @@ xcb_window_t QXcbDrag::findRealWindow(const QPoint & pos, xcb_window_t w, int md return 0; } -void QXcbDrag::move(const QMouseEvent *me) +void QXcbDrag::move(const QPoint &globalPos) { - // The mouse event is in the coordinate system of the window that started the drag. - // We do not know which window that was at this point, so we just use the device pixel ratio - // of the QGuiApplication. This will break once we support screens with different DPR. Fixing - // this properly requires some redesign of the drag and drop architecture. - static const int dpr = int(qApp->devicePixelRatio()); - QBasicDrag::move(me); - QPoint globalPos = me->globalPos(); if (source_sameanswer.contains(globalPos) && source_sameanswer.isValid()) return; @@ -318,6 +316,9 @@ void QXcbDrag::move(const QMouseEvent *me) break; } } + + QBasicDrag::moveShapedPixmapWindow(QHighDpiScaling::mapPositionFromNative(globalPos, screen)); + if (screen != current_screen) { // ### need to recreate the shaped pixmap window? // int screen = QCursor::x11Screen(); @@ -340,7 +341,7 @@ void QXcbDrag::move(const QMouseEvent *me) // qt_xdnd_current_screen = screen; xcb_window_t rootwin = current_screen->root(); xcb_translate_coordinates_reply_t *translate = - ::translateCoordinates(connection(), rootwin, rootwin, globalPos.x() * dpr, globalPos.y() * dpr); + ::translateCoordinates(connection(), rootwin, rootwin, globalPos.x(), globalPos.y()); if (!translate) return; @@ -443,7 +444,7 @@ void QXcbDrag::move(const QMouseEvent *me) DEBUG() << "sending Xdnd enter source=" << enter.data.data32[0]; if (w) - handleEnter(w->window(), &enter); + handleEnter(w, &enter); else if (target) xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&enter); waiting_for_status = false; @@ -463,7 +464,7 @@ void QXcbDrag::move(const QMouseEvent *me) move.type = atom(QXcbAtom::XdndPosition); move.data.data32[0] = connection()->clipboard()->owner(); move.data.data32[1] = 0; // flags - move.data.data32[2] = (globalPos.x() * dpr << 16) + globalPos.y() * dpr; + move.data.data32[2] = (globalPos.x() << 16) + globalPos.y(); move.data.data32[3] = connection()->time(); move.data.data32[4] = toXdndAction(defaultAction(currentDrag()->supportedActions(), QGuiApplication::keyboardModifiers())); DEBUG() << "sending Xdnd position source=" << move.data.data32[0] << "target=" << move.window; @@ -471,15 +472,15 @@ void QXcbDrag::move(const QMouseEvent *me) source_time = connection()->time(); if (w) - handle_xdnd_position(w->window(), &move); + handle_xdnd_position(w, &move); else xcb_send_event(xcb_connection(), false, proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&move); } } -void QXcbDrag::drop(const QMouseEvent *event) +void QXcbDrag::drop(const QPoint &globalPos) { - QBasicDrag::drop(event); + QBasicDrag::drop(globalPos); if (!current_target) return; @@ -505,7 +506,7 @@ void QXcbDrag::drop(const QMouseEvent *event) connection()->time(), current_target, current_proxy_target, - (w ? w->window() : 0), + w, // current_embeddig_widget, currentDrag(), QTime::currentTime() @@ -518,7 +519,7 @@ void QXcbDrag::drop(const QMouseEvent *event) } if (w) { - handleDrop(w->window(), &drop); + handleDrop(w, &drop); } else { xcb_send_event(xcb_connection(), false, current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&drop); } @@ -664,7 +665,7 @@ static bool checkEmbedded(QWidget* w, const XEvent* xe) #endif -void QXcbDrag::handleEnter(QWindow *window, const xcb_client_message_event_t *event) +void QXcbDrag::handleEnter(QPlatformWindow *window, const xcb_client_message_event_t *event) { Q_UNUSED(window); DEBUG() << "handleEnter" << window; @@ -689,6 +690,7 @@ void QXcbDrag::handleEnter(QWindow *window, const xcb_client_message_event_t *ev length = xdnd_max_type; xcb_atom_t *atoms = (xcb_atom_t *)xcb_get_property_value(reply); + xdnd_types.reserve(length); for (int i = 0; i < length; ++i) xdnd_types.append(atoms[i]); } @@ -704,17 +706,14 @@ void QXcbDrag::handleEnter(QWindow *window, const xcb_client_message_event_t *ev DEBUG() << " " << connection()->atomName(xdnd_types.at(i)); } -void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *e) +void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *e) { QPoint p((e->data.data32[2] & 0xffff0000) >> 16, e->data.data32[2] & 0x0000ffff); Q_ASSERT(w); QRect geometry = w->geometry(); - const int dpr = int(w->handle()->devicePixelRatio()); - - p /= dpr; p -= geometry.topLeft(); - if (!w || (w->type() == Qt::Desktop)) + if (!w || !w->window() || (w->window()->type() == Qt::Desktop)) return; if (e->data.data32[0] != xdnd_dragsource) { @@ -723,7 +722,7 @@ void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t } currentPosition = p; - currentWindow = w; + currentWindow = w->window(); // timestamp from the source if (e->data.data32[3] != XCB_NONE) { @@ -740,7 +739,7 @@ void QXcbDrag::handle_xdnd_position(QWindow *w, const xcb_client_message_event_t supported_actions = Qt::DropActions(toDropAction(e->data.data32[4])); } - QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(w,dropData,p,supported_actions); + QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(w->window(),dropData,p,supported_actions); QRect answerRect(p + geometry.topLeft(), QSize(1,1)); answerRect = qt_response.answerRect().translated(geometry.topLeft()).intersected(geometry); @@ -796,7 +795,7 @@ namespace }; } -void QXcbDrag::handlePosition(QWindow * w, const xcb_client_message_event_t *event) +void QXcbDrag::handlePosition(QPlatformWindow * w, const xcb_client_message_event_t *event) { xcb_client_message_event_t *lastEvent = const_cast<xcb_client_message_event_t *>(event); xcb_generic_event_t *nextEvent; @@ -830,12 +829,10 @@ void QXcbDrag::handle_xdnd_status(const xcb_client_message_event_t *event) updateCursor(Qt::IgnoreAction); } - static const int dpr = int(qApp->devicePixelRatio()); - if ((event->data.data32[1] & 2) == 0) { QPoint p((event->data.data32[2] & 0xffff0000) >> 16, event->data.data32[2] & 0x0000ffff); QSize s((event->data.data32[3] & 0xffff0000) >> 16, event->data.data32[3] & 0x0000ffff); - source_sameanswer = QRect(p / dpr, s / dpr); + source_sameanswer = QRect(p, s); } else { source_sameanswer = QRect(); } @@ -861,10 +858,10 @@ void QXcbDrag::handleStatus(const xcb_client_message_event_t *event) DEBUG("xdndHandleStatus end"); } -void QXcbDrag::handleLeave(QWindow *w, const xcb_client_message_event_t *event) +void QXcbDrag::handleLeave(QPlatformWindow *w, const xcb_client_message_event_t *event) { DEBUG("xdnd leave"); - if (!currentWindow || w != currentWindow.data()) + if (!currentWindow || w != currentWindow.data()->handle()) return; // sanity // ### @@ -879,7 +876,7 @@ void QXcbDrag::handleLeave(QWindow *w, const xcb_client_message_event_t *event) DEBUG("xdnd drag leave from unexpected source (%x not %x", event->data.data32[0], xdnd_dragsource); } - QWindowSystemInterface::handleDrag(w,0,QPoint(),Qt::IgnoreAction); + QWindowSystemInterface::handleDrag(w->window(),0,QPoint(),Qt::IgnoreAction); xdnd_dragsource = 0; xdnd_types.clear(); @@ -909,7 +906,7 @@ void QXcbDrag::send_leave() w = 0; if (w) - handleLeave(w->window(), (const xcb_client_message_event_t *)&leave); + handleLeave(w, (const xcb_client_message_event_t *)&leave); else xcb_send_event(xcb_connection(), false,current_proxy_target, XCB_EVENT_MASK_NO_EVENT, (const char *)&leave); @@ -920,7 +917,7 @@ void QXcbDrag::send_leave() waiting_for_status = false; } -void QXcbDrag::handleDrop(QWindow *, const xcb_client_message_event_t *event) +void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *event) { DEBUG("xdndHandleDrop"); if (!currentWindow) { diff --git a/src/plugins/platforms/xcb/qxcbdrag.h b/src/plugins/platforms/xcb/qxcbdrag.h index 95da76b732..699d402ea6 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.h +++ b/src/plugins/platforms/xcb/qxcbdrag.h @@ -53,8 +53,8 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_DRAGANDDROP -class QMouseEvent; class QWindow; +class QPlatformWindow; class QXcbConnection; class QXcbWindow; class QXcbDropData; @@ -72,14 +72,14 @@ public: void startDrag() Q_DECL_OVERRIDE; void cancel() Q_DECL_OVERRIDE; - void move(const QMouseEvent *me) Q_DECL_OVERRIDE; - void drop(const QMouseEvent *me) Q_DECL_OVERRIDE; + void move(const QPoint &globalPos) Q_DECL_OVERRIDE; + void drop(const QPoint &globalPos) Q_DECL_OVERRIDE; void endDrag() Q_DECL_OVERRIDE; - void handleEnter(QWindow *window, const xcb_client_message_event_t *event); - void handlePosition(QWindow *w, const xcb_client_message_event_t *event); - void handleLeave(QWindow *w, const xcb_client_message_event_t *event); - void handleDrop(QWindow *, const xcb_client_message_event_t *event); + void handleEnter(QPlatformWindow *window, const xcb_client_message_event_t *event); + 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); void handleStatus(const xcb_client_message_event_t *event); void handleSelectionRequest(const xcb_selection_request_event_t *event); @@ -99,7 +99,7 @@ private: void init(); - void handle_xdnd_position(QWindow *w, const xcb_client_message_event_t *event); + void handle_xdnd_position(QPlatformWindow *w, const xcb_client_message_event_t *event); void handle_xdnd_status(const xcb_client_message_event_t *event); void send_leave(); @@ -146,7 +146,7 @@ private: xcb_timestamp_t timestamp; xcb_window_t target; xcb_window_t proxy_target; - QWindow *targetWindow; + QPlatformWindow *targetWindow; // QWidget *embedding_widget; QPointer<QDrag> drag; QTime time; 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/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index ea541e4556..2e088d3ca5 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -1545,11 +1545,13 @@ void QXcbKeyboard::handleKeyEvent(xcb_window_t sourceWindow, QEvent::Type type, QString QXcbKeyboard::lookupString(struct xkb_state *state, xcb_keycode_t code) const { - QByteArray chars; - chars.resize(1 + xkb_state_key_get_utf8(state, code, 0, 0)); - // equivalent of XLookupString - xkb_state_key_get_utf8(state, code, chars.data(), chars.size()); - return QString::fromUtf8(chars); + QVarLengthArray<char, 32> chars(32); + const int size = xkb_state_key_get_utf8(state, code, chars.data(), chars.size()); + if (Q_UNLIKELY(size + 1 > chars.size())) { // +1 for NUL + chars.resize(size + 1); + xkb_state_key_get_utf8(state, code, chars.data(), chars.size()); + } + return QString::fromUtf8(chars.constData(), size); } void QXcbKeyboard::handleKeyPressEvent(const xcb_key_press_event_t *event) diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp index 8bf9003af7..dfb0a125e2 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp @@ -47,6 +47,7 @@ #include <QtGui/qscreen.h> #include <QtPlatformHeaders/qxcbwindowfunctions.h> +#include <QtPlatformHeaders/qxcbintegrationfunctions.h> #ifndef QT_NO_DBUS #include "QtPlatformSupport/private/qdbusmenuconnection_p.h" @@ -76,7 +77,8 @@ static int resourceType(const QByteArray &key) QByteArrayLiteral("gettimestamp"), QByteArrayLiteral("x11screen"), QByteArrayLiteral("rootwindow"), QByteArrayLiteral("subpixeltype"), QByteArrayLiteral("antialiasingEnabled"), - QByteArrayLiteral("nofonthinting") + QByteArrayLiteral("nofonthinting"), + QByteArrayLiteral("atspibus") }; const QByteArray *end = names + sizeof(names) / sizeof(names[0]); const QByteArray *result = std::find(names, end, key); @@ -85,8 +87,7 @@ static int resourceType(const QByteArray &key) QXcbNativeInterface::QXcbNativeInterface() : m_genericEventFilterType(QByteArrayLiteral("xcb_generic_event_t")), - m_sysTraySelectionAtom(XCB_ATOM_NONE), - m_systrayVisualId(XCB_NONE) + m_sysTraySelectionAtom(XCB_ATOM_NONE) { } @@ -117,22 +118,12 @@ bool QXcbNativeInterface::systemTrayAvailable(const QScreen *screen) const bool QXcbNativeInterface::requestSystemTrayWindowDock(const QWindow *window) { - const QPlatformWindow *platformWindow = window->handle(); - if (!platformWindow) - return false; - QXcbSystemTrayTracker *trayTracker = systemTrayTracker(window->screen()); - if (!trayTracker) - return false; - trayTracker->requestSystemTrayWindowDock(static_cast<const QXcbWindow *>(platformWindow)->xcb_window()); - return true; + return QXcbWindow::requestSystemTrayWindowDockStatic(window); } QRect QXcbNativeInterface::systemTrayWindowGlobalGeometry(const QWindow *window) { - if (const QPlatformWindow *platformWindow = window->handle()) - if (const QXcbSystemTrayTracker *trayTracker = systemTrayTracker(window->screen())) - return trayTracker->systemTrayWindowGlobalGeometry(static_cast<const QXcbWindow *>(platformWindow)->xcb_window()); - return QRect(); + return QXcbWindow::systemTrayWindowGlobalGeometryStatic(window); } xcb_window_t QXcbNativeInterface::locateSystemTray(xcb_connection_t *conn, const QXcbScreen *screen) @@ -163,54 +154,14 @@ xcb_window_t QXcbNativeInterface::locateSystemTray(xcb_connection_t *conn, const return selection_window; } -bool QXcbNativeInterface::systrayVisualHasAlphaChannel() { - const QXcbScreen *screen = static_cast<QXcbScreen *>(QGuiApplication::primaryScreen()->handle()); - - if (m_systrayVisualId == XCB_NONE) { - xcb_connection_t *xcb_conn = screen->xcb_connection(); - xcb_atom_t tray_atom = screen->atom(QXcbAtom::_NET_SYSTEM_TRAY_VISUAL); - - xcb_window_t systray_window = locateSystemTray(xcb_conn, screen); - if (systray_window == XCB_WINDOW_NONE) - return false; - - // Get the xcb property for the _NET_SYSTEM_TRAY_VISUAL atom - xcb_get_property_cookie_t systray_atom_cookie; - xcb_get_property_reply_t *systray_atom_reply; - - systray_atom_cookie = xcb_get_property_unchecked(xcb_conn, false, systray_window, - tray_atom, XCB_ATOM_VISUALID, 0, 1); - systray_atom_reply = xcb_get_property_reply(xcb_conn, systray_atom_cookie, 0); - - if (!systray_atom_reply) - return false; - - if (systray_atom_reply->value_len > 0 && xcb_get_property_value_length(systray_atom_reply) > 0) { - xcb_visualid_t * vids = (uint32_t *)xcb_get_property_value(systray_atom_reply); - m_systrayVisualId = vids[0]; - } - - free(systray_atom_reply); - } - - if (m_systrayVisualId != XCB_NONE) { - quint8 depth = screen->depthOfVisual(m_systrayVisualId); - return depth == 32; - } else { - return false; - } +bool QXcbNativeInterface::systrayVisualHasAlphaChannel() +{ + return QXcbConnection::xEmbedSystemTrayVisualHasAlphaChannel(); } -void QXcbNativeInterface::setParentRelativeBackPixmap(const QWindow *qwindow) +void QXcbNativeInterface::setParentRelativeBackPixmap(QWindow *window) { - if (const QPlatformWindow *platformWindow = qwindow->handle()) { - const QXcbWindow *qxwindow = static_cast<const QXcbWindow *>(platformWindow); - xcb_connection_t *xcb_conn = qxwindow->xcb_connection(); - - const quint32 mask = XCB_CW_BACK_PIXMAP; - const quint32 values[] = { XCB_BACK_PIXMAP_PARENT_RELATIVE }; - Q_XCB_CALL(xcb_change_window_attributes(xcb_conn, qxwindow->xcb_window(), mask, values)); - } + QXcbWindow::setParentRelativeBackPixmapStatic(window); } void *QXcbNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString) @@ -233,6 +184,9 @@ void *QXcbNativeInterface::nativeResourceForIntegration(const QByteArray &resour case Display: result = display(); break; + case AtspiBus: + result = atspiBus(); + break; case Connection: result = connection(); break; @@ -294,6 +248,9 @@ void *QXcbNativeInterface::nativeResourceForScreen(const QByteArray &resourceStr case NoFontHinting: result = xcbScreen->noFontHinting() ? this : 0; //qboolptr... break; + case RootWindow: + result = reinterpret_cast<void *>(xcbScreen->root()); + break; default: break; } @@ -389,9 +346,24 @@ QFunctionPointer QXcbNativeInterface::platformFunction(const QByteArray &functio return func; //case sensitive - if (function == QXcbWindowFunctions::setWmWindowTypeIdentifier()) { - return QFunctionPointer(QXcbWindow::setWmWindowTypeStatic); - } + if (function == QXcbWindowFunctions::setWmWindowTypeIdentifier()) + return QFunctionPointer(QXcbWindowFunctions::SetWmWindowType(QXcbWindow::setWmWindowTypeStatic)); + + if (function == QXcbWindowFunctions::setWmWindowIconTextIdentifier()) + return QFunctionPointer(QXcbWindowFunctions::SetWmWindowIconText(QXcbWindow::setWindowIconTextStatic)); + + if (function == QXcbWindowFunctions::setParentRelativeBackPixmapIdentifier()) + return QFunctionPointer(QXcbWindowFunctions::SetParentRelativeBackPixmap(QXcbWindow::setParentRelativeBackPixmapStatic)); + + if (function == QXcbWindowFunctions::requestSystemTrayWindowDockIdentifier()) + return QFunctionPointer(QXcbWindowFunctions::RequestSystemTrayWindowDock(QXcbWindow::requestSystemTrayWindowDockStatic)); + + if (function == QXcbWindowFunctions::systemTrayWindowGlobalGeometryIdentifier()) + return QFunctionPointer(QXcbWindowFunctions::SystemTrayWindowGlobalGeometry(QXcbWindow::systemTrayWindowGlobalGeometryStatic)); + + if (function == QXcbIntegrationFunctions::xEmbedSystemTrayVisualHasAlphaChannelIdentifier()) + return QFunctionPointer(QXcbIntegrationFunctions::XEmbedSystemTrayVisualHasAlphaChannel(QXcbConnection::xEmbedSystemTrayVisualHasAlphaChannel)); + if (function == QXcbWindowFunctions::visualIdIdentifier()) { return QFunctionPointer(QXcbWindowFunctions::VisualId(QXcbWindow::visualIdStatic)); } @@ -466,6 +438,27 @@ void *QXcbNativeInterface::connection() return integration->defaultConnection()->xcb_connection(); } +void *QXcbNativeInterface::atspiBus() +{ + QXcbIntegration *integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration()); + QXcbConnection *defaultConnection = integration->defaultConnection(); + if (defaultConnection) { + xcb_atom_t atspiBusAtom = defaultConnection->internAtom("AT_SPI_BUS"); + xcb_get_property_cookie_t cookie = Q_XCB_CALL(xcb_get_property(defaultConnection->xcb_connection(), false, + defaultConnection->rootWindow(), + atspiBusAtom, + XCB_ATOM_STRING, 0, 128)); + xcb_get_property_reply_t *reply = Q_XCB_CALL(xcb_get_property_reply(defaultConnection->xcb_connection(), cookie, 0)); + Q_ASSERT(!reply->bytes_after); + char *data = (char *)xcb_get_property_value(reply); + int length = xcb_get_property_value_length(reply); + QByteArray *busAddress = new QByteArray(data, length); + free(reply); + return busAddress; + } + return 0; +} + void QXcbNativeInterface::setAppTime(QScreen* screen, xcb_timestamp_t time) { if (screen) { diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h index 721c6f4b1d..f88b710864 100644 --- a/src/plugins/platforms/xcb/qxcbnativeinterface.h +++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h @@ -67,7 +67,8 @@ public: RootWindow, ScreenSubpixelType, ScreenAntialiasingEnabled, - NoFontHinting + NoFontHinting, + AtspiBus }; QXcbNativeInterface(); @@ -98,6 +99,7 @@ public: void *x11Screen(); void *rootWindow(); void *display(); + void *atspiBus(); void *connection(); static void setStartupId(const char *); static void setAppTime(QScreen *screen, xcb_timestamp_t time); @@ -105,7 +107,7 @@ public: Q_INVOKABLE void beep(); Q_INVOKABLE bool systemTrayAvailable(const QScreen *screen) const; - Q_INVOKABLE void setParentRelativeBackPixmap(const QWindow *window); + Q_INVOKABLE void setParentRelativeBackPixmap(QWindow *window); Q_INVOKABLE bool systrayVisualHasAlphaChannel(); Q_INVOKABLE bool requestSystemTrayWindowDock(const QWindow *window); Q_INVOKABLE QRect systemTrayWindowGlobalGeometry(const QWindow *window); @@ -121,7 +123,6 @@ private: const QByteArray m_genericEventFilterType; xcb_atom_t m_sysTraySelectionAtom; - xcb_visualid_t m_systrayVisualId; static QXcbScreen *qPlatformScreenForWindow(QWindow *window); diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 3dcd6a713a..c6e48dc8c4 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -44,6 +44,7 @@ #include <qpa/qwindowsysteminterface.h> #include <private/qmath_p.h> +#include <QtGui/private/qhighdpiscaling_p.h> QT_BEGIN_NAMESPACE @@ -86,7 +87,7 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe , m_orientation(Qt::PrimaryOrientation) , m_refreshRate(60) , m_forcedDpi(-1) - , m_devicePixelRatio(1) + , m_pixelDensity(1) , m_hintStyle(QFontEngine::HintStyle(-1)) , m_noFontHinting(false) , m_subpixelType(QFontEngine::SubpixelAntialiasingType(-1)) @@ -107,9 +108,8 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe updateGeometry(output ? output->timestamp : 0); } - const int dpr = int(devicePixelRatio()); if (m_geometry.isEmpty()) { - m_geometry = QRect(QPoint(), m_virtualSize/dpr); + m_geometry = QRect(QPoint(), m_virtualSize); m_nativeGeometry = QRect(QPoint(), m_virtualSize); } if (m_availableGeometry.isEmpty()) @@ -117,12 +117,6 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe readXResources(); - // disable font hinting when we do UI scaling - static bool dpr_scaling_enabled = (qgetenv("QT_DEVICE_PIXEL_RATIO").toInt() > 1 - || qgetenv("QT_DEVICE_PIXEL_RATIO").toLower() == "auto"); - if (dpr_scaling_enabled) - m_noFontHinting = true; - QScopedPointer<xcb_get_window_attributes_reply_t, QScopedPointerPodDeleter> rootAttribs( xcb_get_window_attributes_reply(xcb_connection(), xcb_get_window_attributes_unchecked(xcb_connection(), screen()->root), NULL)); @@ -201,9 +195,8 @@ QWindow *QXcbScreen::topLevelAt(const QPoint &p) const { xcb_window_t root = screen()->root; - int dpr = int(devicePixelRatio()); - int x = p.x() / dpr; - int y = p.y() / dpr; + int x = p.x(); + int y = p.y(); xcb_window_t parent = root; xcb_window_t child = root; @@ -237,43 +230,6 @@ QWindow *QXcbScreen::topLevelAt(const QPoint &p) const return 0; } - -QPoint QXcbScreen::mapToNative(const QPoint &pos) const -{ - const int dpr = int(devicePixelRatio()); - return (pos - m_geometry.topLeft()) * dpr + m_nativeGeometry.topLeft(); -} - -QPoint QXcbScreen::mapFromNative(const QPoint &pos) const -{ - const int dpr = int(devicePixelRatio()); - return (pos - m_nativeGeometry.topLeft()) / dpr + m_geometry.topLeft(); -} - -QPointF QXcbScreen::mapToNative(const QPointF &pos) const -{ - const int dpr = int(devicePixelRatio()); - return (pos - m_geometry.topLeft()) * dpr + m_nativeGeometry.topLeft(); -} - -QPointF QXcbScreen::mapFromNative(const QPointF &pos) const -{ - const int dpr = int(devicePixelRatio()); - return (pos - m_nativeGeometry.topLeft()) / dpr + m_geometry.topLeft(); -} - -QRect QXcbScreen::mapToNative(const QRect &rect) const -{ - const int dpr = int(devicePixelRatio()); - return QRect(mapToNative(rect.topLeft()), rect.size() * dpr); -} - -QRect QXcbScreen::mapFromNative(const QRect &rect) const -{ - const int dpr = int(devicePixelRatio()); - return QRect(mapFromNative(rect.topLeft()), rect.size() / dpr); -} - void QXcbScreen::windowShown(QXcbWindow *window) { // Freedesktop.org Startup Notification @@ -335,29 +291,22 @@ QDpi QXcbScreen::virtualDpi() const Q_MM_PER_INCH * m_virtualSize.height() / m_virtualSizeMillimeters.height()); } + QDpi QXcbScreen::logicalDpi() const { static const int overrideDpi = qEnvironmentVariableIntValue("QT_FONT_DPI"); if (overrideDpi) return QDpi(overrideDpi, overrideDpi); - int primaryDpr = int(connection()->screens().at(0)->devicePixelRatio()); - if (m_forcedDpi > 0) - return QDpi(m_forcedDpi/primaryDpr, m_forcedDpi/primaryDpr); - QDpi vDpi = virtualDpi(); - return QDpi(vDpi.first/primaryDpr, vDpi.second/primaryDpr); + if (m_forcedDpi > 0) { + return QDpi(m_forcedDpi, m_forcedDpi); + } + return virtualDpi(); } - -qreal QXcbScreen::devicePixelRatio() const +qreal QXcbScreen::pixelDensity() const { - static int override_dpr = qEnvironmentVariableIntValue("QT_DEVICE_PIXEL_RATIO"); - static bool auto_dpr = qgetenv("QT_DEVICE_PIXEL_RATIO").toLower() == "auto"; - if (override_dpr > 0) - return override_dpr; - if (auto_dpr) - return m_devicePixelRatio; - return 1.0; + return m_pixelDensity; } QPlatformCursor *QXcbScreen::cursor() const @@ -516,11 +465,10 @@ void QXcbScreen::updateGeometry(const QRect &geom, uint8_t rotation) free(workArea); qreal dpi = xGeometry.width() / physicalSize().width() * qreal(25.4); - m_devicePixelRatio = qRound(dpi/96); - const int dpr = int(devicePixelRatio()); // we may override m_devicePixelRatio - m_geometry = QRect(xGeometry.topLeft(), xGeometry.size()/dpr); + m_pixelDensity = qRound(dpi/96); + m_geometry = QRect(xGeometry.topLeft(), xGeometry.size()); m_nativeGeometry = QRect(xGeometry.topLeft(), xGeometry.size()); - m_availableGeometry = QRect(mapFromNative(xAvailableGeometry.topLeft()), xAvailableGeometry.size()/dpr); + m_availableGeometry = QRect(xAvailableGeometry.topLeft(), xAvailableGeometry.size()); QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry); } diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index ccc30c0b84..cbb6307d6e 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -96,7 +96,7 @@ public: QSizeF physicalVirtualSize() const { return m_virtualSizeMillimeters; } QDpi virtualDpi() const; QDpi logicalDpi() const Q_DECL_OVERRIDE; - qreal devicePixelRatio() const Q_DECL_OVERRIDE; + qreal pixelDensity() const Q_DECL_OVERRIDE; QPlatformCursor *cursor() const Q_DECL_OVERRIDE; qreal refreshRate() const Q_DECL_OVERRIDE { return m_refreshRate; } Qt::ScreenOrientation orientation() const Q_DECL_OVERRIDE { return m_orientation; } @@ -139,13 +139,6 @@ public: QXcbXSettings *xSettings() const; - QPoint mapToNative(const QPoint &pos) const; - QPoint mapFromNative(const QPoint &pos) const; - QPointF mapToNative(const QPointF &pos) const; - QPointF mapFromNative(const QPointF &pos) const; - QRect mapToNative(const QRect &rect) const; - QRect mapFromNative(const QRect &rect) const; - private: static bool xResource(const QByteArray &identifier, const QByteArray &expectedIdentifier, @@ -176,7 +169,7 @@ private: QXcbCursor *m_cursor; int m_refreshRate; int m_forcedDpi; - int m_devicePixelRatio; + int m_pixelDensity; QFontEngine::HintStyle m_hintStyle; bool m_noFontHinting; QFontEngine::SubpixelAntialiasingType m_subpixelType; diff --git a/src/plugins/platforms/xcb/qxcbsessionmanager.cpp b/src/plugins/platforms/xcb/qxcbsessionmanager.cpp index 328b72234a..c2101a71c1 100644 --- a/src/plugins/platforms/xcb/qxcbsessionmanager.cpp +++ b/src/plugins/platforms/xcb/qxcbsessionmanager.cpp @@ -134,6 +134,7 @@ static void sm_setProperty(const QString &name, const QStringList &value) SmPropValue *prop = new SmPropValue[value.count()]; int count = 0; QList<QByteArray> vl; + vl.reserve(value.size()); for (QStringList::ConstIterator it = value.begin(); it != value.end(); ++it) { prop[count].length = (*it).length(); vl.append((*it).toUtf8()); diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp index a4fdd70b79..1f217e8de7 100644 --- a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp +++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp @@ -63,14 +63,14 @@ QXcbSystemTrayTracker *QXcbSystemTrayTracker::create(QXcbConnection *connection) const xcb_atom_t selection = connection->internAtom(netSysTray.constData()); if (!selection) return 0; - return new QXcbSystemTrayTracker(connection, trayAtom, selection, connection); + + return new QXcbSystemTrayTracker(connection, trayAtom, selection); } QXcbSystemTrayTracker::QXcbSystemTrayTracker(QXcbConnection *connection, xcb_atom_t trayAtom, - xcb_atom_t selection, - QObject *parent) - : QObject(parent) + xcb_atom_t selection) + : QObject(connection) , m_selection(selection) , m_trayAtom(trayAtom) , m_connection(connection) @@ -125,6 +125,7 @@ xcb_window_t QXcbSystemTrayTracker::trayWindow() // does not work for the QWindow parented on the tray. QRect QXcbSystemTrayTracker::systemTrayWindowGlobalGeometry(xcb_window_t window) const { + xcb_connection_t *conn = m_connection->xcb_connection(); xcb_get_geometry_reply_t *geomReply = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, window), 0); @@ -161,9 +162,43 @@ void QXcbSystemTrayTracker::handleDestroyNotifyEvent(const xcb_destroy_notify_ev { if (event->window == m_trayWindow) { m_connection->removeWindowEventListener(m_trayWindow); - m_trayWindow = 0; + m_trayWindow = XCB_WINDOW_NONE; emitSystemTrayWindowChanged(); } } +bool QXcbSystemTrayTracker::visualHasAlphaChannel() +{ + if (m_trayWindow == XCB_WINDOW_NONE) + return false; + + xcb_atom_t tray_atom = m_connection->atom(QXcbAtom::_NET_SYSTEM_TRAY_VISUAL); + + // Get the xcb property for the _NET_SYSTEM_TRAY_VISUAL atom + xcb_get_property_cookie_t systray_atom_cookie; + xcb_get_property_reply_t *systray_atom_reply; + + systray_atom_cookie = xcb_get_property_unchecked(m_connection->xcb_connection(), false, m_trayWindow, + tray_atom, XCB_ATOM_VISUALID, 0, 1); + systray_atom_reply = xcb_get_property_reply(m_connection->xcb_connection(), systray_atom_cookie, 0); + + if (!systray_atom_reply) + return false; + + xcb_visualid_t systrayVisualId = XCB_NONE; + if (systray_atom_reply->value_len > 0 && xcb_get_property_value_length(systray_atom_reply) > 0) { + xcb_visualid_t * vids = (uint32_t *)xcb_get_property_value(systray_atom_reply); + systrayVisualId = vids[0]; + } + + free(systray_atom_reply); + + if (systrayVisualId != XCB_NONE) { + quint8 depth = m_connection->primaryScreen()->depthOfVisual(systrayVisualId); + return depth == 32; + } + + return false; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.h b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h index 9c20f1729a..b619afb9c4 100644 --- a/src/plugins/platforms/xcb/qxcbsystemtraytracker.h +++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h @@ -57,14 +57,14 @@ public: void handleDestroyNotifyEvent(const xcb_destroy_notify_event_t *) Q_DECL_OVERRIDE; + bool visualHasAlphaChannel(); signals: void systemTrayWindowChanged(QScreen *screen); private: explicit QXcbSystemTrayTracker(QXcbConnection *connection, xcb_atom_t trayAtom, - xcb_atom_t selection, - QObject *parent = 0); + xcb_atom_t selection); static xcb_window_t locateTrayWindow(const QXcbConnection *connection, xcb_atom_t selection); void emitSystemTrayWindowChanged(); diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 4fdebe1ebb..1ff052f2c0 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -37,6 +37,7 @@ #include <QScreen> #include <QtGui/QIcon> #include <QtGui/QRegion> +#include <QtGui/private/qhighdpiscaling_p.h> #include "qxcbintegration.h" #include "qxcbconnection.h" @@ -46,6 +47,7 @@ #include "qxcbwmsupport.h" #include "qxcbimage.h" #include "qxcbnativeinterface.h" +#include "qxcbsystemtraytracker.h" #include <qpa/qplatformintegration.h> @@ -139,73 +141,11 @@ enum QX11EmbedMessageType { const quint32 XEMBED_VERSION = 0; -static inline QRect mapLocalGeometryToNative(const QRect &qtRect, int dpr) -{ - return QRect(qtRect.x() * dpr, qtRect.y() * dpr, qtRect.width() * dpr, qtRect.height() * dpr); -} - -// When mapping expose events to Qt rects: round top/left towards the origin and -// bottom/right away from the origin, making sure that we cover the whole widget - -static inline QPoint dpr_floor(const QPoint &p, int dpr) -{ - return QPoint(p.x()/dpr, p.y()/dpr); -} - -static inline QPoint dpr_ceil(const QPoint &p, int dpr) -{ - return QPoint((p.x() + dpr - 1) / dpr, (p.y() + dpr - 1) / dpr); -} - -static inline QSize dpr_ceil(const QSize &s, int dpr) -{ - return QSize((s.width() + dpr - 1) / dpr, (s.height() + dpr - 1) / dpr); -} - -static inline QRect mapExposeFromNative(const QRect &xRect, int dpr) -{ - return QRect(dpr_floor(xRect.topLeft(), dpr), dpr_ceil(xRect.bottomRight(), dpr)); -} - -static inline QRect mapLocalGeometryFromNative(const QRect &xRect, int dpr) -{ - return QRect(xRect.topLeft() / dpr, dpr_ceil(xRect.size(), dpr)); -} - QXcbScreen *QXcbWindow::parentScreen() { return parent() ? static_cast<QXcbWindow*>(parent())->parentScreen() : m_xcbScreen; } -QPoint QXcbWindow::mapToNative(const QPoint &pos, const QXcbScreen *screen) const -{ - if (parent()) - return pos * int(screen->devicePixelRatio()); - else - return screen->mapToNative(pos); -} -QPoint QXcbWindow::mapFromNative(const QPoint &pos, const QXcbScreen *screen) const -{ - if (parent()) - return pos / int(screen->devicePixelRatio()); - else - return screen->mapFromNative(pos); -} -QRect QXcbWindow::mapToNative(const QRect &rect, const QXcbScreen *screen) const -{ - if (parent()) - return mapLocalGeometryToNative(rect, int(screen->devicePixelRatio())); - else - return screen->mapToNative(rect); -} -QRect QXcbWindow::mapFromNative(const QRect &rect, const QXcbScreen *screen) const -{ - if (parent()) - return mapLocalGeometryFromNative(rect, int(screen->devicePixelRatio())); - else - return screen->mapFromNative(rect); -} - // Returns \c true if we should set WM_TRANSIENT_FOR on \a w static inline bool isTransient(const QWindow *w) { @@ -381,7 +321,7 @@ void QXcbWindow::create() Qt::WindowType type = window()->type(); QXcbScreen *currentScreen = xcbScreen(); - QRect rect = window()->geometry(); + QRect rect = windowGeometry(); QXcbScreen *platformScreen = parent() ? parentScreen() : static_cast<QXcbScreen*>(screenForGeometry(rect)); m_xcbScreen = platformScreen; @@ -424,17 +364,15 @@ void QXcbWindow::create() if (platformScreen != currentScreen) QWindowSystemInterface::handleWindowScreenChanged(window(), platformScreen->QPlatformScreen::screen()); - const int dpr = int(devicePixelRatio()); - - QSize minimumSize = window()->minimumSize(); + const QSize minimumSize = windowMinimumSize(); if (rect.width() > 0 || rect.height() > 0) { - rect.setWidth(qBound(1, rect.width(), XCOORD_MAX/dpr)); - rect.setHeight(qBound(1, rect.height(), XCOORD_MAX/dpr)); + rect.setWidth(qBound(1, rect.width(), XCOORD_MAX)); + rect.setHeight(qBound(1, rect.height(), XCOORD_MAX)); } else if (minimumSize.width() > 0 || minimumSize.height() > 0) { rect.setSize(minimumSize); } else { - rect.setWidth(defaultWindowWidth); - rect.setHeight(defaultWindowHeight); + rect.setWidth(QHighDpi::toNativePixels(int(defaultWindowWidth), platformScreen->QPlatformScreen::screen())); + rect.setHeight(QHighDpi::toNativePixels(int(defaultWindowHeight), platformScreen->QPlatformScreen::screen())); } xcb_window_t xcb_parent_id = platformScreen->root(); @@ -478,9 +416,7 @@ void QXcbWindow::create() m_visualId = visualInfo->visualid; - const QRect xRect = mapToNative(rect, platformScreen); - - m_window = XCreateWindow(DISPLAY_FROM_XCB(this), xcb_parent_id, xRect.x(), xRect.y(), xRect.width(), xRect.height(), + m_window = XCreateWindow(DISPLAY_FROM_XCB(this), xcb_parent_id, rect.x(), rect.y(), rect.width(), rect.height(), 0, visualInfo->depth, InputOutput, visualInfo->visual, CWBackPixel|CWBorderPixel|CWColormap, &a); @@ -536,16 +472,14 @@ void QXcbWindow::create() } m_imageFormat = imageFormatForVisual(m_depth, visual->red_mask, visual->blue_mask, &m_imageRgbSwap); - const QRect xRect = mapToNative(rect, platformScreen); - Q_XCB_CALL(xcb_create_window(xcb_connection(), m_depth, m_window, // window id xcb_parent_id, // parent window id - xRect.x(), - xRect.y(), - xRect.width(), - xRect.height(), + rect.x(), + rect.y(), + rect.width(), + rect.height(), 0, // border width XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class m_visualId, // visual @@ -708,15 +642,14 @@ void QXcbWindow::setGeometry(const QRect &rect) propagateSizeHints(); - QXcbScreen *currentScreen = xcbScreen(); + QXcbScreen *currentScreen = m_xcbScreen; QXcbScreen *newScreen = parent() ? parentScreen() : static_cast<QXcbScreen*>(screenForGeometry(rect)); if (!newScreen) - newScreen = currentScreen; + newScreen = xcbScreen(); m_xcbScreen = newScreen; - const QRect xRect = mapToNative(rect, newScreen); - const QRect wmGeometry = windowToWmGeometry(xRect); + const QRect wmGeometry = windowToWmGeometry(rect); if (newScreen != currentScreen) QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen()); @@ -1328,7 +1261,7 @@ void QXcbWindow::updateMotifWmHintsBeforeMap() mwmhints.flags &= ~MWM_HINTS_INPUT_MODE; } - if (window()->minimumSize() == window()->maximumSize()) { + if (windowMinimumSize() == windowMaximumSize()) { // fixed size, remove the resize handle (since mwm/dtwm // isn't smart enough to do it itself) mwmhints.flags |= MWM_HINTS_FUNCTIONS; @@ -1522,10 +1455,22 @@ void QXcbWindow::setWindowTitle(const QString &title) xcb_flush(xcb_connection()); } +void QXcbWindow::setWindowIconText(const QString &title) +{ + const QByteArray ba = title.toUtf8(); + Q_XCB_CALL(xcb_change_property(xcb_connection(), + XCB_PROP_MODE_REPLACE, + m_window, + atom(QXcbAtom::_NET_WM_ICON_NAME), + atom(QXcbAtom::UTF8_STRING), + 8, + ba.length(), + ba.constData())); +} + void QXcbWindow::setWindowIcon(const QIcon &icon) { QVector<quint32> icon_data; - if (!icon.isNull()) { QList<QSize> availableSizes = icon.availableSizes(); if (availableSizes.isEmpty()) { @@ -1602,8 +1547,7 @@ void QXcbWindow::propagateSizeHints() xcb_size_hints_t hints; memset(&hints, 0, sizeof(hints)); - const int dpr = int(devicePixelRatio()); - const QRect xRect = windowToWmGeometry(mapToNative(geometry(), xcbScreen())); + const QRect xRect = windowToWmGeometry(geometry()); QWindow *win = window(); @@ -1613,10 +1557,10 @@ void QXcbWindow::propagateSizeHints() xcb_size_hints_set_size(&hints, true, xRect.width(), xRect.height()); xcb_size_hints_set_win_gravity(&hints, m_gravity); - QSize minimumSize = win->minimumSize() * dpr; - QSize maximumSize = win->maximumSize() * dpr; - QSize baseSize = win->baseSize() * dpr; - QSize sizeIncrement = win->sizeIncrement() * dpr; + QSize minimumSize = windowMinimumSize(); + QSize maximumSize = windowMaximumSize(); + QSize baseSize = windowBaseSize(); + QSize sizeIncrement = windowSizeIncrement(); if (minimumSize.width() > 0 || minimumSize.height() > 0) xcb_size_hints_set_min_size(&hints, @@ -1690,6 +1634,12 @@ void QXcbWindow::setWmWindowTypeStatic(QWindow *window, QXcbWindowFunctions::WmW static_cast<QXcbWindow *>(window->handle())->setWmWindowType(windowTypes, window->flags()); } +void QXcbWindow::setWindowIconTextStatic(QWindow *window, const QString &text) +{ + if (window->handle()) + static_cast<QXcbWindow *>(window->handle())->setWindowIconText(text); +} + uint QXcbWindow::visualIdStatic(QWindow *window) { if (window && window->handle()) @@ -1855,13 +1805,54 @@ void QXcbWindow::setWmWindowType(QXcbWindowFunctions::WmWindowTypes types, Qt::W xcb_flush(xcb_connection()); } +void QXcbWindow::setParentRelativeBackPixmapStatic(QWindow *window) +{ + if (window->handle()) + static_cast<QXcbWindow *>(window->handle())->setParentRelativeBackPixmap(); +} + +void QXcbWindow::setParentRelativeBackPixmap() +{ + const quint32 mask = XCB_CW_BACK_PIXMAP; + const quint32 values[] = { XCB_BACK_PIXMAP_PARENT_RELATIVE }; + Q_XCB_CALL(xcb_change_window_attributes(xcb_connection(), m_window, mask, values)); +} + +bool QXcbWindow::requestSystemTrayWindowDockStatic(const QWindow *window) +{ + if (window->handle()) + return static_cast<QXcbWindow *>(window->handle())->requestSystemTrayWindowDock(); + return false; +} + +bool QXcbWindow::requestSystemTrayWindowDock() const +{ + if (!connection()->systemTrayTracker()) + return false; + connection()->systemTrayTracker()->requestSystemTrayWindowDock(m_window); + return true; +} + +QRect QXcbWindow::systemTrayWindowGlobalGeometryStatic(const QWindow *window) +{ + if (window->handle()) + return static_cast<QXcbWindow *>(window->handle())->systemTrayWindowGlobalGeometry(); + return QRect(); +} + +QRect QXcbWindow::systemTrayWindowGlobalGeometry() const +{ + if (!connection()->systemTrayTracker()) + return QRect(); + return connection()->systemTrayTracker()->systemTrayWindowGlobalGeometry(m_window); +} + class ExposeCompressor { public: - ExposeCompressor(xcb_window_t window, QRegion *region, int devicePixelRatio) + ExposeCompressor(xcb_window_t window, QRegion *region) : m_window(window) , m_region(region) - , m_dpr(devicePixelRatio) , m_pending(true) { } @@ -1877,7 +1868,7 @@ public: return false; if (expose->count == 0) m_pending = false; - *m_region |= mapExposeFromNative(QRect(expose->x, expose->y, expose->width, expose->height), m_dpr); + *m_region |= QRect(expose->x, expose->y, expose->width, expose->height); return true; } @@ -1889,7 +1880,6 @@ public: private: xcb_window_t m_window; QRegion *m_region; - int m_dpr; bool m_pending; }; @@ -1903,16 +1893,14 @@ bool QXcbWindow::handleGenericEvent(xcb_generic_event_t *event, long *result) void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event) { - const int dpr = int(devicePixelRatio()); - QRect x_rect(event->x, event->y, event->width, event->height); - QRect rect = mapExposeFromNative(x_rect, dpr); + QRect rect(event->x, event->y, event->width, event->height); if (m_exposeRegion.isEmpty()) m_exposeRegion = rect; else m_exposeRegion |= rect; - ExposeCompressor compressor(m_window, &m_exposeRegion, dpr); + ExposeCompressor compressor(m_window, &m_exposeRegion); xcb_generic_event_t *filter = 0; do { filter = connection()->checkEvent(compressor); @@ -1964,13 +1952,13 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even } #ifndef QT_NO_DRAGANDDROP } else if (event->type == atom(QXcbAtom::XdndEnter)) { - connection()->drag()->handleEnter(window(), event); + connection()->drag()->handleEnter(this, event); } else if (event->type == atom(QXcbAtom::XdndPosition)) { - connection()->drag()->handlePosition(window(), event); + connection()->drag()->handlePosition(this, event); } else if (event->type == atom(QXcbAtom::XdndLeave)) { - connection()->drag()->handleLeave(window(), event); + connection()->drag()->handleLeave(this, event); } else if (event->type == atom(QXcbAtom::XdndDrop)) { - connection()->drag()->handleDrop(window(), event); + connection()->drag()->handleDrop(this, event); #endif } else if (event->type == atom(QXcbAtom::_XEMBED)) { handleXEmbedMessage(event); @@ -1990,26 +1978,6 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even } } -// Temporary workaround for bug in QPlatformScreen::screenForGeometry -// we need the native geometries to detect our screen, but that's not -// available in cross-platform code. Will be fixed properly when highDPI -// support is refactored to expose the native coordinate system. - -QXcbScreen *QXcbWindow::screenForNativeGeometry(const QRect &newGeometry) const -{ - QXcbScreen *currentScreen = xcbScreen(); - if (!currentScreen && QGuiApplication::primaryScreen()) - currentScreen = static_cast<QXcbScreen*>(QGuiApplication::primaryScreen()->handle()); - if (currentScreen && !parent() && !currentScreen->nativeGeometry().intersects(newGeometry)) { - Q_FOREACH (QPlatformScreen* screen, currentScreen->virtualSiblings()) { - QXcbScreen *xcbScreen = static_cast<QXcbScreen*>(screen); - if (xcbScreen->nativeGeometry().intersects(newGeometry)) - return xcbScreen; - } - } - return currentScreen; -} - void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *event) { bool fromSendEvent = (event->response_type & 0x80); @@ -2026,19 +1994,18 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * } } - const QRect nativeRect = QRect(pos, QSize(event->width, event->height)); - QXcbScreen *newScreen = parent() ? parentScreen() : screenForNativeGeometry(nativeRect); + const QRect rect = QRect(pos, QSize(event->width, event->height)); + QPlatformScreen *newScreen = parent() ? parent()->screen() : screenForGeometry(rect); QXcbScreen *currentScreen = m_xcbScreen; - m_xcbScreen = newScreen; + m_xcbScreen = static_cast<QXcbScreen*>(newScreen); if (!newScreen) return; - const QRect rect = mapFromNative(nativeRect, newScreen); QPlatformWindow::setGeometry(rect); QWindowSystemInterface::handleGeometryChange(window(), rect); if (newScreen != currentScreen) - QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen()); + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); m_configureNotifyPending = false; @@ -2071,11 +2038,10 @@ QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const if (!m_embedded) return pos; - const int dpr = int(devicePixelRatio()); QPoint ret; xcb_translate_coordinates_cookie_t cookie = xcb_translate_coordinates(xcb_connection(), xcb_window(), xcbScreen()->root(), - pos.x() * dpr, pos.y() * dpr); + pos.x(), pos.y()); xcb_translate_coordinates_reply_t *reply = xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL); if (reply) { @@ -2084,7 +2050,7 @@ QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const free(reply); } - return mapFromNative(ret, xcbScreen()); + return ret; } QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const @@ -2092,17 +2058,15 @@ QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const if (!m_embedded) return pos; - const int dpr = int(devicePixelRatio()); QPoint ret; - QPoint xPos = mapToNative(pos, xcbScreen()); xcb_translate_coordinates_cookie_t cookie = xcb_translate_coordinates(xcb_connection(), xcbScreen()->root(), xcb_window(), - xPos.x(), xPos.y()); + pos.x(), pos.y()); xcb_translate_coordinates_reply_t *reply = xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL); if (reply) { - ret.setX(reply->dst_x / dpr); - ret.setY(reply->dst_y / dpr); + ret.setX(reply->dst_x); + ret.setY(reply->dst_y); free(reply); } @@ -2118,7 +2082,7 @@ void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event) if (m_configureNotifyPending) m_deferredExpose = true; else - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size() * int(devicePixelRatio()))); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); } } @@ -2150,9 +2114,8 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in sendXEmbedMessage(container->xcb_window(), XEMBED_REQUEST_FOCUS); } } - const int dpr = int(devicePixelRatio()); - QPoint local(event_x / dpr, event_y / dpr); - QPoint global = xcbScreen()->mapFromNative(QPoint(root_x, root_y)); + QPoint local(event_x, event_y); + QPoint global(root_x, root_y); if (isWheel) { if (!connection()->isAtLeastXI21()) { @@ -2174,9 +2137,8 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x, int root_y, int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp) { - const int dpr = int(devicePixelRatio()); - QPoint local(event_x / dpr, event_y / dpr); - QPoint global = xcbScreen()->mapFromNative(QPoint(root_x, root_y)); + QPoint local(event_x, event_y); + QPoint global(root_x, root_y); if (detail >= 4 && detail <= 7) { // mouse wheel, handled in handleButtonPressEvent() @@ -2189,11 +2151,8 @@ void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x, void QXcbWindow::handleMotionNotifyEvent(int event_x, int event_y, int root_x, int root_y, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp) { - if (!xcbScreen()) - return; - const int dpr = int(devicePixelRatio()); - QPoint local(event_x / dpr, event_y / dpr); - QPoint global = xcbScreen()->mapFromNative(QPoint(root_x, root_y)); + QPoint local(event_x, event_y); + QPoint global(root_x, root_y); handleMouseEvent(timestamp, local, global, modifiers); } @@ -2321,11 +2280,10 @@ void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event) if (ignoreEnterEvent(event)) return; - const int dpr = int(devicePixelRatio()); - const QPoint local(event->event_x/dpr, event->event_y/dpr); + const QPoint local(event->event_x, event->event_y); if (!xcbScreen()) return; - QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y)); + QPoint global = QPoint(event->root_x, event->root_y); QWindowSystemInterface::handleEnterEvent(window(), local, global); } @@ -2341,11 +2299,10 @@ void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event) QXcbWindow *enterWindow = enter ? connection()->platformWindowFromId(enter->event) : 0; if (enterWindow) { - const int dpr = int(devicePixelRatio()); - QPoint local(enter->event_x/dpr, enter->event_y/dpr); + QPoint local(enter->event_x, enter->event_y); if (!xcbScreen()) return; - QPoint global = xcbScreen()->mapFromNative(QPoint(event->root_x, event->root_y)); + QPoint global = QPoint(event->root_x, event->root_y); QWindowSystemInterface::handleEnterLeaveEvent(enterWindow->window(), window(), local, global); } else { @@ -2524,7 +2481,7 @@ bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner) xev.type = moveResize; xev.window = xcb_window(); xev.format = 32; - const QPoint globalPos = mapToNative(window()->mapToGlobal(pos), xcbScreen()); + const QPoint globalPos = window()->mapToGlobal(pos); xev.data.data32[0] = globalPos.x(); xev.data.data32[1] = globalPos.y(); const bool bottom = corner == Qt::BottomRightCorner || corner == Qt::BottomLeftCorner; @@ -2650,10 +2607,11 @@ void QXcbWindow::setMask(const QRegion ®ion) xcb_shape_mask(connection()->xcb_connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, xcb_window(), 0, 0, XCB_NONE); } else { - const int dpr = devicePixelRatio(); QVector<xcb_rectangle_t> rects; - foreach (const QRect &r, region.rects()) - rects.push_back(qRectToXCBRectangle(mapLocalGeometryToNative(r, dpr))); + const QVector<QRect> regionRects = region.rects(); + rects.reserve(regionRects.count()); + foreach (const QRect &r, regionRects) + rects.push_back(qRectToXCBRectangle(r)); xcb_shape_rectangles(connection()->xcb_connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED, xcb_window(), 0, 0, rects.size(), &rects[0]); @@ -2691,11 +2649,6 @@ void QXcbWindow::postSyncWindowRequest() } } -qreal QXcbWindow::devicePixelRatio() const -{ - return xcbScreen() ? xcbScreen()->devicePixelRatio() : 1.0; -} - QXcbScreen *QXcbWindow::xcbScreen() const { return static_cast<QXcbScreen *>(screen()); diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index a379a6f9db..8968664bad 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -86,6 +86,7 @@ public: QPoint mapFromGlobal(const QPoint &pos) const Q_DECL_OVERRIDE; void setWindowTitle(const QString &title) Q_DECL_OVERRIDE; + void setWindowIconText(const QString &title); void setWindowIcon(const QIcon &icon) Q_DECL_OVERRIDE; void raise() Q_DECL_OVERRIDE; void lower() Q_DECL_OVERRIDE; @@ -145,6 +146,16 @@ public: QXcbWindowFunctions::WmWindowTypes wmWindowTypes() const; void setWmWindowType(QXcbWindowFunctions::WmWindowTypes types, Qt::WindowFlags flags); + static void setWindowIconTextStatic(QWindow *window, const QString &text); + + static void setParentRelativeBackPixmapStatic(QWindow *window); + void setParentRelativeBackPixmap(); + + static bool requestSystemTrayWindowDockStatic(const QWindow *window); + bool requestSystemTrayWindowDock() const; + + static QRect systemTrayWindowGlobalGeometryStatic(const QWindow *window); + QRect systemTrayWindowGlobalGeometry() const; uint visualId() const; bool needsSync() const; @@ -152,8 +163,6 @@ public: void postSyncWindowRequest(); void clearSyncWindowRequest() { m_pendingSyncRequest = 0; } - qreal devicePixelRatio() const Q_DECL_OVERRIDE; - QXcbScreen *xcbScreen() const; virtual void create(); @@ -169,10 +178,6 @@ protected: virtual void *createVisual() { return Q_NULLPTR; } virtual bool supportsSyncProtocol() { return !window()->supportsOpenGL(); } - QPoint mapToNative(const QPoint &pos, const QXcbScreen *screen) const; - QPoint mapFromNative(const QPoint &pos, const QXcbScreen *screen) const; - QRect mapToNative(const QRect &rect, const QXcbScreen *screen) const; - QRect mapFromNative(const QRect &rect, const QXcbScreen *screen) const; QXcbScreen *parentScreen(); void changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two = 0); diff --git a/src/plugins/platforms/xcb/qxlibconvenience.cpp b/src/plugins/platforms/xcb/qxlibconvenience.cpp deleted file mode 100644 index f3c7d2b24e..0000000000 --- a/src/plugins/platforms/xcb/qxlibconvenience.cpp +++ /dev/null @@ -1,63 +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$ -** -****************************************************************************/ - -#ifdef XCB_USE_XLIB - -#include "qxlibconvenience.h" - -// Some Xlib headers are heavy macro namespace polluters and conflict with Qt types. -// This unit makes it easier to deal with them by encapsulating these includes in this .cpp. -#include <X11/Xutil.h> - -QT_BEGIN_NAMESPACE - -xcb_keysym_t q_XLookupString(void *display, xcb_window_t window, xcb_window_t root, uint state, xcb_keycode_t code, int type, QByteArray *chars) -{ - KeySym sym = 0; - chars->resize(512); - XKeyEvent event; - memset(&event, 0, sizeof(event)); - event.type = type; - event.display = static_cast<Display*>(display); - event.window = window; - event.root = root; - event.state = state; - event.keycode = code; - int count = XLookupString(&event, chars->data(), chars->size(), &sym, 0); - chars->resize(count); - return sym; -} - -QT_END_NAMESPACE - -#endif diff --git a/src/plugins/platforms/xcb/qxlibconvenience.h b/src/plugins/platforms/xcb/qxlibconvenience.h deleted file mode 100644 index 0e6e1c37ec..0000000000 --- a/src/plugins/platforms/xcb/qxlibconvenience.h +++ /dev/null @@ -1,49 +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 XLIBUTILS_H -#define XLIBUTILS_H - -#ifdef XCB_USE_XLIB - -#include <xcb/xcb_keysyms.h> -#include <QByteArray> - -QT_BEGIN_NAMESPACE - -xcb_keysym_t q_XLookupString(void *display, xcb_window_t window, xcb_window_t root, uint state, xcb_keycode_t code, int type, QByteArray *chars); - -QT_END_NAMESPACE - -#endif // XCB_USE_XLIB -#endif |