diff options
author | Liang Qi <liang.qi@theqtcompany.com> | 2016-01-21 08:17:21 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@theqtcompany.com> | 2016-01-21 08:17:21 +0100 |
commit | 158a3a4159bdc5a49caecd63e021dacbc06cf23c (patch) | |
tree | c3ed9aee6cabd46e5e8615b3815b92d32857c4da /src/plugins/platforms | |
parent | 26ece94a68fb5ae680c5639716b06c4e1ae979a8 (diff) | |
parent | 7b2fb038ae4b8b9231ae989ad309b6eca107a858 (diff) |
Merge remote-tracking branch 'origin/5.6' into dev
Conflicts:
src/corelib/io/qiodevice_p.h
src/corelib/kernel/qvariant_p.h
src/corelib/tools/qsimd.cpp
src/gui/kernel/qguiapplication.cpp
tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp
Change-Id: I742a093cbb231b282b43e463ec67173e0d29f57a
Diffstat (limited to 'src/plugins/platforms')
45 files changed, 1318 insertions, 611 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index 9e24c4fc9d..11c68efd40 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -50,11 +50,11 @@ QT_USE_NAMESPACE #ifndef QT_NO_ACCESSIBILITY -static void convertLineOffset(QAccessibleTextInterface *text, int &line, int &offset, NSUInteger *start = 0, NSUInteger *end = 0) +static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *offset, NSUInteger *start = 0, NSUInteger *end = 0) { - Q_ASSERT(line == -1 || offset == -1); - Q_ASSERT(line != -1 || offset != -1); - Q_ASSERT(offset <= text->characterCount()); + Q_ASSERT(*line == -1 || *offset == -1); + Q_ASSERT(*line != -1 || *offset != -1); + Q_ASSERT(*offset <= text->characterCount()); int curLine = -1; int curStart = 0, curEnd = 0; @@ -81,14 +81,14 @@ static void convertLineOffset(QAccessibleTextInterface *text, int &line, int &of if (nextEnd == curEnd) ++curEnd; } - } while ((line == -1 || curLine < line) && (offset == -1 || (curEnd <= offset)) && curEnd <= text->characterCount()); + } while ((*line == -1 || curLine < *line) && (*offset == -1 || (curEnd <= *offset)) && curEnd <= text->characterCount()); curEnd = qMin(curEnd, text->characterCount()); - if (line == -1) - line = curLine; - if (offset == -1) - offset = curStart; + if (*line == -1) + *line = curLine; + if (*offset == -1) + *offset = curStart; Q_ASSERT(curStart >= 0); Q_ASSERT(curEnd >= 0); @@ -346,7 +346,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int &line, int &of if (QAccessibleTextInterface *text = iface->textInterface()) { int line = -1; int position = text->cursorPosition(); - convertLineOffset(text, line, position); + convertLineOffset(text, &line, &position); return [NSNumber numberWithInt: line]; } return nil; @@ -405,7 +405,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int &line, int &of if (index < 0 || index > iface->textInterface()->characterCount()) return nil; int line = -1; - convertLineOffset(iface->textInterface(), line, index); + convertLineOffset(iface->textInterface(), &line, &index); return [NSNumber numberWithInt:line]; } if ([attribute isEqualToString: NSAccessibilityRangeForLineParameterizedAttribute]) { @@ -415,7 +415,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int &line, int &of int lineOffset = -1; NSUInteger startOffset = 0; NSUInteger endOffset = 0; - convertLineOffset(iface->textInterface(), line, lineOffset, &startOffset, &endOffset); + convertLineOffset(iface->textInterface(), &line, &lineOffset, &startOffset, &endOffset); return [NSValue valueWithRange:NSMakeRange(startOffset, endOffset - startOffset)]; } if ([attribute isEqualToString: NSAccessibilityBoundsForRangeParameterizedAttribute]) { diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm index 06ba4d42c3..0cbdc5d9c8 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm @@ -204,7 +204,7 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon) // current OS X versions is 22 points. Provide some future-proofing // by deriving the icon height from the menu height. const int padding = 4; - const int menuHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight]; + const int menuHeight = [[NSStatusBar systemStatusBar] thickness]; const int maxImageHeight = menuHeight - padding; // Select pixmap based on the device pixel height. Ideally we would use diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h index dcdaccb389..9d754866cc 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dbackingstore.h @@ -54,8 +54,8 @@ public: QWindowsDirect2DBackingStore(QWindow *window); ~QWindowsDirect2DBackingStore(); - void beginPaint(const QRegion &); - void endPaint(); + void beginPaint(const QRegion &) Q_DECL_OVERRIDE; + void endPaint() Q_DECL_OVERRIDE; QPaintDevice *paintDevice() Q_DECL_OVERRIDE; void flush(QWindow *targetWindow, const QRegion ®ion, const QPoint &offset) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h index b5699e1191..5f65a2313a 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dplatformpixmap.h @@ -60,8 +60,7 @@ public: ~QWindowsDirect2DPlatformPixmap(); void resize(int width, int height) Q_DECL_OVERRIDE; - virtual void fromImage(const QImage &image, - Qt::ImageConversionFlags flags); + void fromImage(const QImage &image, Qt::ImageConversionFlags flags) Q_DECL_OVERRIDE; int metric(QPaintDevice::PaintDeviceMetric metric) const Q_DECL_OVERRIDE; void fill(const QColor &color) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp b/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp index 20d315955f..79ece86570 100644 --- a/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp +++ b/src/plugins/platforms/eglfs/qeglfsdeviceintegration.cpp @@ -217,7 +217,7 @@ QDpi QEGLDeviceIntegration::logicalDpi() const qreal QEGLDeviceIntegration::pixelDensity() const { - return logicalDpi().first / qreal(100); + return qRound(logicalDpi().first / qreal(100)); } Qt::ScreenOrientation QEGLDeviceIntegration::nativeOrientation() const diff --git a/src/plugins/platforms/mirclient/mirclient.pro b/src/plugins/platforms/mirclient/mirclient.pro index 033ce579b9..0851e8d719 100644 --- a/src/plugins/platforms/mirclient/mirclient.pro +++ b/src/plugins/platforms/mirclient/mirclient.pro @@ -21,6 +21,7 @@ PKGCONFIG += egl mirclient ubuntu-platform-api SOURCES = \ qmirclientbackingstore.cpp \ qmirclientclipboard.cpp \ + qmirclientcursor.cpp \ qmirclientglcontext.cpp \ qmirclientinput.cpp \ qmirclientintegration.cpp \ @@ -34,6 +35,7 @@ SOURCES = \ HEADERS = \ qmirclientbackingstore.h \ qmirclientclipboard.h \ + qmirclientcursor.h \ qmirclientglcontext.h \ qmirclientinput.h \ qmirclientintegration.h \ diff --git a/src/plugins/platforms/mirclient/qmirclientclipboard.cpp b/src/plugins/platforms/mirclient/qmirclientclipboard.cpp index 4494847b54..4cb2b5f740 100644 --- a/src/plugins/platforms/mirclient/qmirclientclipboard.cpp +++ b/src/plugins/platforms/mirclient/qmirclientclipboard.cpp @@ -87,12 +87,12 @@ void QMirClientClipboard::requestDBusClipboardContents() if (!mPendingGetContentsCall.isNull()) return; - QDBusPendingCall pendingCall = mDBusClipboard->asyncCall("GetContents"); + QDBusPendingCall pendingCall = mDBusClipboard->asyncCall(QStringLiteral("GetContents")); mPendingGetContentsCall = new QDBusPendingCallWatcher(pendingCall, this); - QObject::connect(mPendingGetContentsCall.data(), SIGNAL(finished(QDBusPendingCallWatcher*)), - this, SLOT(onDBusClipboardGetContentsFinished(QDBusPendingCallWatcher*))); + QObject::connect(mPendingGetContentsCall.data(), &QDBusPendingCallWatcher::finished, + this, &QMirClientClipboard::onDBusClipboardGetContentsFinished); } void QMirClientClipboard::onDBusClipboardGetContentsFinished(QDBusPendingCallWatcher* call) @@ -143,17 +143,17 @@ void QMirClientClipboard::setupDBus() QDBusConnection dbusConnection = QDBusConnection::sessionBus(); bool ok = dbusConnection.connect( - "com.canonical.QtMir", - "/com/canonical/QtMir/Clipboard", - "com.canonical.QtMir.Clipboard", - "ContentsChanged", + QStringLiteral("com.canonical.QtMir"), + QStringLiteral("/com/canonical/QtMir/Clipboard"), + QStringLiteral("com.canonical.QtMir.Clipboard"), + QStringLiteral("ContentsChanged"), this, SLOT(updateMimeData(QByteArray))); if (Q_UNLIKELY(!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", + mDBusClipboard = new QDBusInterface(QStringLiteral("com.canonical.QtMir"), + QStringLiteral("/com/canonical/QtMir/Clipboard"), + QStringLiteral("com.canonical.QtMir.Clipboard"), dbusConnection); mDBusSetupDone = true; @@ -161,6 +161,8 @@ void QMirClientClipboard::setupDBus() QByteArray QMirClientClipboard::serializeMimeData(QMimeData *mimeData) const { + Q_ASSERT(mimeData != nullptr); + const QStringList formats = mimeData->formats(); const int formatCount = qMin(formats.size(), maxFormatsCount); const int headerSize = sizeof(int) + (formatCount * 4 * sizeof(int)); @@ -179,12 +181,13 @@ QByteArray QMirClientClipboard::serializeMimeData(QMimeData *mimeData) const int offset = headerSize; header[0] = formatCount; for (int i = 0; i < formatCount; i++) { + const QByteArray data = mimeData->data(formats[i]); const int formatOffset = offset; const int formatSize = formats[i].size(); const int dataOffset = offset + formatSize; - const int dataSize = mimeData->data(formats[i]).size(); + const int dataSize = data.size(); memcpy(&buffer[formatOffset], formats[i].toLatin1().data(), formatSize); - memcpy(&buffer[dataOffset], mimeData->data(formats[i]).data(), dataSize); + memcpy(&buffer[dataOffset], data.data(), dataSize); header[i*4+1] = formatOffset; header[i*4+2] = formatSize; header[i*4+3] = dataOffset; @@ -264,13 +267,15 @@ void QMirClientClipboard::setMimeData(QMimeData* mimeData, QClipboard::Mode mode delete mPendingGetContentsCall.data(); } - QByteArray serializedMimeData = serializeMimeData(mimeData); - if (!serializedMimeData.isEmpty()) { - setDBusClipboardContents(serializedMimeData); - } + if (mimeData != nullptr) { + QByteArray serializedMimeData = serializeMimeData(mimeData); + if (!serializedMimeData.isEmpty()) { + setDBusClipboardContents(serializedMimeData); + } - mMimeData = mimeData; - emitChanged(QClipboard::Clipboard); + mMimeData = mimeData; + emitChanged(QClipboard::Clipboard); + } } bool QMirClientClipboard::supportsMode(QClipboard::Mode mode) const @@ -286,6 +291,10 @@ bool QMirClientClipboard::ownsMode(QClipboard::Mode mode) const void QMirClientClipboard::setDBusClipboardContents(const QByteArray &clipboardContents) { + if (!mDBusSetupDone) { + setupDBus(); + } + if (!mPendingSetContentsCall.isNull()) { // Ignore any previous set call as we are going to overwrite it anyway QObject::disconnect(mPendingSetContentsCall.data(), 0, this, 0); @@ -295,10 +304,10 @@ void QMirClientClipboard::setDBusClipboardContents(const QByteArray &clipboardCo delete mPendingSetContentsCall.data(); } - QDBusPendingCall pendingCall = mDBusClipboard->asyncCall("SetContents", clipboardContents); + QDBusPendingCall pendingCall = mDBusClipboard->asyncCall(QStringLiteral("SetContents"), clipboardContents); mPendingSetContentsCall = new QDBusPendingCallWatcher(pendingCall, this); - QObject::connect(mPendingSetContentsCall.data(), SIGNAL(finished(QDBusPendingCallWatcher*)), - this, SLOT(onDBusClipboardSetContentsFinished(QDBusPendingCallWatcher*))); + QObject::connect(mPendingSetContentsCall.data(), &QDBusPendingCallWatcher::finished, + this, &QMirClientClipboard::onDBusClipboardSetContentsFinished); } diff --git a/src/plugins/platforms/mirclient/qmirclientcursor.cpp b/src/plugins/platforms/mirclient/qmirclientcursor.cpp new file mode 100644 index 0000000000..1d6ec8391e --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientcursor.cpp @@ -0,0 +1,201 @@ +/**************************************************************************** +** +** Copyright (C) 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$ +** +****************************************************************************/ + + +#include "qmirclientcursor.h" + +#include "qmirclientlogging.h" +#include "qmirclientwindow.h" + +#include <mir_toolkit/mir_client_library.h> + +QMirClientCursor::QMirClientCursor(MirConnection *connection) + : mConnection(connection) +{ + mShapeToCursorName[Qt::ArrowCursor] = "left_ptr"; + mShapeToCursorName[Qt::UpArrowCursor] = "up_arrow"; + mShapeToCursorName[Qt::CrossCursor] = "cross"; + mShapeToCursorName[Qt::WaitCursor] = "watch"; + mShapeToCursorName[Qt::IBeamCursor] = "xterm"; + mShapeToCursorName[Qt::SizeVerCursor] = "size_ver"; + mShapeToCursorName[Qt::SizeHorCursor] = "size_hor"; + mShapeToCursorName[Qt::SizeBDiagCursor] = "size_bdiag"; + mShapeToCursorName[Qt::SizeFDiagCursor] = "size_fdiag"; + mShapeToCursorName[Qt::SizeAllCursor] = "size_all"; + mShapeToCursorName[Qt::BlankCursor] = "blank"; + mShapeToCursorName[Qt::SplitVCursor] = "split_v"; + mShapeToCursorName[Qt::SplitHCursor] = "split_h"; + mShapeToCursorName[Qt::PointingHandCursor] = "hand"; + mShapeToCursorName[Qt::ForbiddenCursor] = "forbidden"; + mShapeToCursorName[Qt::WhatsThisCursor] = "whats_this"; + mShapeToCursorName[Qt::BusyCursor] = "left_ptr_watch"; + mShapeToCursorName[Qt::OpenHandCursor] = "openhand"; + mShapeToCursorName[Qt::ClosedHandCursor] = "closedhand"; + mShapeToCursorName[Qt::DragCopyCursor] = "dnd-copy"; + mShapeToCursorName[Qt::DragMoveCursor] = "dnd-move"; + mShapeToCursorName[Qt::DragLinkCursor] = "dnd-link"; +} + +namespace { +#if !defined(QT_NO_DEBUG) +const char *qtCursorShapeToStr(Qt::CursorShape shape) +{ + switch (shape) { + case Qt::ArrowCursor: + return "Arrow"; + case Qt::UpArrowCursor: + return "UpArrow"; + case Qt::CrossCursor: + return "Cross"; + case Qt::WaitCursor: + return "Wait"; + case Qt::IBeamCursor: + return "IBeam"; + case Qt::SizeVerCursor: + return "SizeVer"; + case Qt::SizeHorCursor: + return "SizeHor"; + case Qt::SizeBDiagCursor: + return "SizeBDiag"; + case Qt::SizeFDiagCursor: + return "SizeFDiag"; + case Qt::SizeAllCursor: + return "SizeAll"; + case Qt::BlankCursor: + return "Blank"; + case Qt::SplitVCursor: + return "SplitV"; + case Qt::SplitHCursor: + return "SplitH"; + case Qt::PointingHandCursor: + return "PointingHand"; + case Qt::ForbiddenCursor: + return "Forbidden"; + case Qt::WhatsThisCursor: + return "WhatsThis"; + case Qt::BusyCursor: + return "Busy"; + case Qt::OpenHandCursor: + return "OpenHand"; + case Qt::ClosedHandCursor: + return "ClosedHand"; + case Qt::DragCopyCursor: + return "DragCopy"; + case Qt::DragMoveCursor: + return "DragMove"; + case Qt::DragLinkCursor: + return "DragLink"; + case Qt::BitmapCursor: + return "Bitmap"; + default: + return "???"; + } +} +#endif // !defined(QT_NO_DEBUG) +} // anonymous namespace + +void QMirClientCursor::changeCursor(QCursor *windowCursor, QWindow *window) +{ + if (!window) { + return; + } + + MirSurface *surface = static_cast<QMirClientWindow*>(window->handle())->mirSurface(); + + if (!surface) { + return; + } + + + if (windowCursor) { + DLOG("[ubuntumirclient QPA] changeCursor shape=%s, window=%p\n", qtCursorShapeToStr(windowCursor->shape()), window); + if (!windowCursor->pixmap().isNull()) { + configureMirCursorWithPixmapQCursor(surface, *windowCursor); + } else if (windowCursor->shape() == Qt::BitmapCursor) { + // TODO: Implement bitmap cursor support + applyDefaultCursorConfiguration(surface); + } else { + const auto &cursorName = mShapeToCursorName.value(windowCursor->shape(), QByteArray("left_ptr")); + auto cursorConfiguration = mir_cursor_configuration_from_name(cursorName.data()); + mir_surface_configure_cursor(surface, cursorConfiguration); + mir_cursor_configuration_destroy(cursorConfiguration); + } + } else { + applyDefaultCursorConfiguration(surface); + } + +} + +void QMirClientCursor::configureMirCursorWithPixmapQCursor(MirSurface *surface, QCursor &cursor) +{ + QImage image = cursor.pixmap().toImage(); + + if (image.format() != QImage::Format_ARGB32) { + image.convertToFormat(QImage::Format_ARGB32); + } + + MirBufferStream *bufferStream = mir_connection_create_buffer_stream_sync(mConnection, + image.width(), image.height(), mir_pixel_format_argb_8888, mir_buffer_usage_software); + + { + MirGraphicsRegion region; + mir_buffer_stream_get_graphics_region(bufferStream, ®ion); + + char *regionLine = region.vaddr; + Q_ASSERT(image.bytesPerLine() <= region.stride); + for (int i = 0; i < image.height(); ++i) { + memcpy(regionLine, image.scanLine(i), image.bytesPerLine()); + regionLine += region.stride; + } + } + + mir_buffer_stream_swap_buffers_sync(bufferStream); + + { + auto configuration = mir_cursor_configuration_from_buffer_stream(bufferStream, cursor.hotSpot().x(), cursor.hotSpot().y()); + mir_surface_configure_cursor(surface, configuration); + mir_cursor_configuration_destroy(configuration); + } + + mir_buffer_stream_release_sync(bufferStream); +} + +void QMirClientCursor::applyDefaultCursorConfiguration(MirSurface *surface) +{ + auto cursorConfiguration = mir_cursor_configuration_from_name("left_ptr"); + mir_surface_configure_cursor(surface, cursorConfiguration); + mir_cursor_configuration_destroy(cursorConfiguration); +} diff --git a/src/plugins/platforms/mirclient/qmirclientcursor.h b/src/plugins/platforms/mirclient/qmirclientcursor.h new file mode 100644 index 0000000000..8bb151ddda --- /dev/null +++ b/src/plugins/platforms/mirclient/qmirclientcursor.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 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 QMIRCLIENTCURSOR_H +#define QMIRCLIENTCURSOR_H + +#include <qpa/qplatformcursor.h> + +#include <QMap> +#include <QByteArray> + +struct MirConnection; +struct MirSurface; + +class QMirClientCursor : public QPlatformCursor +{ +public: + QMirClientCursor(MirConnection *connection); + void changeCursor(QCursor *windowCursor, QWindow *window) override; +private: + void configureMirCursorWithPixmapQCursor(MirSurface *surface, QCursor &cursor); + void applyDefaultCursorConfiguration(MirSurface *surface); + QMap<int, QByteArray> mShapeToCursorName; + MirConnection *mConnection; +}; + +#endif // QMIRCLIENTCURSOR_H diff --git a/src/plugins/platforms/mirclient/qmirclientglcontext.cpp b/src/plugins/platforms/mirclient/qmirclientglcontext.cpp index bbd7f5ee75..e1e7727486 100644 --- a/src/plugins/platforms/mirclient/qmirclientglcontext.cpp +++ b/src/plugins/platforms/mirclient/qmirclientglcontext.cpp @@ -140,19 +140,7 @@ void QMirClientOpenGLContext::swapBuffers(QPlatformSurface* surface) 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); + ubuntuWindow->onSwapBuffersDone(); } void (*QMirClientOpenGLContext::getProcAddress(const QByteArray& procName)) () diff --git a/src/plugins/platforms/mirclient/qmirclientglcontext.h b/src/plugins/platforms/mirclient/qmirclientglcontext.h index cc40298259..29c196ce5c 100644 --- a/src/plugins/platforms/mirclient/qmirclientglcontext.h +++ b/src/plugins/platforms/mirclient/qmirclientglcontext.h @@ -53,7 +53,7 @@ public: bool makeCurrent(QPlatformSurface* surface) override; void doneCurrent() override; bool isValid() const override { return mEglContext != EGL_NO_CONTEXT; } - void (*getProcAddress(const QByteArray& procName)) (); + void (*getProcAddress(const QByteArray& procName)) () override; EGLContext eglContext() const { return mEglContext; } diff --git a/src/plugins/platforms/mirclient/qmirclientinput.cpp b/src/plugins/platforms/mirclient/qmirclientinput.cpp index 56bc21f420..addeda634c 100644 --- a/src/plugins/platforms/mirclient/qmirclientinput.cpp +++ b/src/plugins/platforms/mirclient/qmirclientinput.cpp @@ -163,6 +163,7 @@ QMirClientInput::QMirClientInput(QMirClientClientIntegration* integration) , mEventFilterType(static_cast<QMirClientNativeInterface*>( integration->nativeInterface())->genericEventFilterType()) , mEventType(static_cast<QEvent::Type>(QEvent::registerEventType())) + , mLastFocusedWindow(nullptr) { // Initialize touch device. mTouchDevice = new QTouchDevice; @@ -234,7 +235,7 @@ void QMirClientInput::customEvent(QEvent* event) switch (mir_event_get_type(nativeEvent)) { case mir_event_type_input: - dispatchInputEvent(ubuntuEvent->window->window(), mir_event_get_input_event(nativeEvent)); + dispatchInputEvent(ubuntuEvent->window, mir_event_get_input_event(nativeEvent)); break; case mir_event_type_resize: { @@ -246,7 +247,7 @@ void QMirClientInput::customEvent(QEvent* event) mir_resize_event_get_width(resizeEvent), mir_resize_event_get_height(resizeEvent)); - ubuntuEvent->window->handleSurfaceResize(mir_resize_event_get_width(resizeEvent), + ubuntuEvent->window->handleSurfaceResized(mir_resize_event_get_width(resizeEvent), mir_resize_event_get_height(resizeEvent)); break; } @@ -254,8 +255,24 @@ void QMirClientInput::customEvent(QEvent* event) { 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); + const bool focused = mir_surface_event_get_attribute_value(surfaceEvent) == mir_surface_focused; + // Mir may have sent a pair of focus lost/gained events, so we need to "peek" into the queue + // so that we don't deactivate windows prematurely. + if (focused) { + mPendingFocusGainedEvents--; + ubuntuEvent->window->handleSurfaceFocused(); + QWindowSystemInterface::handleWindowActivated(ubuntuEvent->window->window(), Qt::ActiveWindowFocusReason); + + // NB: Since processing of system events is queued, never check qGuiApp->applicationState() + // as it might be outdated. Always call handleApplicationStateChanged() with the latest + // state regardless. + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive); + + } else if (!mPendingFocusGainedEvents) { + DLOG("[ubuntumirclient QPA] No windows have focus"); + QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason); + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); + } } break; } @@ -274,6 +291,17 @@ void QMirClientInput::postEvent(QMirClientWindow *platformWindow, const MirEvent { QWindow *window = platformWindow->window(); + const auto eventType = mir_event_get_type(event); + if (mir_event_type_surface == eventType) { + auto surfaceEvent = mir_event_get_surface_event(event); + if (mir_surface_attrib_focus == mir_surface_event_get_attribute(surfaceEvent)) { + const bool focused = mir_surface_event_get_attribute_value(surfaceEvent) == mir_surface_focused; + if (focused) { + mPendingFocusGainedEvents++; + } + } + } + QCoreApplication::postEvent(this, new QMirClientEvent( platformWindow, event, mEventType)); @@ -284,7 +312,7 @@ void QMirClientInput::postEvent(QMirClientWindow *platformWindow, const MirEvent } } -void QMirClientInput::dispatchInputEvent(QWindow *window, const MirInputEvent *ev) +void QMirClientInput::dispatchInputEvent(QMirClientWindow *window, const MirInputEvent *ev) { switch (mir_input_event_get_type(ev)) { @@ -302,7 +330,7 @@ void QMirClientInput::dispatchInputEvent(QWindow *window, const MirInputEvent *e } } -void QMirClientInput::dispatchTouchEvent(QWindow *window, const MirInputEvent *ev) +void QMirClientInput::dispatchTouchEvent(QMirClientWindow *window, const MirInputEvent *ev) { const MirTouchEvent *tev = mir_input_event_get_touch_event(ev); @@ -333,6 +361,7 @@ void QMirClientInput::dispatchTouchEvent(QWindow *window, const MirInputEvent *e switch (touch_action) { case mir_touch_action_down: + mLastFocusedWindow = window; touchPoint.state = Qt::TouchPointPressed; break; case mir_touch_action_up: @@ -347,7 +376,7 @@ void QMirClientInput::dispatchTouchEvent(QWindow *window, const MirInputEvent *e } ulong timestamp = mir_input_event_get_event_time(ev) / 1000000; - QWindowSystemInterface::handleTouchEvent(window, timestamp, + QWindowSystemInterface::handleTouchEvent(window->window(), timestamp, mTouchDevice, touchPoints); } @@ -390,7 +419,7 @@ Qt::KeyboardModifiers qt_modifiers_from_mir(MirInputEventModifiers modifiers) } } -void QMirClientInput::dispatchKeyEvent(QWindow *window, const MirInputEvent *event) +void QMirClientInput::dispatchKeyEvent(QMirClientWindow *window, const MirInputEvent *event) { const MirKeyboardEvent *key_event = mir_input_event_get_keyboard_event(event); @@ -404,6 +433,9 @@ void QMirClientInput::dispatchKeyEvent(QWindow *window, const MirInputEvent *eve QEvent::Type keyType = action == mir_keyboard_action_up ? QEvent::KeyRelease : QEvent::KeyPress; + if (action == mir_keyboard_action_down) + mLastFocusedWindow = window; + char s[2]; int sym = translateKeysym(xk_sym, s, sizeof(s)); QString text = QString::fromLatin1(s); @@ -420,7 +452,7 @@ void QMirClientInput::dispatchKeyEvent(QWindow *window, const MirInputEvent *eve } } - QWindowSystemInterface::handleKeyEvent(window, timestamp, keyType, sym, modifiers, text, is_auto_rep); + QWindowSystemInterface::handleKeyEvent(window->window(), timestamp, keyType, sym, modifiers, text, is_auto_rep); } namespace @@ -433,27 +465,54 @@ Qt::MouseButtons extract_buttons(const MirPointerEvent *pev) 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; + buttons |= Qt::MiddleButton; + if (mir_pointer_event_button_state(pev, mir_pointer_button_back)) + buttons |= Qt::BackButton; + if (mir_pointer_event_button_state(pev, mir_pointer_button_forward)) + buttons |= Qt::ForwardButton; - // 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) +void QMirClientInput::dispatchPointerEvent(QMirClientWindow *platformWindow, const MirInputEvent *ev) { + auto window = platformWindow->window(); auto timestamp = mir_input_event_get_event_time(ev) / 1000000; auto pev = mir_input_event_get_pointer_event(ev); + auto action = mir_pointer_event_action(pev); + auto localPoint = QPointF(mir_pointer_event_axis_value(pev, mir_pointer_axis_x), + mir_pointer_event_axis_value(pev, mir_pointer_axis_y)); 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)); + switch (action) { + case mir_pointer_action_button_up: + case mir_pointer_action_button_down: + case mir_pointer_action_motion: + { + const float hDelta = mir_pointer_event_axis_value(pev, mir_pointer_axis_hscroll); + const float vDelta = mir_pointer_event_axis_value(pev, mir_pointer_axis_vscroll); - QWindowSystemInterface::handleMouseEvent(window, timestamp, local_point, local_point /* Should we omit global point instead? */, - buttons, modifiers); + if (hDelta != 0 || vDelta != 0) { + const QPoint angleDelta = QPoint(hDelta * 15, vDelta * 15); + QWindowSystemInterface::handleWheelEvent(window, timestamp, localPoint, window->position() + localPoint, + QPoint(), angleDelta, modifiers, Qt::ScrollUpdate); + } + auto buttons = extract_buttons(pev); + QWindowSystemInterface::handleMouseEvent(window, timestamp, localPoint, window->position() + localPoint /* Should we omit global point instead? */, + buttons, modifiers); + break; + } + case mir_pointer_action_enter: + QWindowSystemInterface::handleEnterEvent(window, localPoint, window->position() + localPoint); + break; + case mir_pointer_action_leave: + QWindowSystemInterface::handleLeaveEvent(window); + break; + default: + DLOG("Unrecognized pointer event"); + } } #if (LOG_EVENTS != 0) diff --git a/src/plugins/platforms/mirclient/qmirclientinput.h b/src/plugins/platforms/mirclient/qmirclientinput.h index c987d18c12..3ed887419e 100644 --- a/src/plugins/platforms/mirclient/qmirclientinput.h +++ b/src/plugins/platforms/mirclient/qmirclientinput.h @@ -40,6 +40,7 @@ // Qt #include <qpa/qwindowsysteminterface.h> +#include <QAtomicInt> #include <mir_toolkit/mir_client_library.h> @@ -59,12 +60,13 @@ public: void postEvent(QMirClientWindow* window, const MirEvent *event); QMirClientClientIntegration* integration() const { return mIntegration; } + QMirClientWindow *lastFocusedWindow() const {return mLastFocusedWindow; } 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 dispatchKeyEvent(QMirClientWindow *window, const MirInputEvent *event); + void dispatchPointerEvent(QMirClientWindow *window, const MirInputEvent *event); + void dispatchTouchEvent(QMirClientWindow *window, const MirInputEvent *event); + void dispatchInputEvent(QMirClientWindow *window, const MirInputEvent *event); void dispatchOrientationEvent(QWindow* window, const MirOrientationEvent *event); @@ -73,6 +75,9 @@ private: QTouchDevice* mTouchDevice; const QByteArray mEventFilterType; const QEvent::Type mEventType; + + QMirClientWindow *mLastFocusedWindow; + QAtomicInt mPendingFocusGainedEvents; }; #endif // QMIRCLIENTINPUT_H diff --git a/src/plugins/platforms/mirclient/qmirclientintegration.cpp b/src/plugins/platforms/mirclient/qmirclientintegration.cpp index 87d2002c56..592c2d803b 100644 --- a/src/plugins/platforms/mirclient/qmirclientintegration.cpp +++ b/src/plugins/platforms/mirclient/qmirclientintegration.cpp @@ -35,28 +35,28 @@ ****************************************************************************/ -// 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 "qmirclientintegration.h" #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" +// 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> + // platform-api #include <ubuntu/application/lifecycle_delegate.h> #include <ubuntu/application/id.h> @@ -67,8 +67,11 @@ 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)); + if (qGuiApp->focusWindow()) { + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive); + } else { + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive); + } } static void aboutToStopCallback(UApplicationArchive *archive, void* context) @@ -76,9 +79,13 @@ 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)); + QPlatformInputContext *inputContext = integration->inputContext(); + if (inputContext) { + inputContext->hideInputPanel(); + } else { + qWarning("QMirClientClientIntegration aboutToStopCallback(): no input context"); + } + QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended); } QMirClientClientIntegration::QMirClientClientIntegration() @@ -100,6 +107,8 @@ QMirClientClientIntegration::QMirClientClientIntegration() "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"); + mNativeInterface->setMirConnection(u_application_instance_get_mir_connection(mInstance)); + // Create default screen. mScreen = new QMirClientScreen(u_application_instance_get_mir_connection(mInstance)); screenAdded(mScreen); @@ -176,10 +185,8 @@ QPlatformWindow* QMirClientClientIntegration::createPlatformWindow(QWindow* wind 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; + return new QMirClientWindow(window, mClipboard, static_cast<QMirClientScreen*>(mScreen), + mInput, u_application_instance_get_mir_connection(mInstance)); } bool QMirClientClientIntegration::hasCapability(QPlatformIntegration::Capability cap) const @@ -187,11 +194,12 @@ bool QMirClientClientIntegration::hasCapability(QPlatformIntegration::Capability switch (cap) { case ThreadedPixmaps: return true; - break; case OpenGL: return true; - break; + + case ApplicationState: + return true; case ThreadedOpenGL: if (qEnvironmentVariableIsEmpty("QTUBUNTU_NO_THREADED_OPENGL")) { @@ -200,8 +208,9 @@ bool QMirClientClientIntegration::hasCapability(QPlatformIntegration::Capability DLOG("ubuntumirclient: disabled threaded OpenGL"); return false; } - break; - + case MultipleWindows: + case NonFullScreenWindows: + return true; default: return QPlatformIntegration::hasCapability(cap); } @@ -262,3 +271,8 @@ QPlatformClipboard* QMirClientClientIntegration::clipboard() const { return mClipboard.data(); } + +QPlatformNativeInterface* QMirClientClientIntegration::nativeInterface() const +{ + return mNativeInterface; +} diff --git a/src/plugins/platforms/mirclient/qmirclientintegration.h b/src/plugins/platforms/mirclient/qmirclientintegration.h index 2960209691..e41cbe2cee 100644 --- a/src/plugins/platforms/mirclient/qmirclientintegration.h +++ b/src/plugins/platforms/mirclient/qmirclientintegration.h @@ -49,6 +49,7 @@ class QMirClientClipboard; class QMirClientInput; +class QMirClientNativeInterface; class QMirClientScreen; class QMirClientClientIntegration : public QPlatformIntegration { @@ -59,7 +60,7 @@ public: // QPlatformIntegration methods. bool hasCapability(QPlatformIntegration::Capability cap) const override; QAbstractEventDispatcher *createEventDispatcher() const override; - QPlatformNativeInterface* nativeInterface() const override { return mNativeInterface; } + QPlatformNativeInterface* nativeInterface() const override; QPlatformBackingStore* createPlatformBackingStore(QWindow* window) const override; QPlatformOpenGLContext* createPlatformOpenGLContext(QOpenGLContext* context) const override; QPlatformFontDatabase* fontDatabase() const override { return mFontDb; } @@ -79,7 +80,7 @@ private: void setupOptions(); void setupDescription(); - QPlatformNativeInterface* mNativeInterface; + QMirClientNativeInterface* mNativeInterface; QPlatformFontDatabase* mFontDb; QMirClientPlatformServices* mServices; diff --git a/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp b/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp index a0bb932df3..1b4c20153b 100644 --- a/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp +++ b/src/plugins/platforms/mirclient/qmirclientnativeinterface.cpp @@ -35,17 +35,17 @@ ****************************************************************************/ +// Local +#include "qmirclientnativeinterface.h" +#include "qmirclientscreen.h" +#include "qmirclientglcontext.h" + // 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: @@ -55,6 +55,7 @@ public: insert("eglcontext", QMirClientNativeInterface::EglContext); insert("nativeorientation", QMirClientNativeInterface::NativeOrientation); insert("display", QMirClientNativeInterface::Display); + insert("mirconnection", QMirClientNativeInterface::MirConnection); } }; @@ -63,6 +64,7 @@ Q_GLOBAL_STATIC(QMirClientResourceMap, ubuntuResourceMap) QMirClientNativeInterface::QMirClientNativeInterface() : mGenericEventFilterType(QByteArrayLiteral("Event")) , mNativeOrientation(nullptr) + , mMirConnection(nullptr) { } @@ -72,6 +74,23 @@ QMirClientNativeInterface::~QMirClientNativeInterface() mNativeOrientation = nullptr; } +void* QMirClientNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString) +{ + const QByteArray lowerCaseResource = resourceString.toLower(); + + if (!ubuntuResourceMap()->contains(lowerCaseResource)) { + return nullptr; + } + + const ResourceType resourceType = ubuntuResourceMap()->value(lowerCaseResource); + + if (resourceType == QMirClientNativeInterface::MirConnection) { + return mMirConnection; + } else { + return nullptr; + } +} + void* QMirClientNativeInterface::nativeResourceForContext( const QByteArray& resourceString, QOpenGLContext* context) { diff --git a/src/plugins/platforms/mirclient/qmirclientnativeinterface.h b/src/plugins/platforms/mirclient/qmirclientnativeinterface.h index 84f03bb915..7df646e73a 100644 --- a/src/plugins/platforms/mirclient/qmirclientnativeinterface.h +++ b/src/plugins/platforms/mirclient/qmirclientnativeinterface.h @@ -42,12 +42,13 @@ class QMirClientNativeInterface : public QPlatformNativeInterface { public: - enum ResourceType { EglDisplay, EglContext, NativeOrientation, Display }; + enum ResourceType { EglDisplay, EglContext, NativeOrientation, Display, MirConnection }; QMirClientNativeInterface(); ~QMirClientNativeInterface(); // QPlatformNativeInterface methods. + void* nativeResourceForIntegration(const QByteArray &resource) override; void* nativeResourceForContext(const QByteArray& resourceString, QOpenGLContext* context) override; void* nativeResourceForWindow(const QByteArray& resourceString, @@ -57,10 +58,12 @@ public: // New methods. const QByteArray& genericEventFilterType() const { return mGenericEventFilterType; } + void setMirConnection(void *mirConnection) { mMirConnection = mirConnection; } private: const QByteArray mGenericEventFilterType; Qt::ScreenOrientation* mNativeOrientation; + void *mMirConnection; }; #endif // QMIRCLIENTNATIVEINTERFACE_H diff --git a/src/plugins/platforms/mirclient/qmirclientorientationchangeevent_p.h b/src/plugins/platforms/mirclient/qmirclientorientationchangeevent_p.h index 24d7307faa..2a1ed9c09f 100644 --- a/src/plugins/platforms/mirclient/qmirclientorientationchangeevent_p.h +++ b/src/plugins/platforms/mirclient/qmirclientorientationchangeevent_p.h @@ -43,15 +43,7 @@ class OrientationChangeEvent : public QEvent { public: - enum Orientation { - Undefined = 0, - TopUp, - TopDown, - LeftUp, - RightUp, - FaceUp, - FaceDown - }; + enum Orientation { TopUp, LeftUp, TopDown, RightUp }; OrientationChangeEvent(QEvent::Type type, Orientation orientation) : QEvent(type) diff --git a/src/plugins/platforms/mirclient/qmirclientplugin.cpp b/src/plugins/platforms/mirclient/qmirclientplugin.cpp index 203a1cbfd8..75561f7fd3 100644 --- a/src/plugins/platforms/mirclient/qmirclientplugin.cpp +++ b/src/plugins/platforms/mirclient/qmirclientplugin.cpp @@ -41,14 +41,14 @@ QStringList QMirClientIntegrationPlugin::keys() const { QStringList list; - list << "mirclient"; + list << QStringLiteral("mirclient"); return list; } QPlatformIntegration* QMirClientIntegrationPlugin::create(const QString &system, const QStringList &) { - if (system.toLower() == "mirclient") { + if (system.toLower() == QLatin1String("mirclient")) { return new QMirClientClientIntegration; } else { return 0; diff --git a/src/plugins/platforms/mirclient/qmirclientscreen.cpp b/src/plugins/platforms/mirclient/qmirclientscreen.cpp index 5c4b1cd0d6..3eb01f816a 100644 --- a/src/plugins/platforms/mirclient/qmirclientscreen.cpp +++ b/src/plugins/platforms/mirclient/qmirclientscreen.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014 Canonical, Ltd. +** Copyright (C) 2014-2015 Canonical, Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -35,6 +35,11 @@ ****************************************************************************/ +// local +#include "qmirclientscreen.h" +#include "qmirclientlogging.h" +#include "qmirclientorientationchangeevent_p.h" + #include <mir_toolkit/mir_client_library.h> // Qt @@ -45,12 +50,7 @@ #include <qpa/qwindowsysteminterface.h> #include <QtPlatformSupport/private/qeglconvenience_p.h> -// local -#include "qmirclientscreen.h" -#include "qmirclientlogging.h" -#include "qmirclientorientationchangeevent_p.h" - -#include "memory" +#include <memory> static const int kSwapInterval = 1; @@ -149,9 +149,11 @@ static const MirDisplayOutput *find_active_output( QMirClientScreen::QMirClientScreen(MirConnection *connection) : mFormat(QImage::Format_RGB32) , mDepth(32) + , mOutputId(0) , mSurfaceFormat() , mEglDisplay(EGL_NO_DISPLAY) , mEglConfig(nullptr) + , mCursor(connection) { // Initialize EGL. ASSERT(eglBindAPI(EGL_OPENGL_ES_API) == EGL_TRUE); @@ -203,6 +205,11 @@ QMirClientScreen::QMirClientScreen(MirConnection *connection) auto const displayOutput = find_active_output(displayConfig.get()); ASSERT(displayOutput != nullptr); + mOutputId = displayOutput->output_id; + + mPhysicalSize = QSizeF(displayOutput->physical_width_mm, displayOutput->physical_height_mm); + DLOG("ubuntumirclient: screen physical size: %.2fx%.2f", mPhysicalSize.width(), mPhysicalSize.height()); + const MirDisplayMode *mode = &displayOutput->modes[displayOutput->current_mode]; const int kScreenWidth = mode->horizontal_resolution; const int kScreenHeight = mode->vertical_resolution; diff --git a/src/plugins/platforms/mirclient/qmirclientscreen.h b/src/plugins/platforms/mirclient/qmirclientscreen.h index 5d9325354f..a6b4f442da 100644 --- a/src/plugins/platforms/mirclient/qmirclientscreen.h +++ b/src/plugins/platforms/mirclient/qmirclientscreen.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014 Canonical, Ltd. +** Copyright (C) 2014-2015 Canonical, Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -42,6 +42,8 @@ #include <QSurfaceFormat> #include <EGL/egl.h> +#include "qmirclientcursor.h" + struct MirConnection; class QMirClientScreen : public QObject, public QPlatformScreen @@ -56,8 +58,10 @@ public: int depth() const override { return mDepth; } QRect geometry() const override { return mGeometry; } QRect availableGeometry() const override { return mGeometry; } + QSizeF physicalSize() const override { return mPhysicalSize; } Qt::ScreenOrientation nativeOrientation() const override { return mNativeOrientation; } Qt::ScreenOrientation orientation() const override { return mNativeOrientation; } + QPlatformCursor *cursor() const override { return const_cast<QMirClientCursor*>(&mCursor); } // New methods. QSurfaceFormat surfaceFormat() const { return mSurfaceFormat; } @@ -65,20 +69,24 @@ public: EGLConfig eglConfig() const { return mEglConfig; } EGLNativeDisplayType eglNativeDisplay() const { return mEglNativeDisplay; } void handleWindowSurfaceResize(int width, int height); + uint32_t mirOutputId() const { return mOutputId; } // QObject methods. - void customEvent(QEvent* event); + void customEvent(QEvent* event) override; private: QRect mGeometry; + QSizeF mPhysicalSize; Qt::ScreenOrientation mNativeOrientation; Qt::ScreenOrientation mCurrentOrientation; QImage::Format mFormat; int mDepth; + uint32_t mOutputId; QSurfaceFormat mSurfaceFormat; EGLDisplay mEglDisplay; EGLConfig mEglConfig; EGLNativeDisplayType mEglNativeDisplay; + QMirClientCursor mCursor; }; #endif // QMIRCLIENTSCREEN_H diff --git a/src/plugins/platforms/mirclient/qmirclientwindow.cpp b/src/plugins/platforms/mirclient/qmirclientwindow.cpp index 3d1e5377e5..9a72c2f9dc 100644 --- a/src/plugins/platforms/mirclient/qmirclientwindow.cpp +++ b/src/plugins/platforms/mirclient/qmirclientwindow.cpp @@ -36,16 +36,16 @@ // Local +#include "qmirclientwindow.h" #include "qmirclientclipboard.h" #include "qmirclientinput.h" -#include "qmirclientwindow.h" #include "qmirclientscreen.h" #include "qmirclientlogging.h" +#include <mir_toolkit/mir_client_library.h> + // Qt #include <qpa/qwindowsysteminterface.h> -#include <qpa/qwindowsysteminterface.h> -#include <QMutex> #include <QMutexLocker> #include <QSize> #include <QtMath> @@ -55,25 +55,46 @@ #include <EGL/egl.h> -#define IS_OPAQUE_FLAG 1 - namespace { + +// FIXME: this used to be defined by platform-api, but it's been removed in v3. Change ubuntu-keyboard to use +// a different enum for window roles. +enum UAUiWindowRole { + U_MAIN_ROLE = 1, + U_DASH_ROLE, + U_INDICATOR_ROLE, + U_NOTIFICATIONS_ROLE, + U_GREETER_ROLE, + U_LAUNCHER_ROLE, + U_ON_SCREEN_KEYBOARD_ROLE, + U_SHUTDOWN_DIALOG_ROLE, +}; + +struct MirSpecDeleter +{ + void operator()(MirSurfaceSpec *spec) { mir_surface_spec_release(spec); } +}; + +using Spec = std::unique_ptr<MirSurfaceSpec, MirSpecDeleter>; + +EGLNativeWindowType nativeWindowFor(MirSurface *surf) +{ + auto stream = mir_surface_get_buffer_stream(surf); + return reinterpret_cast<EGLNativeWindowType>(mir_buffer_stream_get_egl_native_window(stream)); +} + 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; @@ -86,117 +107,137 @@ 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 +WId makeId() { -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 int id = 1; + return id++; } -static void surfaceCreateCallback(MirSurface* surface, void* context) +MirPixelFormat defaultPixelFormatFor(MirConnection *connection) { - DASSERT(context != NULL); - QMirClientWindow* platformWindow = static_cast<QMirClientWindow*>(context); - platformWindow->priv()->surface = surface; - - mir_surface_set_event_handler(surface, eventCallback, context); + MirPixelFormat format; + unsigned int nformats; + mir_connection_get_available_surface_formats(connection, &format, 1, &nformats); + return format; } -QMirClientWindow::QMirClientWindow(QWindow* w, QSharedPointer<QMirClientClipboard> clipboard, QMirClientScreen* screen, - QMirClientInput* input, MirConnection* connection) - : QObject(nullptr), QPlatformWindow(w) +UAUiWindowRole roleFor(QWindow *window) { - DASSERT(screen != NULL); + QVariant roleVariant = window->property("role"); + if (!roleVariant.isValid()) + return U_MAIN_ROLE; - d = new QMirClientWindowPrivate; - d->screen = screen; - d->eglSurface = EGL_NO_SURFACE; - d->input = input; - d->state = window()->windowState(); - d->connection = connection; - d->clipboard = clipboard; + uint role = roleVariant.toUInt(); + if (role < U_MAIN_ROLE || role > U_SHUTDOWN_DIALOG_ROLE) + return U_MAIN_ROLE; - static int id = 1; - d->id = id++; - - // Use client geometry if set explicitly, use available screen geometry otherwise. - QPlatformWindow::setGeometry(window()->geometry().isValid() && window()->geometry() != screen->geometry() ? - window()->geometry() : screen->availableGeometry()); - createWindow(); - DLOG("QMirClientWindow::QMirClientWindow (this=%p, w=%p, screen=%p, input=%p)", this, w, screen, input); + return static_cast<UAUiWindowRole>(role); } -QMirClientWindow::~QMirClientWindow() +QMirClientWindow *transientParentFor(QWindow *window) { - DLOG("QMirClientWindow::~QMirClientWindow"); - d->destroyEGLSurface(); - - mir_surface_release_sync(d->surface); - - delete d; + QWindow *parent = window->transientParent(); + return parent ? static_cast<QMirClientWindow *>(parent->handle()) : nullptr; } -void QMirClientWindowPrivate::createEGLSurface(EGLNativeWindowType nativeWindow) +Spec makeSurfaceSpec(QWindow *window, QMirClientInput *input, MirConnection *connection) { - DLOG("QMirClientWindowPrivate::createEGLSurface (this=%p, nativeWindow=%p)", - this, reinterpret_cast<void*>(nativeWindow)); - - eglSurface = eglCreateWindowSurface(screen->eglDisplay(), screen->eglConfig(), - nativeWindow, nullptr); + const auto geom = window->geometry(); + const int width = geom.width() > 0 ? geom.width() : 1; + const int height = geom.height() > 0 ? geom.height() : 1; + const auto pixelFormat = defaultPixelFormatFor(connection); + + if (U_ON_SCREEN_KEYBOARD_ROLE == roleFor(window)) { + DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating input method surface (width=%d, height=%d", window, width, height); + return Spec{mir_connection_create_spec_for_input_method(connection, width, height, pixelFormat)}; + } + + const Qt::WindowType type = window->type(); + if (type == Qt::Popup) { + auto parent = transientParentFor(window); + if (parent == nullptr) { + //NOTE: We cannot have a parentless popup - + //try using the last surface to receive input as that will most likely be + //the one that caused this popup to be created + parent = input->lastFocusedWindow(); + } + if (parent) { + auto pos = geom.topLeft(); + pos -= parent->geometry().topLeft(); + MirRectangle location{pos.x(), pos.y(), 0, 0}; + DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating menu surface(width:%d, height:%d)", window, width, height); + return Spec{mir_connection_create_spec_for_menu( + connection, width, height, pixelFormat, parent->mirSurface(), + &location, mir_edge_attachment_any)}; + } else { + DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - cannot create a menu without a parent!", window); + } + } else if (type == Qt::Dialog) { + auto parent = transientParentFor(window); + if (parent) { + // Modal dialog + DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating modal dialog (width=%d, height=%d", window, width, height); + return Spec{mir_connection_create_spec_for_modal_dialog(connection, width, height, pixelFormat, parent->mirSurface())}; + } else { + // TODO: do Qt parentless dialogs have the same semantics as mir? + DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating parentless dialog (width=%d, height=%d)", window, width, height); + return Spec{mir_connection_create_spec_for_dialog(connection, width, height, pixelFormat)}; + } + } + DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating normal surface(type=0x%x, width=%d, height=%d)", window, type, width, height); + return Spec{mir_connection_create_spec_for_normal_surface(connection, width, height, pixelFormat)}; +} - DASSERT(eglSurface != EGL_NO_SURFACE); +void setSizingConstraints(MirSurfaceSpec *spec, const QSize& minSize, const QSize& maxSize, const QSize& increment) +{ + mir_surface_spec_set_min_width(spec, minSize.width()); + mir_surface_spec_set_min_height(spec, minSize.height()); + if (maxSize.width() >= minSize.width()) { + mir_surface_spec_set_max_width(spec, maxSize.width()); + } + if (maxSize.height() >= minSize.height()) { + mir_surface_spec_set_max_height(spec, maxSize.height()); + } + if (increment.width() > 0) { + mir_surface_spec_set_width_increment(spec, increment.width()); + } + if (increment.height() > 0) { + mir_surface_spec_set_height_increment(spec, increment.height()); + } } -void QMirClientWindowPrivate::destroyEGLSurface() +MirSurface *createMirSurface(QWindow *window, QMirClientScreen *screen, QMirClientInput *input, MirConnection *connection) { - DLOG("QMirClientWindowPrivate::destroyEGLSurface (this=%p)", this); - if (eglSurface != EGL_NO_SURFACE) { - eglDestroySurface(screen->eglDisplay(), eglSurface); - eglSurface = EGL_NO_SURFACE; + auto spec = makeSurfaceSpec(window, input, connection); + const auto title = window->title().toUtf8(); + mir_surface_spec_set_name(spec.get(), title.constData()); + + setSizingConstraints(spec.get(), window->minimumSize(), window->maximumSize(), window->sizeIncrement()); + + if (window->windowState() == Qt::WindowFullScreen) { + mir_surface_spec_set_fullscreen_on_output(spec.get(), screen->mirOutputId()); } + + auto surface = mir_surface_create_sync(spec.get()); + Q_ASSERT(mir_surface_is_valid(surface)); + return 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() +// we need to guess the panel height (3GU) +int panelHeight() { if (qEnvironmentVariableIsSet("QT_MIRCLIENT_IGNORE_PANEL")) return 0; @@ -210,245 +251,412 @@ int QMirClientWindowPrivate::panelHeight() gridUnit = defaultGridUnit; } } - qreal densityPixelRatio = static_cast<qreal>(gridUnit) / defaultGridUnit; - return gridUnit * 3 + qFloor(densityPixelRatio) * 2; + return gridUnit * 3; } -namespace +} //namespace + +class QMirClientSurface { -static MirPixelFormat -mir_choose_default_pixel_format(MirConnection *connection) +public: + QMirClientSurface(QMirClientWindow *platformWindow, QMirClientScreen *screen, QMirClientInput *input, MirConnection *connection) + : mWindow(platformWindow->window()) + , mPlatformWindow(platformWindow) + , mInput(input) + , mConnection(connection) + , mMirSurface(createMirSurface(mWindow, screen, input, connection)) + , mEglDisplay(screen->eglDisplay()) + , mEglSurface(eglCreateWindowSurface(mEglDisplay, screen->eglConfig(), nativeWindowFor(mMirSurface), nullptr)) + , mVisible(false) + , mNeedsRepaint(false) + , mParented(mWindow->transientParent() || mWindow->parent()) + , mWindowState(mWindow->windowState()) + + { + mir_surface_set_event_handler(mMirSurface, surfaceEventCallback, this); + + // 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(mMirSurface, ¶meters); + + auto geom = mWindow->geometry(); + geom.setWidth(parameters.width); + geom.setHeight(parameters.height); + if (mWindowState == Qt::WindowFullScreen) { + geom.setY(0); + } else { + geom.setY(panelHeight()); + } + + // Assume that the buffer size matches the surface size at creation time + mBufferSize = geom.size(); + platformWindow->QPlatformWindow::setGeometry(geom); + QWindowSystemInterface::handleGeometryChange(mWindow, geom); + + DLOG("[ubuntumirclient QPA] created surface at (%d, %d) with size (%d, %d), title '%s', role: '%d'\n", + geom.x(), geom.y(), geom.width(), geom.height(), mWindow->title().toUtf8().constData(), roleFor(mWindow)); + } + + ~QMirClientSurface() + { + if (mEglSurface != EGL_NO_SURFACE) + eglDestroySurface(mEglDisplay, mEglSurface); + if (mMirSurface) + mir_surface_release_sync(mMirSurface); + } + + QMirClientSurface(QMirClientSurface const&) = delete; + QMirClientSurface& operator=(QMirClientSurface const&) = delete; + + void resize(const QSize& newSize); + void setState(Qt::WindowState newState); + void setVisible(bool state); + void updateTitle(const QString& title); + void setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment); + + void onSwapBuffersDone(); + void handleSurfaceResized(int width, int height); + int needsRepaint() const; + + EGLSurface eglSurface() const { return mEglSurface; } + MirSurface *mirSurface() const { return mMirSurface; } + +private: + static void surfaceEventCallback(MirSurface* surface, const MirEvent *event, void* context); + void postEvent(const MirEvent *event); + void updateSurface(); + + QWindow * const mWindow; + QMirClientWindow * const mPlatformWindow; + QMirClientInput * const mInput; + MirConnection * const mConnection; + + MirSurface * const mMirSurface; + const EGLDisplay mEglDisplay; + const EGLSurface mEglSurface; + + bool mVisible; + bool mNeedsRepaint; + bool mParented; + Qt::WindowState mWindowState; + QSize mBufferSize; + + QMutex mTargetSizeMutex; + QSize mTargetSize; +}; + +void QMirClientSurface::resize(const QSize& size) { - MirPixelFormat format[mir_pixel_formats]; - unsigned int nformats; + DLOG("[ubuntumirclient QPA] resize(window=%p, width=%d, height=%d)", mWindow, size.width(), size.height()); + + if (mWindowState == Qt::WindowFullScreen || mWindowState == Qt::WindowMaximized) { + DLOG("[ubuntumirclient QPA] resize(window=%p) - not resizing, window is maximized or fullscreen", mWindow); + return; + } - mir_connection_get_available_surface_formats(connection, - format, mir_pixel_formats, &nformats); + if (size.isEmpty()) { + DLOG("[ubuntumirclient QPA] resize(window=%p) - not resizing, size is empty", mWindow); + return; + } - return format[0]; + Spec spec{mir_connection_create_spec_for_changes(mConnection)}; + mir_surface_spec_set_width(spec.get(), size.width()); + mir_surface_spec_set_height(spec.get(), size.height()); + mir_surface_apply_spec(mMirSurface, spec.get()); } + +void QMirClientSurface::setState(Qt::WindowState newState) +{ + mir_wait_for(mir_surface_set_state(mMirSurface, qtWindowStateToMirSurfaceState(newState))); + mWindowState = newState; } -void QMirClientWindow::createWindow() +void QMirClientSurface::setVisible(bool visible) { - DLOG("QMirClientWindow::createWindow (this=%p)", this); + if (mVisible == visible) + return; - // 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; + mVisible = visible; - // FIXME(loicm) Opaque flag is forced for now for non-system sessions (applications) for - // performance reasons. - flags |= static_cast<uint>(IS_OPAQUE_FLAG); + if (mVisible) + updateSurface(); + + // TODO: Use the new mir_surface_state_hidden state instead of mir_surface_state_minimized. + // Will have to change qtmir and unity8 for that. + const auto newState = visible ? qtWindowStateToMirSurfaceState(mWindowState) : mir_surface_state_minimized; + mir_wait_for(mir_surface_set_state(mMirSurface, newState)); +} + +void QMirClientSurface::updateTitle(const QString& newTitle) +{ + const auto title = newTitle.toUtf8(); + Spec spec{mir_connection_create_spec_for_changes(mConnection)}; + mir_surface_spec_set_name(spec.get(), title.constData()); + mir_surface_apply_spec(mMirSurface, spec.get()); +} - const QByteArray title = (!window()->title().isNull()) ? window()->title().toUtf8() : "Window 1"; // legacy title - const int panelHeight = d->panelHeight(); +void QMirClientSurface::setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment) +{ + Spec spec{mir_connection_create_spec_for_changes(mConnection)}; + ::setSizingConstraints(spec.get(), minSize, maxSize, increment); + mir_surface_apply_spec(mMirSurface, spec.get()); +} + +void QMirClientSurface::handleSurfaceResized(int width, int height) +{ + QMutexLocker lock(&mTargetSizeMutex); + + // mir's resize event is mainly a signal that we need to redraw our content. We use the + // width/height as identifiers to figure out if this is the latest surface resize event + // that has posted, discarding any old ones. This avoids issuing too many redraw events. + // see TODO in postEvent as the ideal way we should handle this. + // The actual buffer size may or may have not changed at this point, so let the rendering + // thread drive the window geometry updates. + mNeedsRepaint = mTargetSize.width() == width && mTargetSize.height() == height; +} + +int QMirClientSurface::needsRepaint() const +{ + if (mNeedsRepaint) { + if (mTargetSize != mBufferSize) { + //If the buffer hasn't changed yet, we need at least two redraws, + //once to get the new buffer size and propagate the geometry changes + //and the second to redraw the content at the new size + return 2; + } else { + // The buffer size has already been updated so we only need one redraw + // to render at the new size + return 1; + } + } + return 0; +} +void QMirClientSurface::onSwapBuffersDone() +{ #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()); + static int sFrameNumber = 0; + ++sFrameNumber; #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); - } + EGLint eglSurfaceWidth = -1; + EGLint eglSurfaceHeight = -1; + eglQuerySurface(mEglDisplay, mEglSurface, EGL_WIDTH, &eglSurfaceWidth); + eglQuerySurface(mEglDisplay, mEglSurface, EGL_HEIGHT, &eglSurfaceHeight); - 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()); + const bool validSize = eglSurfaceWidth > 0 && eglSurfaceHeight > 0; - 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()); + if (validSize && (mBufferSize.width() != eglSurfaceWidth || mBufferSize.height() != eglSurfaceHeight)) { - // Create platform window - mir_wait_for(mir_surface_create(spec, surfaceCreateCallback, this)); - mir_surface_spec_release(spec); + DLOG("[ubuntumirclient QPA] onSwapBuffersDone(window=%p) [%d] - size changed (%d, %d) => (%d, %d)", + mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height(), eglSurfaceWidth, eglSurfaceHeight); - DASSERT(d->surface != NULL); - d->createEGLSurface((EGLNativeWindowType)mir_buffer_stream_get_egl_native_window(mir_surface_get_buffer_stream(d->surface))); + mBufferSize.rwidth() = eglSurfaceWidth; + mBufferSize.rheight() = eglSurfaceHeight; - 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)); + QRect newGeometry = mPlatformWindow->geometry(); + newGeometry.setSize(mBufferSize); + + mPlatformWindow->QPlatformWindow::setGeometry(newGeometry); + QWindowSystemInterface::handleGeometryChange(mWindow, newGeometry); + } else { +#if 0 + DLOG("[ubuntumirclient QPA] onSwapBuffersDone(window=%p) [%d] - buffer size (%d,%d)", + mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height()); +#endif } +} - // 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); +void QMirClientSurface::surfaceEventCallback(MirSurface *surface, const MirEvent *event, void* context) +{ + Q_UNUSED(surface); + Q_ASSERT(context != nullptr); - geometry.setWidth(parameters.width); - geometry.setHeight(parameters.height); - } + auto s = static_cast<QMirClientSurface *>(context); + s->postEvent(event); +} - DLOG("[ubuntumirclient QPA] created surface has size (%d, %d)", - geometry.width(), geometry.height()); +void QMirClientSurface::postEvent(const MirEvent *event) +{ + if (mir_event_type_resize == mir_event_get_type(event)) { + // TODO: The current event queue just accumulates all resize events; + // It would be nicer if we could update just one event if that event has not been dispatched. + // As a workaround, we use the width/height as an identifier of this latest event + // so the event handler (handleSurfaceResized) can discard/ignore old ones. + const auto resizeEvent = mir_event_get_resize_event(event); + const auto width = mir_resize_event_get_width(resizeEvent); + const auto height = mir_resize_event_get_height(resizeEvent); + DLOG("[ubuntumirclient QPA] resizeEvent(window=%p, width=%d, height=%d)", mWindow, width, height); + + QMutexLocker lock(&mTargetSizeMutex); + mTargetSize.rwidth() = width; + mTargetSize.rheight() = height; + } - // Assume that the buffer size matches the surface size at creation time - d->bufferSize = geometry.size(); + mInput->postEvent(mPlatformWindow, event); +} - // Tell Qt about the geometry. - QWindowSystemInterface::handleGeometryChange(window(), geometry); - QPlatformWindow::setGeometry(geometry); +void QMirClientSurface::updateSurface() +{ + DLOG("[ubuntumirclient QPA] updateSurface(window=%p)", mWindow); + + if (!mParented && mWindow->type() == Qt::Dialog) { + // The dialog may have been parented after creation time + // so morph it into a modal dialog + auto parent = transientParentFor(mWindow); + if (parent) { + DLOG("[ubuntumirclient QPA] updateSurface(window=%p) dialog now parented", mWindow); + mParented = true; + Spec spec{mir_connection_create_spec_for_changes(mConnection)}; + mir_surface_spec_set_parent(spec.get(), parent->mirSurface()); + mir_surface_apply_spec(mMirSurface, spec.get()); + } + } } -void QMirClientWindow::moveResize(const QRect& rect) +QMirClientWindow::QMirClientWindow(QWindow *w, const QSharedPointer<QMirClientClipboard> &clipboard, QMirClientScreen *screen, + QMirClientInput *input, MirConnection *connection) + : QObject(nullptr) + , QPlatformWindow(w) + , mId(makeId()) + , mClipboard(clipboard) + , mSurface(new QMirClientSurface{this, screen, input, connection}) { - (void) rect; - // TODO: Not yet supported by mir. + DLOG("[ubuntumirclient QPA] QMirClientWindow(window=%p, screen=%p, input=%p, surf=%p)", w, screen, input, mSurface.get()); } -void QMirClientWindow::handleSurfaceResize(int width, int height) +QMirClientWindow::~QMirClientWindow() { - QMutexLocker(&d->mutex); - LOG("QMirClientWindow::handleSurfaceResize(width=%d, height=%d)", width, height); + DLOG("[ubuntumirclient QPA] ~QMirClientWindow(window=%p)", this); +} - // 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::handleSurfaceResized(int width, int height) +{ + QMutexLocker lock(&mMutex); + DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p, width=%d, height=%d)", window(), width, height); + + mSurface->handleSurfaceResized(width, height); + + // This resize event could have occurred just after the last buffer swap for this window. + // This means the client may still be holding a buffer with the older size. The first redraw call + // will then render at the old size. After swapping the client now will get a new buffer with the + // updated size but it still needs re-rendering so another redraw may be needed. + // A mir API to drop the currently held buffer would help here, so that we wouldn't have to redraw twice + auto const numRepaints = mSurface->needsRepaint(); + DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p) redraw %d times", window(), numRepaints); + for (int i = 0; i < numRepaints; i++) { + DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p) repainting width=%d, height=%d", window(), geometry().size().width(), geometry().size().height()); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); } } -void QMirClientWindow::handleSurfaceFocusChange(bool focused) +void QMirClientWindow::handleSurfaceFocused() { - LOG("QMirClientWindow::handleSurfaceFocusChange(focused=%s)", focused ? "true" : "false"); - QWindow *activatedWindow = focused ? window() : nullptr; + DLOG("[ubuntumirclient QPA] handleSurfaceFocused(window=%p)", window()); - // System clipboard contents might have changed while this window was unfocused and wihtout + // System clipboard contents might have changed while this window was unfocused and without // 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); + mClipboard->requestDBusClipboardContents(); } void QMirClientWindow::setWindowState(Qt::WindowState state) { - QMutexLocker(&d->mutex); - DLOG("QMirClientWindow::setWindowState (this=%p, %s)", this, qtWindowStateToStr(state)); + QMutexLocker lock(&mMutex); + DLOG("[ubuntumirclient QPA] setWindowState(window=%p, %s)", this, qtWindowStateToStr(state)); + mSurface->setState(state); - if (state == d->state) - return; + updatePanelHeightHack(state); +} - // TODO: Perhaps we should check if the states are applied? - mir_wait_for(mir_surface_set_state(d->surface, qtWindowStateToMirSurfaceState(state))); - d->state = state; +/* + FIXME: Mir does not let clients know the position of their windows in the virtual + desktop space. So we have this ugly hack that assumes a phone situation where the + window is always on the top-left corner, right below the indicators panel if not + in fullscreen. + */ +void QMirClientWindow::updatePanelHeightHack(Qt::WindowState state) +{ + if (state == Qt::WindowFullScreen && geometry().y() != 0) { + QRect newGeometry = geometry(); + newGeometry.setY(0); + QPlatformWindow::setGeometry(newGeometry); + QWindowSystemInterface::handleGeometryChange(window(), newGeometry); + } else if (geometry().y() == 0) { + QRect newGeometry = geometry(); + newGeometry.setY(panelHeight()); + QPlatformWindow::setGeometry(newGeometry); + QWindowSystemInterface::handleGeometryChange(window(), newGeometry); + } } void QMirClientWindow::setGeometry(const QRect& rect) { - DLOG("QMirClientWindow::setGeometry (this=%p)", this); + QMutexLocker lock(&mMutex); + DLOG("[ubuntumirclient QPA] setGeometry (window=%p, x=%d, y=%d, width=%d, height=%d)", + window(), rect.x(), rect.y(), rect.width(), rect.height()); - bool doMoveResize; + //NOTE: mir surfaces cannot be moved by the client so ignore the topLeft coordinates + const auto newSize = rect.size(); + auto newGeometry = geometry(); + newGeometry.setSize(newSize); + QPlatformWindow::setGeometry(newGeometry); - { - QMutexLocker(&d->mutex); - QPlatformWindow::setGeometry(rect); - doMoveResize = d->state != Qt::WindowFullScreen && d->state != Qt::WindowMaximized; - } - - if (doMoveResize) { - moveResize(rect); - } + mSurface->resize(newSize); } void QMirClientWindow::setVisible(bool visible) { - QMutexLocker(&d->mutex); - DLOG("QMirClientWindow::setVisible (this=%p, visible=%s)", this, visible ? "true" : "false"); + QMutexLocker lock(&mMutex); + DLOG("[ubuntumirclient QPA] setVisible (window=%p, visible=%s)", window(), visible ? "true" : "false"); - if (visible) { - mir_wait_for(mir_surface_set_state(d->surface, qtWindowStateToMirSurfaceState(d->state))); + mSurface->setVisible(visible); + const QRect& exposeRect = visible ? QRect(QPoint(), geometry().size()) : QRect(); - 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)); - } + lock.unlock(); + QWindowSystemInterface::handleExposeEvent(window(), exposeRect); + QWindowSystemInterface::flushWindowSystemEvents(); } -void* QMirClientWindow::eglSurface() const +void QMirClientWindow::setWindowTitle(const QString& title) { - return d->eglSurface; + QMutexLocker lock(&mMutex); + DLOG("[ubuntumirclient QPA] setWindowTitle(window=%p) title=%s)", window(), title.toUtf8().constData()); + mSurface->updateTitle(title); } -WId QMirClientWindow::winId() const +void QMirClientWindow::propagateSizeHints() { - return d->id; + QMutexLocker lock(&mMutex); + const auto win = window(); + DLOG("[ubuntumirclient QPA] propagateSizeHints(window=%p) min(%d,%d), max(%d,%d) increment(%d, %d)", + win, win->minimumSize().width(), win->minimumSize().height(), + win->maximumSize().width(), win->maximumSize().height(), + win->sizeIncrement().width(), win->sizeIncrement().height()); + mSurface->setSizingConstraints(win->minimumSize(), win->maximumSize(), win->sizeIncrement()); } -void QMirClientWindow::onBuffersSwapped_threadSafe(int newBufferWidth, int newBufferHeight) +void* QMirClientWindow::eglSurface() const { - 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; + return mSurface->eglSurface(); +} - QRect newGeometry; +MirSurface *QMirClientWindow::mirSurface() const +{ + return mSurface->mirSurface(); +} - newGeometry = geometry(); - newGeometry.setWidth(d->bufferSize.width()); - newGeometry.setHeight(d->bufferSize.height()); +WId QMirClientWindow::winId() const +{ + return mId; +} - QPlatformWindow::setGeometry(newGeometry); - QWindowSystemInterface::handleGeometryChange(window(), newGeometry, QRect()); - } +void QMirClientWindow::onSwapBuffersDone() +{ + QMutexLocker lock(&mMutex); + mSurface->onSwapBuffersDone(); } diff --git a/src/plugins/platforms/mirclient/qmirclientwindow.h b/src/plugins/platforms/mirclient/qmirclientwindow.h index f342669544..4ec7879949 100644 --- a/src/plugins/platforms/mirclient/qmirclientwindow.h +++ b/src/plugins/platforms/mirclient/qmirclientwindow.h @@ -40,20 +40,23 @@ #include <qpa/qplatformwindow.h> #include <QSharedPointer> +#include <QMutex> -#include <mir_toolkit/mir_client_library.h> +#include <memory> class QMirClientClipboard; class QMirClientInput; class QMirClientScreen; -class QMirClientWindowPrivate; +class QMirClientSurface; +struct MirConnection; +struct MirSurface; class QMirClientWindow : public QObject, public QPlatformWindow { Q_OBJECT public: - QMirClientWindow(QWindow *w, QSharedPointer<QMirClientClipboard> clipboard, QMirClientScreen *screen, - QMirClientInput *input, MirConnection *mir_connection); + QMirClientWindow(QWindow *w, const QSharedPointer<QMirClientClipboard> &clipboard, QMirClientScreen *screen, + QMirClientInput *input, MirConnection *mirConnection); virtual ~QMirClientWindow(); // QPlatformWindow methods. @@ -61,20 +64,22 @@ public: void setGeometry(const QRect&) override; void setWindowState(Qt::WindowState state) override; void setVisible(bool visible) override; + void setWindowTitle(const QString &title) override; + void propagateSizeHints() 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; } + void *eglSurface() const; + MirSurface *mirSurface() const; + void handleSurfaceResized(int width, int height); + void handleSurfaceFocused(); + void onSwapBuffersDone(); private: - void createWindow(); - void moveResize(const QRect& rect); - - QMirClientWindowPrivate *d; + void updatePanelHeightHack(Qt::WindowState); + mutable QMutex mMutex; + const WId mId; + const QSharedPointer<QMirClientClipboard> mClipboard; + std::unique_ptr<QMirClientSurface> mSurface; }; #endif // QMIRCLIENTWINDOW_H diff --git a/src/plugins/platforms/windows/accessible/accessible.pri b/src/plugins/platforms/windows/accessible/accessible.pri index e26c6614e2..0774d907f2 100644 --- a/src/plugins/platforms/windows/accessible/accessible.pri +++ b/src/plugins/platforms/windows/accessible/accessible.pri @@ -1,17 +1,20 @@ SOURCES += \ - $$PWD/qwindowsmsaaaccessible.cpp \ $$PWD/qwindowsaccessibility.cpp \ $$PWD/comutils.cpp HEADERS += \ - $$PWD/qwindowsmsaaaccessible.h \ $$PWD/qwindowsaccessibility.h \ $$PWD/comutils.h -!mingw: { - SOURCES += $$PWD/iaccessible2.cpp - HEADERS += $$PWD/iaccessible2.h - include(../../../../3rdparty/iaccessible2/iaccessible2.pri) +!wince: { + SOURCES += $$PWD/qwindowsmsaaaccessible.cpp + HEADERS += $$PWD/qwindowsmsaaaccessible.h + + !mingw: { + SOURCES += $$PWD/iaccessible2.cpp + HEADERS += $$PWD/iaccessible2.h + include(../../../../3rdparty/iaccessible2/iaccessible2.pri) + } } -mingw: LIBS *= -luuid
\ No newline at end of file +mingw: LIBS *= -luuid diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp index 44a9030c0c..13eee8e0fa 100644 --- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp +++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp @@ -56,10 +56,12 @@ #include <QtGui/qguiapplication.h> #include "qwindowsaccessibility.h" -#ifdef Q_CC_MINGW -# include "qwindowsmsaaaccessible.h" -#else -# include "iaccessible2.h" +#if !defined(Q_OS_WINCE) +# ifdef Q_CC_MINGW +# include "qwindowsmsaaaccessible.h" +# else +# include "iaccessible2.h" +# endif #endif #include "comutils.h" @@ -74,8 +76,9 @@ #if !defined(WINABLEAPI) # if defined(Q_OS_WINCE) # include <bldver.h> +# else +# include <winable.h> # endif -# include <winable.h> #endif #include <servprov.h> @@ -199,6 +202,11 @@ QWindow *QWindowsAccessibility::windowHelper(const QAccessibleInterface *iface) */ IAccessible *QWindowsAccessibility::wrap(QAccessibleInterface *acc) { +#if defined(Q_OS_WINCE) + Q_UNUSED(acc); + + return 0; +#else if (!acc) return 0; @@ -206,14 +214,15 @@ IAccessible *QWindowsAccessibility::wrap(QAccessibleInterface *acc) if (!QAccessible::uniqueId(acc)) QAccessible::registerAccessibleInterface(acc); -#ifdef Q_CC_MINGW +# ifdef Q_CC_MINGW QWindowsMsaaAccessible *wacc = new QWindowsMsaaAccessible(acc); -#else +# else QWindowsIA2Accessible *wacc = new QWindowsIA2Accessible(acc); -#endif +# endif IAccessible *iacc = 0; wacc->QueryInterface(IID_IAccessible, (void**)&iacc); return iacc; +#endif // defined(Q_OS_WINCE) } /* @@ -236,6 +245,7 @@ void QWindowsAccessibility::cleanup() bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, WPARAM wParam, LPARAM lParam, LRESULT *lResult) { +#if !defined(Q_OS_WINCE) if (static_cast<long>(lParam) == static_cast<long>(UiaRootObjectId)) { /* For UI Automation */ } else if ((DWORD)lParam == DWORD(OBJID_CLIENT)) { @@ -254,9 +264,7 @@ bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, W if (!oleaccChecked) { oleaccChecked = true; -#if !defined(Q_OS_WINCE) ptrLresultFromObject = (PtrLresultFromObject)QSystemLibrary::resolve(QLatin1String("oleacc"), "LresultFromObject"); -#endif } if (ptrLresultFromObject) { @@ -275,6 +283,12 @@ bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, W } } } +#else + Q_UNUSED(hwnd); + Q_UNUSED(wParam); + Q_UNUSED(lParam); + Q_UNUSED(lResult); +#endif // !defined(Q_OS_WINCE) return false; } diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp index 298562e12f..0f41d01716 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -45,6 +45,7 @@ #include <QtGui/QWindow> #include <QtGui/QPainter> #include <private/qhighdpiscaling_p.h> +#include <private/qimage_p.h> #include <QtCore/QDebug> @@ -58,7 +59,8 @@ QT_BEGIN_NAMESPACE */ QWindowsBackingStore::QWindowsBackingStore(QWindow *window) : - QPlatformBackingStore(window) + QPlatformBackingStore(window), + m_alphaNeedsFill(false) { qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << window; } @@ -150,8 +152,16 @@ void QWindowsBackingStore::resize(const QSize &size, const QRegion ®ion) << " from: " << (m_image.isNull() ? QSize() : m_image->image().size()); } #endif - const QImage::Format format = window()->format().hasAlpha() ? - QImage::Format_ARGB32_Premultiplied : QWindowsNativeImage::systemFormat(); + QImage::Format format = window()->format().hasAlpha() ? + QImage::Format_ARGB32_Premultiplied : QWindowsNativeImage::systemFormat(); + + // The backingstore composition (enabling render-to-texture widgets) + // punches holes in the backingstores using the alpha channel. Hence + // the need for a true alpha format. + if (QImage::toPixelFormat(format).alphaUsage() == QPixelFormat::UsesAlpha) + m_alphaNeedsFill = true; + else // upgrade but here we know app painting does not rely on alpha hence no need to fill + format = qt_alphaVersionForPainting(format); QWindowsNativeImage *oldwni = m_image.data(); QWindowsNativeImage *newwni = new QWindowsNativeImage(size.width(), size.height(), format); @@ -192,7 +202,7 @@ void QWindowsBackingStore::beginPaint(const QRegion ®ion) if (QWindowsContext::verbose > 1) qCDebug(lcQpaBackingStore) <<__FUNCTION__ << region; - if (m_image->image().hasAlphaChannel()) { + if (m_alphaNeedsFill) { QPainter p(&m_image->image()); p.setCompositionMode(QPainter::CompositionMode_Source); const QColor blank = Qt::transparent; diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.h b/src/plugins/platforms/windows/qwindowsbackingstore.h index b5b1d8feff..26c79348a9 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.h +++ b/src/plugins/platforms/windows/qwindowsbackingstore.h @@ -71,6 +71,7 @@ public: private: QScopedPointer<QWindowsNativeImage> m_image; + bool m_alphaNeedsFill; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 44f3302644..594208ab17 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -882,12 +882,12 @@ public: inline static QWindowsNativeFileDialogBase *create(QFileDialogOptions::AcceptMode am, const QWindowsFileDialogSharedData &data); - virtual void setWindowTitle(const QString &title); + void setWindowTitle(const QString &title) Q_DECL_OVERRIDE; inline void setMode(QFileDialogOptions::FileMode mode, QFileDialogOptions::AcceptMode acceptMode, QFileDialogOptions::FileDialogOptions options); inline void setDirectory(const QUrl &directory); inline void updateDirectory() { setDirectory(m_data.directory()); } inline QString directory() const; - virtual void doExec(HWND owner = 0); + void doExec(HWND owner = 0) Q_DECL_OVERRIDE; virtual void setNameFilters(const QStringList &f); inline void selectNameFilter(const QString &filter); inline void updateSelectedNameFilter() { selectNameFilter(m_data.selectedNameFilter()); } @@ -916,7 +916,7 @@ signals: void filterSelected(const QString & filter); public slots: - virtual void close(); + void close() Q_DECL_OVERRIDE; protected: explicit QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data); @@ -1466,9 +1466,9 @@ class QWindowsNativeSaveFileDialog : public QWindowsNativeFileDialogBase public: explicit QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data) : QWindowsNativeFileDialogBase(data) {} - virtual void setNameFilters(const QStringList &f); - virtual QList<QUrl> selectedFiles() const; - virtual QList<QUrl> dialogResult() const; + void setNameFilters(const QStringList &f) Q_DECL_OVERRIDE; + QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; + QList<QUrl> dialogResult() const Q_DECL_OVERRIDE; }; // Return the first suffix from the name filter "Foo files (*.foo;*.bar)" -> "foo". @@ -1537,8 +1537,8 @@ class QWindowsNativeOpenFileDialog : public QWindowsNativeFileDialogBase public: explicit QWindowsNativeOpenFileDialog(const QWindowsFileDialogSharedData &data) : QWindowsNativeFileDialogBase(data) {} - virtual QList<QUrl> selectedFiles() const; - virtual QList<QUrl> dialogResult() const; + QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; + QList<QUrl> dialogResult() const Q_DECL_OVERRIDE; private: inline IFileOpenDialog *openFileDialog() const @@ -1622,7 +1622,7 @@ public: virtual QString selectedNameFilter() const Q_DECL_OVERRIDE; private: - virtual QWindowsNativeDialogBase *createNativeDialog(); + QWindowsNativeDialogBase *createNativeDialog() Q_DECL_OVERRIDE; inline QWindowsNativeFileDialogBase *nativeFileDialog() const { return static_cast<QWindowsNativeFileDialogBase *>(nativeDialog()); } @@ -1750,14 +1750,13 @@ public: static QWindowsXpNativeFileDialog *create(const OptionsPtr &options, const QWindowsFileDialogSharedData &data); - virtual void setWindowTitle(const QString &t) { m_title = t; } - virtual void doExec(HWND owner = 0); - virtual QPlatformDialogHelper::DialogCode result() const { return m_result; } + void setWindowTitle(const QString &t) Q_DECL_OVERRIDE { m_title = t; } + void doExec(HWND owner = 0) Q_DECL_OVERRIDE; int existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam); public slots: - virtual void close() {} + void close() Q_DECL_OVERRIDE {} private: typedef BOOL (APIENTRY *PtrGetOpenFileNameW)(LPOPENFILENAMEW); @@ -1993,19 +1992,19 @@ class QWindowsXpFileDialogHelper : public QWindowsDialogHelperBase<QPlatformFile { public: QWindowsXpFileDialogHelper() {} - virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return false; } - virtual bool defaultNameFilterDisables() const + bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const Q_DECL_OVERRIDE { return false; } + bool defaultNameFilterDisables() const Q_DECL_OVERRIDE { return true; } - virtual void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; - virtual QUrl directory() const Q_DECL_OVERRIDE; - virtual void selectFile(const QUrl &url) Q_DECL_OVERRIDE; - virtual QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; - virtual void setFilter() Q_DECL_OVERRIDE {} - virtual void selectNameFilter(const QString &) Q_DECL_OVERRIDE; - virtual QString selectedNameFilter() const Q_DECL_OVERRIDE; + void setDirectory(const QUrl &directory) Q_DECL_OVERRIDE; + QUrl directory() const Q_DECL_OVERRIDE; + void selectFile(const QUrl &url) Q_DECL_OVERRIDE; + QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; + void setFilter() Q_DECL_OVERRIDE {} + void selectNameFilter(const QString &) Q_DECL_OVERRIDE; + QString selectedNameFilter() const Q_DECL_OVERRIDE; private: - virtual QWindowsNativeDialogBase *createNativeDialog(); + QWindowsNativeDialogBase *createNativeDialog() Q_DECL_OVERRIDE; inline QWindowsXpNativeFileDialog *nativeFileDialog() const { return static_cast<QWindowsXpNativeFileDialog *>(nativeDialog()); } @@ -2079,14 +2078,13 @@ public: explicit QWindowsNativeColorDialog(const SharedPointerColor &color); - virtual void setWindowTitle(const QString &) {} - virtual QPlatformDialogHelper::DialogCode result() const { return m_code; } + void setWindowTitle(const QString &) Q_DECL_OVERRIDE {} public slots: - virtual void close() {} + void close() Q_DECL_OVERRIDE {} private: - virtual void doExec(HWND owner = 0); + void doExec(HWND owner = 0) Q_DECL_OVERRIDE; COLORREF m_customColors[CustomColorCount]; QPlatformDialogHelper::DialogCode m_code; diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 8c9882c65a..bde9a77e77 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -84,7 +84,7 @@ public: void setPixmap(const QPixmap &p); protected: - void paintEvent(QPaintEvent *) + void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE { QPainter painter(this); painter.drawPixmap(0, 0, m_pixmap); diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h index 7a64fa987c..988b0012f7 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h +++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h @@ -49,12 +49,15 @@ QT_BEGIN_NAMESPACE class QWindowsFontDatabaseFT : public QBasicFontDatabase { public: - void populateFontDatabase(); + void populateFontDatabase() Q_DECL_OVERRIDE; void populateFamily(const QString &familyName) Q_DECL_OVERRIDE; - QFontEngine *fontEngine(const QFontDef &fontDef, void *handle); - QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference); + QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) Q_DECL_OVERRIDE; + QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, + QFont::HintingPreference hintingPreference) Q_DECL_OVERRIDE; - QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; + QStringList fallbacksForFamily(const QString &family, QFont::Style style, + QFont::StyleHint styleHint, + QChar::Script script) const Q_DECL_OVERRIDE; QString fontDir() const Q_DECL_OVERRIDE; QFont defaultFont() const Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h index 0f7cfce4f1..75bff00326 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.h +++ b/src/plugins/platforms/windows/qwindowsfontengine.h @@ -90,7 +90,7 @@ public: void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) Q_DECL_OVERRIDE; virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, - QPainterPath *path, QTextItem::RenderFlags flags); + QPainterPath *path, QTextItem::RenderFlags flags) Q_DECL_OVERRIDE; HGDIOBJ selectDesignFont() const; diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp index c8417b655b..02b56fc40a 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp @@ -526,13 +526,8 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, int margin, const QTransform &xform) { - glyph_metrics_t metrics = QFontEngine::boundingBox(t, xform); - // This needs to be kept in sync with alphaMapBoundingBox - int width = (metrics.width + margin * 2).ceil().toInt() ; - int height = (metrics.height + margin * 2).ceil().toInt(); - UINT16 glyphIndex = t; - FLOAT glyphAdvance = metrics.xoff.toReal(); + FLOAT glyphAdvance = 0; DWRITE_GLYPH_OFFSET glyphOffset; glyphOffset.advanceOffset = 0; @@ -548,12 +543,9 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, glyphRun.bidiLevel = 0; glyphRun.glyphOffsets = &glyphOffset; - QFixed x = margin - metrics.x.floor() + subPixelPosition; - QFixed y = margin - metrics.y.floor(); - DWRITE_MATRIX transform; - transform.dx = x.toReal(); - transform.dy = y.toReal(); + transform.dx = subPixelPosition.toReal(); + transform.dy = 0; transform.m11 = xform.m11(); transform.m12 = xform.m12(); transform.m21 = xform.m21(); @@ -577,46 +569,56 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, if (SUCCEEDED(hr)) { RECT rect; - rect.left = 0; - rect.top = 0; - rect.right = width; - rect.bottom = height; + glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect); - int size = width * height * 3; - BYTE *alphaValues = new BYTE[size]; - memset(alphaValues, 0, size); + rect.left -= margin; + rect.top -= margin; + rect.right += margin; + rect.bottom += margin; - hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, - &rect, - alphaValues, - size); + const int width = rect.right - rect.left; + const int height = rect.bottom - rect.top; - if (SUCCEEDED(hr)) { - QImage img(width, height, QImage::Format_RGB32); - img.fill(0xffffffff); + const int size = width * height * 3; + if (size > 0) { + BYTE *alphaValues = new BYTE[size]; + memset(alphaValues, 0, size); - for (int y=0; y<height; ++y) { - uint *dest = reinterpret_cast<uint *>(img.scanLine(y)); - BYTE *src = alphaValues + width * 3 * y; + hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, + &rect, + alphaValues, + size); - for (int x=0; x<width; ++x) { - dest[x] = *(src) << 16 - | *(src + 1) << 8 - | *(src + 2); + if (SUCCEEDED(hr)) { + QImage img(width, height, QImage::Format_RGB32); + img.fill(0xffffffff); - src += 3; + for (int y=0; y<height; ++y) { + uint *dest = reinterpret_cast<uint *>(img.scanLine(y)); + BYTE *src = alphaValues + width * 3 * y; + + for (int x=0; x<width; ++x) { + dest[x] = *(src) << 16 + | *(src + 1) << 8 + | *(src + 2); + + src += 3; + } } - } - delete[] alphaValues; - glyphAnalysis->Release(); + delete[] alphaValues; + glyphAnalysis->Release(); + + return img; + } else { + delete[] alphaValues; + glyphAnalysis->Release(); - return img; + qErrnoWarning("%s: CreateAlphaTexture failed", __FUNCTION__); + } } else { - delete[] alphaValues; glyphAnalysis->Release(); - - qErrnoWarning("%s: CreateAlphaTexture failed", __FUNCTION__); + qWarning("%s: Glyph has no bounds", __FUNCTION__); } } else { @@ -730,16 +732,65 @@ QString QWindowsFontEngineDirectWrite::fontNameSubstitute(const QString &familyN return QSettings(QLatin1String(keyC), QSettings::NativeFormat).value(familyName, familyName).toString(); } -glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph, QFixed pos, const QTransform &matrix, GlyphFormat format) +glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph, + QFixed subPixelPosition, + const QTransform &matrix, + GlyphFormat format) { - Q_UNUSED(pos); Q_UNUSED(format); + glyph_metrics_t bbox = QFontEngine::boundingBox(glyph, matrix); // To get transformed advance + + UINT16 glyphIndex = glyph; + FLOAT glyphAdvance = 0; + + DWRITE_GLYPH_OFFSET glyphOffset; + glyphOffset.advanceOffset = 0; + glyphOffset.ascenderOffset = 0; + + DWRITE_GLYPH_RUN glyphRun; + glyphRun.fontFace = m_directWriteFontFace; + glyphRun.fontEmSize = fontDef.pixelSize; + glyphRun.glyphCount = 1; + glyphRun.glyphIndices = &glyphIndex; + glyphRun.glyphAdvances = &glyphAdvance; + glyphRun.isSideways = false; + glyphRun.bidiLevel = 0; + glyphRun.glyphOffsets = &glyphOffset; + + DWRITE_MATRIX transform; + transform.dx = subPixelPosition.toReal(); + transform.dy = 0; + transform.m11 = matrix.m11(); + transform.m12 = matrix.m12(); + transform.m21 = matrix.m21(); + transform.m22 = matrix.m22(); + + IDWriteGlyphRunAnalysis *glyphAnalysis = NULL; + HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( + &glyphRun, + 1.0f, + &transform, + DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC, + DWRITE_MEASURING_MODE_NATURAL, + 0.0, 0.0, + &glyphAnalysis + ); - int margin = glyphMargin(QFontEngine::Format_A32); - glyph_metrics_t gm = QFontEngine::boundingBox(glyph, matrix); - gm.width += margin * 2; - gm.height += margin * 2; - return gm; + if (SUCCEEDED(hr)) { + RECT rect; + glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect); + glyphAnalysis->Release(); + + int margin = glyphMargin(QFontEngine::Format_A32); + + return glyph_metrics_t(rect.left, + rect.top, + rect.right - rect.left + margin * 2, + rect.bottom - rect.top + margin * 2, + bbox.xoff, bbox.yoff); + } else { + return glyph_metrics_t(); + } } QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h index 99bdb2dd49..25709d8ee1 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h @@ -67,35 +67,37 @@ public: void initFontInfo(const QFontDef &request, int dpi, IDWriteFont *font); - QFixed lineThickness() const; - QFixed underlinePosition() const; - bool getSfntTableData(uint tag, uchar *buffer, uint *length) const; - QFixed emSquareSize() const; + QFixed lineThickness() const Q_DECL_OVERRIDE; + QFixed underlinePosition() const Q_DECL_OVERRIDE; + bool getSfntTableData(uint tag, uchar *buffer, uint *length) const Q_DECL_OVERRIDE; + QFixed emSquareSize() const Q_DECL_OVERRIDE; glyph_t glyphIndex(uint ucs4) const Q_DECL_OVERRIDE; - bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const; - void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const; + bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, + ShaperFlags flags) const Q_DECL_OVERRIDE; + void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const Q_DECL_OVERRIDE; void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, - QPainterPath *path, QTextItem::RenderFlags flags); + QPainterPath *path, QTextItem::RenderFlags flags) Q_DECL_OVERRIDE; - glyph_metrics_t boundingBox(const QGlyphLayout &glyphs); - glyph_metrics_t boundingBox(glyph_t g); - glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat); + glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) Q_DECL_OVERRIDE; + glyph_metrics_t boundingBox(glyph_t g) Q_DECL_OVERRIDE; + glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed, + const QTransform &matrix, GlyphFormat) Q_DECL_OVERRIDE; - QFixed ascent() const; - QFixed descent() const; - QFixed leading() const; - QFixed xHeight() const; - qreal maxCharWidth() const; + QFixed ascent() const Q_DECL_OVERRIDE; + QFixed descent() const Q_DECL_OVERRIDE; + QFixed leading() const Q_DECL_OVERRIDE; + QFixed xHeight() const Q_DECL_OVERRIDE; + qreal maxCharWidth() const Q_DECL_OVERRIDE; - bool supportsSubPixelPositions() const; + bool supportsSubPixelPositions() const Q_DECL_OVERRIDE; - QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition); - QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t); - QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, const QTransform &xform); + QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) Q_DECL_OVERRIDE; + QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) Q_DECL_OVERRIDE; + QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, const QTransform &xform) Q_DECL_OVERRIDE; - QFontEngine *cloneWithSize(qreal pixelSize) const; + QFontEngine *cloneWithSize(qreal pixelSize) const Q_DECL_OVERRIDE; const QSharedPointer<QWindowsFontEngineData> &fontEngineData() const { return m_fontEngineData; } diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index 73c5f1d517..9658ef711d 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -66,12 +66,12 @@ public: explicit QWindowsIntegration(const QStringList ¶mList); virtual ~QWindowsIntegration(); - bool hasCapability(QPlatformIntegration::Capability cap) const; + bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE; - QPlatformWindow *createPlatformWindow(QWindow *window) const; + QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE; #ifndef QT_NO_OPENGL QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE; - QOpenGLContext::OpenGLModuleType openGLModuleType(); + QOpenGLContext::OpenGLModuleType openGLModuleType() Q_DECL_OVERRIDE; static QWindowsStaticOpenGLContext *staticOpenGLContext(); #endif QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE; @@ -89,7 +89,7 @@ public: QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE; QStringList themeNames() const Q_DECL_OVERRIDE; QPlatformTheme *createPlatformTheme(const QString &name) const Q_DECL_OVERRIDE; - QPlatformServices *services() const; + QPlatformServices *services() const Q_DECL_OVERRIDE; QVariant styleHint(StyleHint hint) const Q_DECL_OVERRIDE; Qt::KeyboardModifiers queryKeyboardModifiers() const Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp index 8c6ff58aa1..a16397f169 100644 --- a/src/plugins/platforms/windows/qwindowsmime.cpp +++ b/src/plugins/platforms/windows/qwindowsmime.cpp @@ -903,14 +903,14 @@ public: QWindowsMimeHtml(); // for converting from Qt - bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const; - bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const; - QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const; + bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const Q_DECL_OVERRIDE; + bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const Q_DECL_OVERRIDE; + QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const Q_DECL_OVERRIDE; // for converting to Qt - bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const; - QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const; - QString mimeForFormat(const FORMATETC &formatetc) const; + bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const Q_DECL_OVERRIDE; + QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const Q_DECL_OVERRIDE; + QString mimeForFormat(const FORMATETC &formatetc) const Q_DECL_OVERRIDE; private: int CF_HTML; @@ -1035,14 +1035,14 @@ class QWindowsMimeImage : public QWindowsMime public: QWindowsMimeImage(); // for converting from Qt - bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const; - bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const; - QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const; + bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const Q_DECL_OVERRIDE; + bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const Q_DECL_OVERRIDE; + QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const Q_DECL_OVERRIDE; // for converting to Qt - bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const; - QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const; - QString mimeForFormat(const FORMATETC &formatetc) const; + bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const Q_DECL_OVERRIDE; + QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const Q_DECL_OVERRIDE; + QString mimeForFormat(const FORMATETC &formatetc) const Q_DECL_OVERRIDE; private: bool hasOriginalDIBV5(IDataObject *pDataObj) const; UINT CF_PNG; @@ -1189,14 +1189,14 @@ public: QBuiltInMimes(); // for converting from Qt - bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const; - bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const; - QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const; + bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const Q_DECL_OVERRIDE; + bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const Q_DECL_OVERRIDE; + QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const Q_DECL_OVERRIDE; // for converting to Qt - bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const; - QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const; - QString mimeForFormat(const FORMATETC &formatetc) const; + bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const Q_DECL_OVERRIDE; + QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const Q_DECL_OVERRIDE; + QString mimeForFormat(const FORMATETC &formatetc) const Q_DECL_OVERRIDE; private: QMap<int, QString> outFormats; @@ -1309,14 +1309,14 @@ public: QLastResortMimes(); // for converting from Qt - bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const; - bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const; - QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const; + bool canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const Q_DECL_OVERRIDE; + bool convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const Q_DECL_OVERRIDE; + QVector<FORMATETC> formatsForMime(const QString &mimeType, const QMimeData *mimeData) const Q_DECL_OVERRIDE; // for converting to Qt - bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const; - QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const; - QString mimeForFormat(const FORMATETC &formatetc) const; + bool canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const Q_DECL_OVERRIDE; + QVariant convertToMime(const QString &mime, IDataObject *pDataObj, QVariant::Type preferredType) const Q_DECL_OVERRIDE; + QString mimeForFormat(const FORMATETC &formatetc) const Q_DECL_OVERRIDE; private: QMap<int, QString> formats; diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index 15bb941a9d..45db934e47 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -57,9 +57,9 @@ public: bool usePlatformNativeDialog(DialogType type) const Q_DECL_OVERRIDE; QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const Q_DECL_OVERRIDE; QVariant themeHint(ThemeHint) const Q_DECL_OVERRIDE; - virtual const QPalette *palette(Palette type = SystemPalette) const + const QPalette *palette(Palette type = SystemPalette) const Q_DECL_OVERRIDE { return m_palettes[type]; } - virtual const QFont *font(Font type = SystemFont) const + const QFont *font(Font type = SystemFont) const Q_DECL_OVERRIDE { return m_fonts[type]; } QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index a3f072b7a8..8497931b9a 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -177,7 +177,7 @@ public: void raise() Q_DECL_OVERRIDE; void lower() Q_DECL_OVERRIDE; - void windowEvent(QEvent *event); + void windowEvent(QEvent *event) Q_DECL_OVERRIDE; void propagateSizeHints() Q_DECL_OVERRIDE; static bool handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &marginsDp); @@ -195,8 +195,8 @@ public: bool startSystemResize(const QPoint &pos, Qt::Corner corner) Q_DECL_OVERRIDE; - void setFrameStrutEventsEnabled(bool enabled); - bool frameStrutEventsEnabled() const { return testFlag(FrameStrutEventsEnabled); } + void setFrameStrutEventsEnabled(bool enabled) Q_DECL_OVERRIDE; + bool frameStrutEventsEnabled() const Q_DECL_OVERRIDE { return testFlag(FrameStrutEventsEnabled); } QMargins customMargins() const { return m_data.customMargins; } void setCustomMargins(const QMargins &m); @@ -243,15 +243,15 @@ public: void setEnabled(bool enabled); bool isEnabled() const; - void setWindowIcon(const QIcon &icon); + void setWindowIcon(const QIcon &icon) Q_DECL_OVERRIDE; void *surface(void *nativeConfig, int *err); void invalidateSurface() Q_DECL_OVERRIDE; void aboutToMakeCurrent(); #ifndef Q_OS_WINCE - void setAlertState(bool enabled); - bool isAlertState() const { return testFlag(AlertState); } + void setAlertState(bool enabled) Q_DECL_OVERRIDE; + bool isAlertState() const Q_DECL_OVERRIDE { return testFlag(AlertState); } void alertWindow(int durationMs = 0); void stopAlertWindow(); #endif diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index 71e92f33ca..2281bf56cc 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -59,10 +59,16 @@ #include <windows.ui.core.h> #include <windows.ui.viewmanagement.h> #include <windows.graphics.display.h> -#ifdef Q_OS_WINPHONE + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) # include <windows.phone.ui.input.h> +# if _MSC_VER >= 1900 +# include <windows.foundation.metadata.h> + using namespace ABI::Windows::Foundation::Metadata; +# endif #endif + using namespace Microsoft::WRL; using namespace Microsoft::WRL::Wrappers; using namespace ABI::Windows::Foundation; @@ -73,13 +79,13 @@ 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 +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) using namespace ABI::Windows::Phone::UI::Input; #endif typedef IEventHandler<IInspectable *> ResumeHandler; typedef IEventHandler<SuspendingEventArgs *> SuspendHandler; -#ifdef Q_OS_WINPHONE +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) typedef IEventHandler<BackPressedEventArgs*> BackPressedHandler; typedef IEventHandler<CameraEventArgs*> CameraButtonHandler; #endif @@ -88,7 +94,7 @@ QT_BEGIN_NAMESPACE typedef HRESULT (__stdcall ICoreApplication::*CoreApplicationCallbackRemover)(EventRegistrationToken); uint qHash(CoreApplicationCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } -#ifdef Q_OS_WINPHONE +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) typedef HRESULT (__stdcall IHardwareButtonsStatics::*HardwareButtonsCallbackRemover)(EventRegistrationToken); uint qHash(HardwareButtonsCallbackRemover key) { void *ptr = *(void **)(&key); return qHash(ptr); } typedef HRESULT (__stdcall IHardwareButtonsStatics2::*HardwareButtons2CallbackRemover)(EventRegistrationToken); @@ -105,11 +111,12 @@ public: ComPtr<ICoreApplication> application; QHash<CoreApplicationCallbackRemover, EventRegistrationToken> applicationTokens; -#ifdef Q_OS_WINPHONE +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) ComPtr<IHardwareButtonsStatics> hardwareButtons; QHash<HardwareButtonsCallbackRemover, EventRegistrationToken> buttonsTokens; ComPtr<IHardwareButtonsStatics2> cameraButtons; QHash<HardwareButtons2CallbackRemover, EventRegistrationToken> cameraTokens; + boolean hasHardwareButtons; bool cameraHalfPressed : 1; bool cameraPressed : 1; #endif @@ -132,31 +139,48 @@ QWinRTIntegration::QWinRTIntegration() : d_ptr(new QWinRTIntegrationPrivate) &d->applicationTokens[&ICoreApplication::remove_Resuming]); 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, &QWinRTIntegration::onBackButtonPressed).Get(), - &d->buttonsTokens[&IHardwareButtonsStatics::remove_BackPressed]); - Q_ASSERT_SUCCEEDED(hr); +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) +#if _MSC_VER >= 1900 + d->hasHardwareButtons = false; + ComPtr<IApiInformationStatics> apiInformationStatics; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_Metadata_ApiInformation).Get(), + IID_PPV_ARGS(&apiInformationStatics)); - hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(), - IID_PPV_ARGS(&d->cameraButtons)); - Q_ASSERT_SUCCEEDED(hr); - if (qEnvironmentVariableIntValue("QT_QPA_ENABLE_CAMERA_KEYS")) { - hr = d->cameraButtons->add_CameraPressed(Callback<CameraButtonHandler>(this, &QWinRTIntegration::onCameraPressed).Get(), - &d->cameraTokens[&IHardwareButtonsStatics2::remove_CameraPressed]); + if (SUCCEEDED(hr)) { + const HStringReference valueRef(L"Windows.Phone.UI.Input.HardwareButtons"); + hr = apiInformationStatics->IsTypePresent(valueRef.Get(), &d->hasHardwareButtons); + } +#else + d->hasHardwareButtons = true; +#endif // _MSC_VER >= 1900 + + if (d->hasHardwareButtons) { + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(), + IID_PPV_ARGS(&d->hardwareButtons)); Q_ASSERT_SUCCEEDED(hr); - hr = d->cameraButtons->add_CameraHalfPressed(Callback<CameraButtonHandler>(this, &QWinRTIntegration::onCameraHalfPressed).Get(), - &d->cameraTokens[&IHardwareButtonsStatics2::remove_CameraHalfPressed]); + hr = d->hardwareButtons->add_BackPressed(Callback<BackPressedHandler>(this, &QWinRTIntegration::onBackButtonPressed).Get(), + &d->buttonsTokens[&IHardwareButtonsStatics::remove_BackPressed]); Q_ASSERT_SUCCEEDED(hr); - hr = d->cameraButtons->add_CameraReleased(Callback<CameraButtonHandler>(this, &QWinRTIntegration::onCameraReleased).Get(), - &d->cameraTokens[&IHardwareButtonsStatics2::remove_CameraReleased]); + + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Phone_UI_Input_HardwareButtons).Get(), + IID_PPV_ARGS(&d->cameraButtons)); Q_ASSERT_SUCCEEDED(hr); + if (qEnvironmentVariableIntValue("QT_QPA_ENABLE_CAMERA_KEYS")) { + hr = d->cameraButtons->add_CameraPressed(Callback<CameraButtonHandler>(this, &QWinRTIntegration::onCameraPressed).Get(), + &d->cameraTokens[&IHardwareButtonsStatics2::remove_CameraPressed]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->cameraButtons->add_CameraHalfPressed(Callback<CameraButtonHandler>(this, &QWinRTIntegration::onCameraHalfPressed).Get(), + &d->cameraTokens[&IHardwareButtonsStatics2::remove_CameraHalfPressed]); + Q_ASSERT_SUCCEEDED(hr); + hr = d->cameraButtons->add_CameraReleased(Callback<CameraButtonHandler>(this, &QWinRTIntegration::onCameraReleased).Get(), + &d->cameraTokens[&IHardwareButtonsStatics2::remove_CameraReleased]); + Q_ASSERT_SUCCEEDED(hr); + } + d->cameraPressed = false; + d->cameraHalfPressed = false; } - d->cameraPressed = false; - d->cameraHalfPressed = false; -#endif // Q_OS_WINPHONE +#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) + QEventDispatcherWinRT::runOnXamlThread([d]() { d->mainScreen = new QWinRTScreen; @@ -172,14 +196,17 @@ 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); - } - for (QHash<HardwareButtons2CallbackRemover, EventRegistrationToken>::const_iterator i = d->cameraTokens.begin(); i != d->cameraTokens.end(); ++i) { - hr = (d->cameraButtons.Get()->*i.key())(i.value()); - Q_ASSERT_SUCCEEDED(hr); + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) + if (d->hasHardwareButtons) { + 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); + } + for (QHash<HardwareButtons2CallbackRemover, EventRegistrationToken>::const_iterator i = d->cameraTokens.begin(); i != d->cameraTokens.end(); ++i) { + hr = (d->cameraButtons.Get()->*i.key())(i.value()); + Q_ASSERT_SUCCEEDED(hr); + } } #endif // Do not execute this on Windows Phone as the application is already @@ -289,7 +316,7 @@ QPlatformTheme *QWinRTIntegration::createPlatformTheme(const QString &name) cons // System-level integration points -#ifdef Q_OS_WINPHONE +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) HRESULT QWinRTIntegration::onBackButtonPressed(IInspectable *, IBackPressedEventArgs *args) { Q_D(QWinRTIntegration); @@ -339,7 +366,7 @@ HRESULT QWinRTIntegration::onCameraReleased(IInspectable *, ICameraEventArgs *) d->cameraPressed = false; return S_OK; } -#endif // Q_OS_WINPHONE +#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) HRESULT QWinRTIntegration::onSuspended(IInspectable *, ISuspendingEventArgs *) { diff --git a/src/plugins/platforms/winrt/qwinrtintegration.h b/src/plugins/platforms/winrt/qwinrtintegration.h index 31a3ce7c1c..9bf5d27973 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.h +++ b/src/plugins/platforms/winrt/qwinrtintegration.h @@ -47,7 +47,7 @@ namespace ABI { namespace Foundation { struct IAsyncAction; } -#ifdef Q_OS_WINPHONE +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) namespace Phone { namespace UI { namespace Input { @@ -100,7 +100,7 @@ public: QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const Q_DECL_OVERRIDE; private: -#ifdef Q_OS_WINPHONE +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) HRESULT onBackButtonPressed(IInspectable *, ABI::Windows::Phone::UI::Input::IBackPressedEventArgs *args); HRESULT onCameraPressed(IInspectable *, ABI::Windows::Phone::UI::Input::ICameraEventArgs *); HRESULT onCameraHalfPressed(IInspectable *, ABI::Windows::Phone::UI::Input::ICameraEventArgs *); 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 eea7e6a2d4..ff624d9755 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -658,7 +658,13 @@ void QGLXContext::queryDummyContext() oldSurface = oldContext->surface(); QScopedPointer<QSurface> surface; - const char *glxvendor = glXGetClientString(glXGetCurrentDisplay(), GLX_VENDOR); + Display *display = glXGetCurrentDisplay(); + if (!display) { + // FIXME: Since Qt 5.6 we don't need to check whether primary screen is NULL + if (QScreen *screen = QGuiApplication::primaryScreen()) + display = DISPLAY_FROM_XCB(static_cast<QXcbScreen *>(screen->handle())); + } + const char *glxvendor = glXGetClientString(display, GLX_VENDOR); if (glxvendor && !strcmp(glxvendor, "ATI")) { QWindow *window = new QWindow; window->resize(64, 64); diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp index 38e996fdb4..3e963ccaa8 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp @@ -201,7 +201,12 @@ QPlatformOffscreenSurface *QXcbGlxIntegration::createPlatformOffscreenSurface(QO static bool glxPbufferUsable = true; if (!vendorChecked) { vendorChecked = true; - const char *glxvendor = glXGetClientString(glXGetCurrentDisplay(), GLX_VENDOR); + Display *display = glXGetCurrentDisplay(); +#ifdef XCB_USE_XLIB + if (!display) + display = static_cast<Display *>(m_connection->xlib_display()); +#endif + const char *glxvendor = glXGetClientString(display, GLX_VENDOR); if (glxvendor && !strcmp(glxvendor, "ATI")) glxPbufferUsable = false; } diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index 212fc722c0..e3686ec010 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -73,6 +73,8 @@ public: QSize size() const { return m_qimage.size(); } + bool hasAlpha() const { return m_hasAlpha; } + void put(xcb_window_t window, const QPoint &dst, const QRect &source); void preparePaint(const QRegion ®ion); @@ -90,6 +92,8 @@ private: xcb_window_t m_gc_window; QRegion m_dirty; + + bool m_hasAlpha; }; class QXcbShmGraphicsBuffer : public QPlatformGraphicsBuffer @@ -179,7 +183,8 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QI qWarning() << "QXcbBackingStore: Error while marking the shared memory segment to be destroyed"; } - if (QImage::toPixelFormat(format).alphaUsage() == QPixelFormat::IgnoresAlpha) + m_hasAlpha = QImage::toPixelFormat(format).alphaUsage() == QPixelFormat::UsesAlpha; + if (!m_hasAlpha) format = qt_alphaVersionForPainting(format); m_qimage = QImage( (uchar*) m_xcb_image->data, m_xcb_image->width, m_xcb_image->height, m_xcb_image->stride, format); @@ -330,7 +335,7 @@ void QXcbBackingStore::beginPaint(const QRegion ®ion) m_paintRegion = region; m_image->preparePaint(m_paintRegion); - if (m_image->image()->hasAlphaChannel()) { + if (m_image->hasAlpha()) { QPainter p(paintDevice()); p.setCompositionMode(QPainter::CompositionMode_Source); const QVector<QRect> rects = m_paintRegion.rects(); diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 8b6d2fa3d3..e2bf6e8eb4 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -873,6 +873,8 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin // We do not set "pixel" delta if it is only measured in ticks. if (scrollingDevice.verticalIncrement > 1) rawDelta.setY(delta); + else if (scrollingDevice.verticalIncrement < -1) + rawDelta.setY(-delta); } } if (scrollingDevice.orientations & Qt::Horizontal) { @@ -883,6 +885,8 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin // We do not set "pixel" delta if it is only measured in ticks. if (scrollingDevice.horizontalIncrement > 1) rawDelta.setX(delta); + else if (scrollingDevice.horizontalIncrement < -1) + rawDelta.setX(-delta); } } if (!angleDelta.isNull()) { diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 49fc4f1f10..a00c4cb9dc 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -1901,6 +1901,17 @@ private: bool m_pending; }; +bool QXcbWindow::compressExposeEvent(QRegion &exposeRegion) +{ + ExposeCompressor compressor(m_window, &exposeRegion); + xcb_generic_event_t *filter = 0; + do { + filter = connection()->checkEvent(compressor); + free(filter); + } while (filter); + return compressor.pending(); +} + bool QXcbWindow::handleGenericEvent(xcb_generic_event_t *event, long *result) { return QWindowSystemInterface::handleNativeEvent(window(), @@ -1918,15 +1929,10 @@ void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event) else m_exposeRegion |= rect; - ExposeCompressor compressor(m_window, &m_exposeRegion); - xcb_generic_event_t *filter = 0; - do { - filter = connection()->checkEvent(compressor); - free(filter); - } while (filter); + bool pending = compressExposeEvent(m_exposeRegion); // if count is non-zero there are more expose events pending - if (event->count == 0 || !compressor.pending()) { + if (event->count == 0 || !pending) { QWindowSystemInterface::handleExposeEvent(window(), m_exposeRegion); m_exposeRegion = QRegion(); } @@ -2013,10 +2019,6 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * } } - // The original geometry requested by setGeometry() might be different - // from what we end up with after applying window constraints. - QRect requestedGeometry = geometry(); - const QRect actualGeometry = QRect(pos, QSize(event->width, event->height)); QPlatformScreen *newScreen = parent() ? parent()->screen() : screenForGeometry(actualGeometry); if (!newScreen) @@ -2037,15 +2039,6 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t * // will make the comparison later. QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); - // For expose events we have no way of telling QGuiApplication to used the locally - // cached version of the previous state, so we may in some situations end up with - // an additional expose event. - QRect previousGeometry = requestedGeometry != actualGeometry ? - requestedGeometry : qt_window_private(window())->geometry; - - if (m_mapped && actualGeometry.size() != previousGeometry.size()) - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), actualGeometry.size())); - if (m_usingSyncProtocol && m_syncState == SyncReceived) m_syncState = SyncAndConfigureReceived; @@ -2112,7 +2105,9 @@ void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event) if (m_deferredActivation) requestActivateWindow(); - QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); + QRegion exposeRegion = QRect(QPoint(), geometry().size()); + compressExposeEvent(exposeRegion); + QWindowSystemInterface::handleExposeEvent(window(), exposeRegion); } } diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 9d08103347..0efd78452c 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -208,6 +208,8 @@ protected: void doFocusIn(); void doFocusOut(); + bool compressExposeEvent(QRegion &exposeRegion); + void handleButtonPressEvent(int event_x, int event_y, int root_x, int root_y, int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp); |