diff options
author | Liang Qi <liang.qi@qt.io> | 2017-10-17 10:19:31 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2017-10-17 10:34:24 +0200 |
commit | d0a0a3c0418a0fdd2ed84b2a5f7e6565537715c6 (patch) | |
tree | d6aeb4d51caf30ccf23eadb806a09295cbf679cd /src/plugins | |
parent | 9f405f98a4247cd263b9c5d35659a4ba89e282de (diff) | |
parent | ac35f9c44c0fb3b2f40ae5585c497200b2ba743d (diff) |
Merge remote-tracking branch 'origin/5.10' into dev
Conflicts:
examples/network/fortuneclient/client.cpp
examples/network/fortuneserver/server.cpp
src/platformsupport/platformcompositor/qopenglcompositorbackingstore_p.h
src/plugins/platforms/cocoa/qcocoabackingstore.h
src/plugins/platforms/cocoa/qcocoaintegration.h
src/plugins/platforms/cocoa/qcocoascreen.h
src/plugins/platforms/ios/qiosbackingstore.h
src/plugins/sqldrivers/oci/qsql_oci.cpp
src/widgets/kernel/qwidgetwindow.cpp
Change-Id: Ia6dd2c52d4a691b671cf9a2ffca70deccece8f10
Diffstat (limited to 'src/plugins')
37 files changed, 806 insertions, 591 deletions
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index 6ac5021ea9..55a9d76b67 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -2,6 +2,7 @@ TARGET = qcocoa OBJECTIVE_SOURCES += main.mm \ qcocoaintegration.mm \ + qcocoascreen.mm \ qcocoatheme.mm \ qcocoabackingstore.mm \ qcocoawindow.mm \ @@ -36,6 +37,7 @@ OBJECTIVE_SOURCES += main.mm \ SOURCES += messages.cpp HEADERS += qcocoaintegration.h \ + qcocoascreen.h \ qcocoatheme.h \ qcocoabackingstore.h \ qcocoawindow.h \ diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index 35ac7182af..5392804d62 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -284,7 +284,7 @@ QT_END_NAMESPACE inLaunch = false; if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) { - if (QSysInfo::macVersion() >= QSysInfo::MV_10_12) { + if (__builtin_available(macOS 10.12, *)) { // Move the application window to front to avoid launching behind the terminal. // Ignoring other apps is necessary (we must ignore the terminal), but makes // Qt apps play slightly less nice with other apps when lanching from Finder diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index 58ba3f2d4d..b4cd506513 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -52,16 +52,12 @@ public: QCocoaBackingStore(QWindow *window); ~QCocoaBackingStore(); - void beginPaint(const QRegion &) override; - void endPaint() override; - void flush(QWindow *, const QRegion &, const QPoint &) override; private: bool windowHasUnifiedToolbar() const; QImage::Format format() const override; void redrawRoundedBottomCorners(CGRect) const; - QCFType<CGImageRef> m_cgImage; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index 1f39d787be..57a03905ab 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -48,7 +48,6 @@ Q_LOGGING_CATEGORY(lcCocoaBackingStore, "qt.qpa.cocoa.backingstore"); QCocoaBackingStore::QCocoaBackingStore(QWindow *window) : QRasterBackingStore(window) - , m_cgImage(nullptr) { } @@ -70,26 +69,6 @@ QImage::Format QCocoaBackingStore::format() const return QRasterBackingStore::format(); } -void QCocoaBackingStore::beginPaint(const QRegion ®ion) -{ - m_cgImage = nullptr; - QRasterBackingStore::beginPaint(region); -} - -void QCocoaBackingStore::endPaint() -{ - QRasterBackingStore::endPaint(); - - // Prevent potentially costly color conversion by assiging the display - // color space to the backingstore image. - NSView *view = static_cast<QCocoaWindow *>(window()->handle())->view(); - CGColorSpaceRef displayColorSpace = view.window.screen.colorSpace.CGColorSpace; - QCFType<CGImageRef> displayColorSpaceImage = - CGImageCreateCopyWithColorSpace(m_image.toCGImage(), displayColorSpace); - - m_cgImage = displayColorSpaceImage; -} - #if !QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_12) static const NSCompositingOperation NSCompositingOperationCopy = NSCompositeCopy; static const NSCompositingOperation NSCompositingOperationSourceOver = NSCompositeSourceOver; @@ -111,6 +90,9 @@ void QCocoaBackingStore::flush(QWindow *window, const QRegion ®ion, const QPo if (m_image.isNull()) return; + // Use local pool so that any stale image references are cleaned up after flushing + QMacAutoReleasePool pool; + const QWindow *topLevelWindow = this->window(); Q_ASSERT(topLevelWindow->handle() && window->handle()); @@ -128,6 +110,12 @@ void QCocoaBackingStore::flush(QWindow *window, const QRegion ®ion, const QPo qCDebug(lcCocoaBackingStore) << "Flushing" << region << "of" << view << qPrintable(targetViewDescription); } + // Prevent potentially costly color conversion by assigning the display color space + // to the backingstore image. This does not copy the underlying image data. + CGColorSpaceRef displayColorSpace = view.window.screen.colorSpace.CGColorSpace; + QCFType<CGImageRef> cgImage = CGImageCreateCopyWithColorSpace( + QCFType<CGImageRef>(m_image.toCGImage()), displayColorSpace); + if (view.layer) { // In layer-backed mode, locking focus on a view does not give the right // view transformation, and doesn't give us a graphics context to render @@ -137,7 +125,7 @@ void QCocoaBackingStore::flush(QWindow *window, const QRegion ®ion, const QPo // we then directly set the layer's backingstore (content) to our backingstore, // masked to the part of the subview that is relevant. // FIXME: Figure out if there's a way to do partial updates - view.layer.contents = (__bridge id)static_cast<CGImageRef>(m_cgImage); + view.layer.contents = (__bridge id)static_cast<CGImageRef>(cgImage); if (view != topLevelView) { view.layer.contentsRect = CGRectApplyAffineTransform( [view convertRect:view.bounds toView:topLevelView], @@ -196,7 +184,7 @@ void QCocoaBackingStore::flush(QWindow *window, const QRegion ®ion, const QPo "Focusing the view should give us a current graphics context"); // Create temporary image to use for blitting, without copying image data - NSImage *backingStoreImage = [[[NSImage alloc] initWithCGImage:m_cgImage size:NSZeroSize] autorelease]; + NSImage *backingStoreImage = [[[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize] autorelease]; QRegion clippedRegion = region; for (QWindow *w = window; w; w = w->parent()) { diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 9a00eb89b7..fa123550ef 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -163,7 +163,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSOpenSavePanelDelegate); [mSavePanel setDelegate:self]; #if QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_11) - if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::OSXElCapitan) + if (__builtin_available(macOS 10.11, *)) mOpenPanel.accessoryViewDisclosed = YES; #endif diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index 75ac348802..5ed81a7f1b 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -218,6 +218,9 @@ void QCocoaGLContext::windowWasHidden() void QCocoaGLContext::swapBuffers(QPlatformSurface *surface) { + if (surface->surface()->surfaceClass() == QSurface::Offscreen) + return; // Nothing to do + QWindow *window = static_cast<QCocoaWindow *>(surface)->window(); setActiveWindow(window); @@ -229,11 +232,13 @@ bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface) Q_ASSERT(surface->surface()->supportsOpenGL()); QMacAutoReleasePool pool; + [m_context makeCurrentContext]; + + if (surface->surface()->surfaceClass() == QSurface::Offscreen) + return true; QWindow *window = static_cast<QCocoaWindow *>(surface)->window(); setActiveWindow(window); - - [m_context makeCurrentContext]; update(); return true; } diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index bf01addb81..9fa7487623 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -58,59 +58,7 @@ QT_BEGIN_NAMESPACE -class QCocoaScreen : public QPlatformScreen -{ -public: - QCocoaScreen(int screenIndex); - ~QCocoaScreen(); - - // ---------------------------------------------------- - // Virtual methods overridden from QPlatformScreen - QPixmap grabWindow(WId window, int x, int y, int width, int height) const override; - QRect geometry() const override { return m_geometry; } - QRect availableGeometry() const override { return m_availableGeometry; } - int depth() const override { return m_depth; } - QImage::Format format() const override { return m_format; } - qreal devicePixelRatio() const override; - QSizeF physicalSize() const override { return m_physicalSize; } - QDpi logicalDpi() const override { return m_logicalDpi; } - qreal refreshRate() const override { return m_refreshRate; } - QString name() const override { return m_name; } - QPlatformCursor *cursor() const override { return m_cursor; } - QWindow *topLevelAt(const QPoint &point) const override; - QList<QPlatformScreen *> virtualSiblings() const override { return m_siblings; } - QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const override; - - // ---------------------------------------------------- - // Additional methods - void setVirtualSiblings(const QList<QPlatformScreen *> &siblings) { m_siblings = siblings; } - NSScreen *nativeScreen() const; - void updateGeometry(); - - QPointF mapToNative(const QPointF &pos) const { return flipCoordinate(pos); } - QRectF mapToNative(const QRectF &rect) const { return flipCoordinate(rect); } - QPointF mapFromNative(const QPointF &pos) const { return flipCoordinate(pos); } - QRectF mapFromNative(const QRectF &rect) const { return flipCoordinate(rect); } - - static QCocoaScreen *primaryScreen(); - -private: - QPointF flipCoordinate(const QPointF &pos) const; - QRectF flipCoordinate(const QRectF &rect) const; - -public: - int m_screenIndex; - QRect m_geometry; - QRect m_availableGeometry; - QDpi m_logicalDpi; - qreal m_refreshRate; - int m_depth; - QString m_name; - QImage::Format m_format; - QSizeF m_physicalSize; - QCocoaCursor *m_cursor; - QList<QPlatformScreen *> m_siblings; -}; +class QCocoaScreen; class QCocoaIntegration : public QPlatformIntegration { @@ -129,6 +77,7 @@ public: bool hasCapability(QPlatformIntegration::Capability cap) const override; QPlatformWindow *createPlatformWindow(QWindow *window) const override; QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const override; + QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override; #ifndef QT_NO_OPENGL QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override; #endif diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 7b1e689388..dd17848109 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -51,10 +51,12 @@ #include "qcocoainputcontext.h" #include "qcocoamimetypes.h" #include "qcocoaaccessibility.h" +#include "qcocoascreen.h" #include <qpa/qplatforminputcontextfactory_p.h> #include <qpa/qplatformaccessibility.h> #include <qpa/qplatforminputcontextfactory_p.h> +#include <qpa/qplatformoffscreensurface.h> #include <QtCore/qcoreapplication.h> #include <QtGui/private/qcoregraphics_p.h> @@ -78,229 +80,6 @@ QT_BEGIN_NAMESPACE class QCoreTextFontEngine; class QFontEngineFT; -QCocoaScreen::QCocoaScreen(int screenIndex) - : QPlatformScreen(), m_screenIndex(screenIndex), m_refreshRate(60.0) -{ - updateGeometry(); - m_cursor = new QCocoaCursor; -} - -QCocoaScreen::~QCocoaScreen() -{ - delete m_cursor; -} - -NSScreen *QCocoaScreen::nativeScreen() const -{ - NSArray *screens = [NSScreen screens]; - - // Stale reference, screen configuration has changed - if (m_screenIndex < 0 || (NSUInteger)m_screenIndex >= [screens count]) - return nil; - - return [screens objectAtIndex:m_screenIndex]; -} - -/*! - Flips the Y coordinate of the point between quadrant I and IV. - - The native coordinate system on macOS uses quadrant I, with origin - in bottom left, and Qt uses quadrant IV, with origin in top left. - - By flippig the Y coordinate, we can map the position between the - two coordinate systems. -*/ -QPointF QCocoaScreen::flipCoordinate(const QPointF &pos) const -{ - return QPointF(pos.x(), m_geometry.height() - pos.y()); -} - -/*! - Flips the Y coordinate of the rectangle between quadrant I and IV. - - The native coordinate system on macOS uses quadrant I, with origin - in bottom left, and Qt uses quadrant IV, with origin in top left. - - By flippig the Y coordinate, we can map the rectangle between the - two coordinate systems. -*/ -QRectF QCocoaScreen::flipCoordinate(const QRectF &rect) const -{ - return QRectF(flipCoordinate(rect.topLeft() + QPoint(0, rect.height())), rect.size()); -} - -void QCocoaScreen::updateGeometry() -{ - NSScreen *nsScreen = nativeScreen(); - if (!nsScreen) - return; - - // At this point the geometry is in native coordinates, but the size - // is correct, which we take advantage of next when we map the native - // coordinates to the Qt coordinate system. - m_geometry = QRectF::fromCGRect(NSRectToCGRect(nsScreen.frame)).toRect(); - m_availableGeometry = QRectF::fromCGRect(NSRectToCGRect(nsScreen.visibleFrame)).toRect(); - - // The reference screen for the geometry is always the primary screen, but since - // we may be in the process of creating and registering the primary screen, we - // must special-case that and assign it direcly. - QCocoaScreen *primaryScreen = (nsScreen == [[NSScreen screens] firstObject]) ? - this : QCocoaScreen::primaryScreen(); - - m_geometry = primaryScreen->mapFromNative(m_geometry).toRect(); - m_availableGeometry = primaryScreen->mapFromNative(m_availableGeometry).toRect(); - - m_format = QImage::Format_RGB32; - m_depth = NSBitsPerPixelFromDepth([nsScreen depth]); - - NSDictionary *devDesc = [nsScreen deviceDescription]; - CGDirectDisplayID dpy = [[devDesc objectForKey:@"NSScreenNumber"] unsignedIntValue]; - CGSize size = CGDisplayScreenSize(dpy); - m_physicalSize = QSizeF(size.width, size.height); - m_logicalDpi.first = 72; - m_logicalDpi.second = 72; - CGDisplayModeRef displayMode = CGDisplayCopyDisplayMode(dpy); - float refresh = CGDisplayModeGetRefreshRate(displayMode); - CGDisplayModeRelease(displayMode); - if (refresh > 0) - m_refreshRate = refresh; - - // Get m_name (brand/model of the monitor) - NSDictionary *deviceInfo = (NSDictionary *)IODisplayCreateInfoDictionary(CGDisplayIOServicePort(dpy), kIODisplayOnlyPreferredName); - NSDictionary *localizedNames = [deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]]; - if ([localizedNames count] > 0) - m_name = QString::fromUtf8([[localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]] UTF8String]); - [deviceInfo release]; - - QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry()); - QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(), m_logicalDpi.first, m_logicalDpi.second); - QWindowSystemInterface::handleScreenRefreshRateChange(screen(), m_refreshRate); -} - -qreal QCocoaScreen::devicePixelRatio() const -{ - QMacAutoReleasePool pool; - NSScreen *nsScreen = nativeScreen(); - return qreal(nsScreen ? [nsScreen backingScaleFactor] : 1.0); -} - -QPlatformScreen::SubpixelAntialiasingType QCocoaScreen::subpixelAntialiasingTypeHint() const -{ - QPlatformScreen::SubpixelAntialiasingType type = QPlatformScreen::subpixelAntialiasingTypeHint(); - if (type == QPlatformScreen::Subpixel_None) { - // Every OSX machine has RGB pixels unless a peculiar or rotated non-Apple screen is attached - type = QPlatformScreen::Subpixel_RGB; - } - return type; -} - -QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const -{ - NSPoint screenPoint = qt_mac_flipPoint(point); - - // Search (hit test) for the top-level window. [NSWidow windowNumberAtPoint: - // belowWindowWithWindowNumber] may return windows that are not interesting - // to Qt. The search iterates until a suitable window or no window is found. - NSInteger topWindowNumber = 0; - QWindow *window = 0; - do { - // Get the top-most window, below any previously rejected window. - topWindowNumber = [NSWindow windowNumberAtPoint:screenPoint - belowWindowWithWindowNumber:topWindowNumber]; - - // Continue the search if the window does not belong to this process. - NSWindow *nsWindow = [NSApp windowWithWindowNumber:topWindowNumber]; - if (nsWindow == 0) - continue; - - // Continue the search if the window does not belong to Qt. - if (![nsWindow conformsToProtocol:@protocol(QNSWindowProtocol)]) - continue; - - id<QNSWindowProtocol> proto = static_cast<id<QNSWindowProtocol> >(nsWindow); - QCocoaWindow *cocoaWindow = proto.platformWindow; - if (!cocoaWindow) - continue; - window = cocoaWindow->window(); - - // Continue the search if the window is not a top-level window. - if (!window->isTopLevel()) - continue; - - // Stop searching. The current window is the correct window. - break; - } while (topWindowNumber > 0); - - return window; -} - -QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height) const -{ - // TODO window should be handled - Q_UNUSED(window) - - const int maxDisplays = 128; // 128 displays should be enough for everyone. - CGDirectDisplayID displays[maxDisplays]; - CGDisplayCount displayCount; - CGRect cgRect; - - if (width < 0 || height < 0) { - // get all displays - cgRect = CGRectInfinite; - } else { - cgRect = CGRectMake(x, y, width, height); - } - const CGDisplayErr err = CGGetDisplaysWithRect(cgRect, maxDisplays, displays, &displayCount); - - if (err && displayCount == 0) - return QPixmap(); - - // calculate pixmap size - QSize windowSize(width, height); - if (width < 0 || height < 0) { - QRect windowRect; - for (uint i = 0; i < displayCount; ++i) { - const CGRect cgRect = CGDisplayBounds(displays[i]); - QRect qRect(cgRect.origin.x, cgRect.origin.y, cgRect.size.width, cgRect.size.height); - windowRect = windowRect.united(qRect); - } - if (width < 0) - windowSize.setWidth(windowRect.width()); - if (height < 0) - windowSize.setHeight(windowRect.height()); - } - - QPixmap windowPixmap(windowSize * devicePixelRatio()); - windowPixmap.fill(Qt::transparent); - - for (uint i = 0; i < displayCount; ++i) { - const CGRect bounds = CGDisplayBounds(displays[i]); - int w = (width < 0 ? bounds.size.width : width) * devicePixelRatio(); - int h = (height < 0 ? bounds.size.height : height) * devicePixelRatio(); - QRect displayRect = QRect(x, y, w, h); - displayRect = displayRect.translated(qRound(-bounds.origin.x), qRound(-bounds.origin.y)); - QCFType<CGImageRef> image = CGDisplayCreateImageForRect(displays[i], - CGRectMake(displayRect.x(), displayRect.y(), displayRect.width(), displayRect.height())); - QPixmap pix(w, h); - pix.fill(Qt::transparent); - CGRect rect = CGRectMake(0, 0, w, h); - QMacCGContext ctx(&pix); - qt_mac_drawCGImage(ctx, &rect, image); - - QPainter painter(&windowPixmap); - painter.drawPixmap(0, 0, pix); - } - return windowPixmap; -} - -/*! - The screen used as a reference for global window geometry -*/ -QCocoaScreen *QCocoaScreen::primaryScreen() -{ - return static_cast<QCocoaScreen *>(QGuiApplication::primaryScreen()->handle()); -} - static QCocoaIntegration::Options parseOptions(const QStringList ¶mList) { QCocoaIntegration::Options options; @@ -363,7 +142,7 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) // Move the application window to front to make it take focus, also when launching // from the terminal. On 10.12+ this call has been moved to applicationDidFinishLauching // to work around issues with loss of focus at startup. - if (QSysInfo::macVersion() < QSysInfo::MV_10_12) { + if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSSierra) { // Ignoring other apps is necessary (we must ignore the terminal), but makes // Qt apps play slightly less nice with other apps when lanching from Finder // (See the activateIgnoringOtherApps docs.) @@ -553,6 +332,24 @@ QPlatformWindow *QCocoaIntegration::createForeignWindow(QWindow *window, WId nat return new QCocoaWindow(window, nativeHandle); } +class QCocoaOffscreenSurface : public QPlatformOffscreenSurface +{ +public: + QCocoaOffscreenSurface(QOffscreenSurface *offscreenSurface) : QPlatformOffscreenSurface(offscreenSurface) {} + + QSurfaceFormat format() const override + { + Q_ASSERT(offscreenSurface()); + return offscreenSurface()->requestedFormat(); + } + bool isValid() const override { return true; } +}; + +QPlatformOffscreenSurface *QCocoaIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const +{ + return new QCocoaOffscreenSurface(surface); +} + #ifndef QT_NO_OPENGL QPlatformOpenGLContext *QCocoaIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { diff --git a/src/plugins/platforms/cocoa/qcocoascreen.h b/src/plugins/platforms/cocoa/qcocoascreen.h new file mode 100644 index 0000000000..b3d958035f --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoascreen.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCOCOASCREEN_H +#define QCOCOASCREEN_H + +#include <AppKit/AppKit.h> + +#include "qcocoacursor.h" + +#include <qpa/qplatformintegration.h> + +QT_BEGIN_NAMESPACE + +class QCocoaScreen : public QPlatformScreen +{ +public: + QCocoaScreen(int screenIndex); + ~QCocoaScreen(); + + // ---------------------------------------------------- + // Virtual methods overridden from QPlatformScreen + QPixmap grabWindow(WId window, int x, int y, int width, int height) const override; + QRect geometry() const override { return m_geometry; } + QRect availableGeometry() const override { return m_availableGeometry; } + int depth() const override { return m_depth; } + QImage::Format format() const override { return m_format; } + qreal devicePixelRatio() const override; + QSizeF physicalSize() const override { return m_physicalSize; } + QDpi logicalDpi() const override { return m_logicalDpi; } + qreal refreshRate() const override { return m_refreshRate; } + QString name() const override { return m_name; } + QPlatformCursor *cursor() const override { return m_cursor; } + QWindow *topLevelAt(const QPoint &point) const override; + QList<QPlatformScreen *> virtualSiblings() const override { return m_siblings; } + QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const override; + + // ---------------------------------------------------- + // Additional methods + void setVirtualSiblings(const QList<QPlatformScreen *> &siblings) { m_siblings = siblings; } + NSScreen *nativeScreen() const; + void updateGeometry(); + + QPointF mapToNative(const QPointF &pos) const { return flipCoordinate(pos); } + QRectF mapToNative(const QRectF &rect) const { return flipCoordinate(rect); } + QPointF mapFromNative(const QPointF &pos) const { return flipCoordinate(pos); } + QRectF mapFromNative(const QRectF &rect) const { return flipCoordinate(rect); } + + static QCocoaScreen *primaryScreen(); + +private: + QPointF flipCoordinate(const QPointF &pos) const; + QRectF flipCoordinate(const QRectF &rect) const; + +public: + int m_screenIndex; + QRect m_geometry; + QRect m_availableGeometry; + QDpi m_logicalDpi; + qreal m_refreshRate; + int m_depth; + QString m_name; + QImage::Format m_format; + QSizeF m_physicalSize; + QCocoaCursor *m_cursor; + QList<QPlatformScreen *> m_siblings; +}; + +QT_END_NAMESPACE + +#endif + diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm new file mode 100644 index 0000000000..13e5220b6a --- /dev/null +++ b/src/plugins/platforms/cocoa/qcocoascreen.mm @@ -0,0 +1,278 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcocoascreen.h" + +#include "qcocoawindow.h" +#include "qcocoahelpers.h" + +#include <QtCore/qcoreapplication.h> +#include <QtGui/private/qcoregraphics_p.h> + +#include <IOKit/graphics/IOGraphicsLib.h> + +QT_BEGIN_NAMESPACE + +class QCoreTextFontEngine; +class QFontEngineFT; + +QCocoaScreen::QCocoaScreen(int screenIndex) + : QPlatformScreen(), m_screenIndex(screenIndex), m_refreshRate(60.0) +{ + updateGeometry(); + m_cursor = new QCocoaCursor; +} + +QCocoaScreen::~QCocoaScreen() +{ + delete m_cursor; +} + +NSScreen *QCocoaScreen::nativeScreen() const +{ + NSArray *screens = [NSScreen screens]; + + // Stale reference, screen configuration has changed + if (m_screenIndex < 0 || (NSUInteger)m_screenIndex >= [screens count]) + return nil; + + return [screens objectAtIndex:m_screenIndex]; +} + +/*! + Flips the Y coordinate of the point between quadrant I and IV. + + The native coordinate system on macOS uses quadrant I, with origin + in bottom left, and Qt uses quadrant IV, with origin in top left. + + By flippig the Y coordinate, we can map the position between the + two coordinate systems. +*/ +QPointF QCocoaScreen::flipCoordinate(const QPointF &pos) const +{ + return QPointF(pos.x(), m_geometry.height() - pos.y()); +} + +/*! + Flips the Y coordinate of the rectangle between quadrant I and IV. + + The native coordinate system on macOS uses quadrant I, with origin + in bottom left, and Qt uses quadrant IV, with origin in top left. + + By flippig the Y coordinate, we can map the rectangle between the + two coordinate systems. +*/ +QRectF QCocoaScreen::flipCoordinate(const QRectF &rect) const +{ + return QRectF(flipCoordinate(rect.topLeft() + QPoint(0, rect.height())), rect.size()); +} + +void QCocoaScreen::updateGeometry() +{ + NSScreen *nsScreen = nativeScreen(); + if (!nsScreen) + return; + + // At this point the geometry is in native coordinates, but the size + // is correct, which we take advantage of next when we map the native + // coordinates to the Qt coordinate system. + m_geometry = QRectF::fromCGRect(NSRectToCGRect(nsScreen.frame)).toRect(); + m_availableGeometry = QRectF::fromCGRect(NSRectToCGRect(nsScreen.visibleFrame)).toRect(); + + // The reference screen for the geometry is always the primary screen, but since + // we may be in the process of creating and registering the primary screen, we + // must special-case that and assign it direcly. + QCocoaScreen *primaryScreen = (nsScreen == [[NSScreen screens] firstObject]) ? + this : QCocoaScreen::primaryScreen(); + + m_geometry = primaryScreen->mapFromNative(m_geometry).toRect(); + m_availableGeometry = primaryScreen->mapFromNative(m_availableGeometry).toRect(); + + m_format = QImage::Format_RGB32; + m_depth = NSBitsPerPixelFromDepth([nsScreen depth]); + + NSDictionary *devDesc = [nsScreen deviceDescription]; + CGDirectDisplayID dpy = [[devDesc objectForKey:@"NSScreenNumber"] unsignedIntValue]; + CGSize size = CGDisplayScreenSize(dpy); + m_physicalSize = QSizeF(size.width, size.height); + m_logicalDpi.first = 72; + m_logicalDpi.second = 72; + CGDisplayModeRef displayMode = CGDisplayCopyDisplayMode(dpy); + float refresh = CGDisplayModeGetRefreshRate(displayMode); + CGDisplayModeRelease(displayMode); + if (refresh > 0) + m_refreshRate = refresh; + + // Get m_name (brand/model of the monitor) + NSDictionary *deviceInfo = (NSDictionary *)IODisplayCreateInfoDictionary(CGDisplayIOServicePort(dpy), kIODisplayOnlyPreferredName); + NSDictionary *localizedNames = [deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]]; + if ([localizedNames count] > 0) + m_name = QString::fromUtf8([[localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]] UTF8String]); + [deviceInfo release]; + + QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry()); + QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(), m_logicalDpi.first, m_logicalDpi.second); + QWindowSystemInterface::handleScreenRefreshRateChange(screen(), m_refreshRate); +} + +qreal QCocoaScreen::devicePixelRatio() const +{ + QMacAutoReleasePool pool; + NSScreen *nsScreen = nativeScreen(); + return qreal(nsScreen ? [nsScreen backingScaleFactor] : 1.0); +} + +QPlatformScreen::SubpixelAntialiasingType QCocoaScreen::subpixelAntialiasingTypeHint() const +{ + QPlatformScreen::SubpixelAntialiasingType type = QPlatformScreen::subpixelAntialiasingTypeHint(); + if (type == QPlatformScreen::Subpixel_None) { + // Every OSX machine has RGB pixels unless a peculiar or rotated non-Apple screen is attached + type = QPlatformScreen::Subpixel_RGB; + } + return type; +} + +QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const +{ + NSPoint screenPoint = qt_mac_flipPoint(point); + + // Search (hit test) for the top-level window. [NSWidow windowNumberAtPoint: + // belowWindowWithWindowNumber] may return windows that are not interesting + // to Qt. The search iterates until a suitable window or no window is found. + NSInteger topWindowNumber = 0; + QWindow *window = 0; + do { + // Get the top-most window, below any previously rejected window. + topWindowNumber = [NSWindow windowNumberAtPoint:screenPoint + belowWindowWithWindowNumber:topWindowNumber]; + + // Continue the search if the window does not belong to this process. + NSWindow *nsWindow = [NSApp windowWithWindowNumber:topWindowNumber]; + if (nsWindow == 0) + continue; + + // Continue the search if the window does not belong to Qt. + if (![nsWindow conformsToProtocol:@protocol(QNSWindowProtocol)]) + continue; + + id<QNSWindowProtocol> proto = static_cast<id<QNSWindowProtocol> >(nsWindow); + QCocoaWindow *cocoaWindow = proto.platformWindow; + if (!cocoaWindow) + continue; + window = cocoaWindow->window(); + + // Continue the search if the window is not a top-level window. + if (!window->isTopLevel()) + continue; + + // Stop searching. The current window is the correct window. + break; + } while (topWindowNumber > 0); + + return window; +} + +QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height) const +{ + // TODO window should be handled + Q_UNUSED(window) + + const int maxDisplays = 128; // 128 displays should be enough for everyone. + CGDirectDisplayID displays[maxDisplays]; + CGDisplayCount displayCount; + CGRect cgRect; + + if (width < 0 || height < 0) { + // get all displays + cgRect = CGRectInfinite; + } else { + cgRect = CGRectMake(x, y, width, height); + } + const CGDisplayErr err = CGGetDisplaysWithRect(cgRect, maxDisplays, displays, &displayCount); + + if (err && displayCount == 0) + return QPixmap(); + + // calculate pixmap size + QSize windowSize(width, height); + if (width < 0 || height < 0) { + QRect windowRect; + for (uint i = 0; i < displayCount; ++i) { + const CGRect cgRect = CGDisplayBounds(displays[i]); + QRect qRect(cgRect.origin.x, cgRect.origin.y, cgRect.size.width, cgRect.size.height); + windowRect = windowRect.united(qRect); + } + if (width < 0) + windowSize.setWidth(windowRect.width()); + if (height < 0) + windowSize.setHeight(windowRect.height()); + } + + QPixmap windowPixmap(windowSize * devicePixelRatio()); + windowPixmap.fill(Qt::transparent); + + for (uint i = 0; i < displayCount; ++i) { + const CGRect bounds = CGDisplayBounds(displays[i]); + int w = (width < 0 ? bounds.size.width : width) * devicePixelRatio(); + int h = (height < 0 ? bounds.size.height : height) * devicePixelRatio(); + QRect displayRect = QRect(x, y, w, h); + displayRect = displayRect.translated(qRound(-bounds.origin.x), qRound(-bounds.origin.y)); + QCFType<CGImageRef> image = CGDisplayCreateImageForRect(displays[i], + CGRectMake(displayRect.x(), displayRect.y(), displayRect.width(), displayRect.height())); + QPixmap pix(w, h); + pix.fill(Qt::transparent); + CGRect rect = CGRectMake(0, 0, w, h); + QMacCGContext ctx(&pix); + qt_mac_drawCGImage(ctx, &rect, image); + + QPainter painter(&windowPixmap); + painter.drawPixmap(0, 0, pix); + } + return windowPixmap; +} + +/*! + The screen used as a reference for global window geometry +*/ +QCocoaScreen *QCocoaScreen::primaryScreen() +{ + return static_cast<QCocoaScreen *>(QGuiApplication::primaryScreen()->handle()); +} + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm index 91fb6e973d..7c6f879b18 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm @@ -144,7 +144,6 @@ QHash<QPlatformTheme::Palette, QPalette*> qt_mac_createRolePalettes() } if (mac_widget_colors[i].paletteRole == QPlatformTheme::MenuPalette || mac_widget_colors[i].paletteRole == QPlatformTheme::MenuBarPalette) { - pal.setBrush(QPalette::Background, qt_mac_toQColor([NSColor windowBackgroundColor])); pal.setBrush(QPalette::Highlight, qt_mac_toQColor([NSColor selectedMenuItemColor])); qc = qt_mac_toQColor([NSColor labelColor]); pal.setBrush(QPalette::ButtonText, qc); diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 1244b46620..4028db2ce9 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -134,11 +134,12 @@ public: void setEmbeddedInForeignView(bool subwindow); + Q_NOTIFICATION_HANDLER(NSViewFrameDidChangeNotification) void viewDidChangeFrame(); + Q_NOTIFICATION_HANDLER(NSViewGlobalFrameDidChangeNotification) void viewDidChangeGlobalFrame(); + Q_NOTIFICATION_HANDLER(NSWindowWillMoveNotification) void windowWillMove(); Q_NOTIFICATION_HANDLER(NSWindowDidMoveNotification) void windowDidMove(); Q_NOTIFICATION_HANDLER(NSWindowDidResizeNotification) void windowDidResize(); - Q_NOTIFICATION_HANDLER(NSViewFrameDidChangeNotification) void viewDidChangeFrame(); - Q_NOTIFICATION_HANDLER(NSViewGlobalFrameDidChangeNotification) void viewDidChangeGlobalFrame(); Q_NOTIFICATION_HANDLER(NSWindowDidEndLiveResizeNotification) void windowDidEndLiveResize(); Q_NOTIFICATION_HANDLER(NSWindowDidBecomeKeyNotification) void windowDidBecomeKey(); Q_NOTIFICATION_HANDLER(NSWindowDidResignKeyNotification) void windowDidResignKey(); @@ -148,8 +149,8 @@ public: Q_NOTIFICATION_HANDLER(NSWindowDidEnterFullScreenNotification) void windowDidEnterFullScreen(); Q_NOTIFICATION_HANDLER(NSWindowWillExitFullScreenNotification) void windowWillExitFullScreen(); Q_NOTIFICATION_HANDLER(NSWindowDidExitFullScreenNotification) void windowDidExitFullScreen(); - Q_NOTIFICATION_HANDLER(NSWindowDidOrderOffScreenNotification) void windowDidOrderOffScreen(); Q_NOTIFICATION_HANDLER(NSWindowDidOrderOnScreenAndFinishAnimatingNotification) void windowDidOrderOnScreen(); + Q_NOTIFICATION_HANDLER(NSWindowDidOrderOffScreenNotification) void windowDidOrderOffScreen(); Q_NOTIFICATION_HANDLER(NSWindowDidChangeOcclusionStateNotification) void windowDidChangeOcclusionState(); Q_NOTIFICATION_HANDLER(NSWindowDidChangeScreenNotification) void windowDidChangeScreen(); Q_NOTIFICATION_HANDLER(NSWindowWillCloseNotification) void windowWillClose(); @@ -284,8 +285,6 @@ public: // for QNSView }; QHash<quintptr, BorderRange> m_contentBorderAreas; // identifer -> uppper/lower QHash<quintptr, bool> m_enabledContentBorderAreas; // identifer -> enabled state (true/false) - - bool m_hasWindowFilePath; }; #ifndef QT_NO_DEBUG_STREAM diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 63ee8c10ac..8e5a9268ec 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qcocoawindow.h" #include "qcocoaintegration.h" +#include "qcocoascreen.h" #include "qnswindowdelegate.h" #include "qcocoaeventdispatcher.h" #ifndef QT_NO_OPENGL @@ -97,34 +98,30 @@ static void qRegisterNotificationCallbacks() [center addObserverForName:notificationName.toNSString() object:nil queue:nil usingBlock:^(NSNotification *notification) { - NSView *view = nullptr; + QVarLengthArray<QCocoaWindow *, 32> cocoaWindows; if ([notification.object isKindOfClass:[NSWindow class]]) { - NSWindow *window = notification.object; - if (!window.contentView) - return; - - view = window.contentView; + NSWindow *nsWindow = notification.object; + for (const QWindow *window : QGuiApplication::allWindows()) { + if (QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle())) + if (cocoaWindow->nativeWindow() == nsWindow) + cocoaWindows += cocoaWindow; + } } else if ([notification.object isKindOfClass:[NSView class]]) { - view = notification.object; + if (QNSView *qnsView = qnsview_cast(notification.object)) + cocoaWindows += qnsView.platformWindow; } else { qCWarning(lcQpaCocoaWindow) << "Unhandled notifcation" << notification.name << "for" << notification.object; return; } - Q_ASSERT(view); - - QCocoaWindow *cocoaWindow = nullptr; - if (QNSView *qnsView = qnsview_cast(view)) - cocoaWindow = qnsView.platformWindow; // FIXME: Could be a foreign window, look up by iterating top level QWindows - if (!cocoaWindow) - return; - - if (!method.invoke(cocoaWindow, Qt::DirectConnection)) { - qCWarning(lcQpaCocoaWindow) << "Failed to invoke NSNotification callback for" - << notification.name << "on" << cocoaWindow; + for (QCocoaWindow *cocoaWindow : cocoaWindows) { + if (!method.invoke(cocoaWindow, Qt::DirectConnection)) { + qCWarning(lcQpaCocoaWindow) << "Failed to invoke NSNotification callback for" + << notification.name << "on" << cocoaWindow; + } } }]; } @@ -161,7 +158,6 @@ QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle) , m_drawContentBorderGradient(false) , m_topContentBorderThickness(0) , m_bottomContentBorderThickness(0) - , m_hasWindowFilePath(false) { qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::QCocoaWindow" << window(); @@ -598,6 +594,11 @@ void QCocoaWindow::setWindowTitle(const QString &title) QMacAutoReleasePool pool; m_view.window.title = title.toNSString(); + + if (title.isEmpty() && !window()->filePath().isEmpty()) { + // Clearing the title should restore the default filename + setWindowFilePath(window()->filePath()); + } } void QCocoaWindow::setWindowFilePath(const QString &filePath) @@ -606,9 +607,14 @@ void QCocoaWindow::setWindowFilePath(const QString &filePath) return; QMacAutoReleasePool pool; - QFileInfo fi(filePath); - [m_view.window setRepresentedFilename:fi.exists() ? filePath.toNSString() : @""]; - m_hasWindowFilePath = fi.exists(); + + if (window()->title().isNull()) + [m_view.window setTitleWithRepresentedFilename:filePath.toNSString()]; + else + m_view.window.representedFilename = filePath.toNSString(); + + // Changing the file path may affect icon visibility + setWindowIcon(window()->icon()); } void QCocoaWindow::setWindowIcon(const QIcon &icon) @@ -616,23 +622,21 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon) if (!isContentView()) return; - QMacAutoReleasePool pool; - NSButton *iconButton = [m_view.window standardWindowButton:NSWindowDocumentIconButton]; - if (iconButton == nil) { - if (icon.isNull()) - return; - NSString *title = window()->title().toNSString(); - [m_view.window setRepresentedURL:[NSURL fileURLWithPath:title]]; - iconButton = [m_view.window standardWindowButton:NSWindowDocumentIconButton]; + if (!iconButton) { + // Window icons are only supported on macOS in combination with a document filePath + return; } + + QMacAutoReleasePool pool; + if (icon.isNull()) { - [iconButton setImage:nil]; + NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; + [iconButton setImage:[workspace iconForFile:m_view.window.representedFilename]]; } else { QPixmap pixmap = icon.pixmap(QSize(22, 22)); NSImage *image = static_cast<NSImage *>(qt_mac_create_nsimage(pixmap)); - [iconButton setImage:image]; - [image release]; + [iconButton setImage:[image autorelease]]; } } @@ -844,8 +848,32 @@ void QCocoaWindow::setEmbeddedInForeignView(bool embedded) m_nsWindow = 0; } +// ----------------------- NSView notifications ----------------------- + +void QCocoaWindow::viewDidChangeFrame() +{ + handleGeometryChange(); +} + +/*! + Callback for NSViewGlobalFrameDidChangeNotification. + + Posted whenever an NSView object that has attached surfaces (that is, + NSOpenGLContext objects) moves to a different screen, or other cases + where the NSOpenGLContext object needs to be updated. +*/ +void QCocoaWindow::viewDidChangeGlobalFrame() +{ + [m_view setNeedsDisplay:YES]; +} + // ----------------------- NSWindow notifications ----------------------- +// Note: The following notifications are delivered to every QCocoaWindow +// that is a child of the NSWindow that triggered the notification. Each +// callback should make sure to filter out notifications if they do not +// apply to that QCocoaWindow, e.g. if the window is not a content view. + void QCocoaWindow::windowWillMove() { // Close any open popups on window move @@ -854,6 +882,9 @@ void QCocoaWindow::windowWillMove() void QCocoaWindow::windowDidMove() { + if (!isContentView()) + return; + handleGeometryChange(); // Moving a window might bring it out of maximized state @@ -871,30 +902,19 @@ void QCocoaWindow::windowDidResize() handleWindowStateChanged(); } -void QCocoaWindow::viewDidChangeFrame() -{ - handleGeometryChange(); -} - -/*! - Callback for NSViewGlobalFrameDidChangeNotification. - - Posted whenever an NSView object that has attached surfaces (that is, - NSOpenGLContext objects) moves to a different screen, or other cases - where the NSOpenGLContext object needs to be updated. -*/ -void QCocoaWindow::viewDidChangeGlobalFrame() -{ - [m_view setNeedsDisplay:YES]; -} - void QCocoaWindow::windowDidEndLiveResize() { + if (!isContentView()) + return; + handleWindowStateChanged(); } void QCocoaWindow::windowDidBecomeKey() { + if (!isContentView()) + return; + if (isForeignWindow()) return; @@ -911,6 +931,9 @@ void QCocoaWindow::windowDidBecomeKey() void QCocoaWindow::windowDidResignKey() { + if (!isContentView()) + return; + if (isForeignWindow()) return; @@ -927,16 +950,25 @@ void QCocoaWindow::windowDidResignKey() void QCocoaWindow::windowDidMiniaturize() { + if (!isContentView()) + return; + handleWindowStateChanged(); } void QCocoaWindow::windowDidDeminiaturize() { + if (!isContentView()) + return; + handleWindowStateChanged(); } void QCocoaWindow::windowWillEnterFullScreen() { + if (!isContentView()) + return; + // The NSWindow needs to be resizable, otherwise we'll end up with // the normal window geometry, centered in the middle of the screen // on a black background. The styleMask will be reset below. @@ -945,6 +977,9 @@ void QCocoaWindow::windowWillEnterFullScreen() void QCocoaWindow::windowDidEnterFullScreen() { + if (!isContentView()) + return; + Q_ASSERT_X(m_view.window.qt_fullScreen, "QCocoaWindow", "FullScreen category processes window notifications first"); @@ -956,6 +991,9 @@ void QCocoaWindow::windowDidEnterFullScreen() void QCocoaWindow::windowWillExitFullScreen() { + if (!isContentView()) + return; + // The NSWindow needs to be resizable, otherwise we'll end up with // a weird zoom animation. The styleMask will be reset below. m_view.window.styleMask |= NSResizableWindowMask; @@ -963,6 +1001,9 @@ void QCocoaWindow::windowWillExitFullScreen() void QCocoaWindow::windowDidExitFullScreen() { + if (!isContentView()) + return; + Q_ASSERT_X(!m_view.window.qt_fullScreen, "QCocoaWindow", "FullScreen category processes window notifications first"); @@ -981,14 +1022,14 @@ void QCocoaWindow::windowDidExitFullScreen() } } -void QCocoaWindow::windowDidOrderOffScreen() +void QCocoaWindow::windowDidOrderOnScreen() { - handleExposeEvent(QRegion()); + [m_view setNeedsDisplay:YES]; } -void QCocoaWindow::windowDidOrderOnScreen() +void QCocoaWindow::windowDidOrderOffScreen() { - [m_view setNeedsDisplay:YES]; + handleExposeEvent(QRegion()); } void QCocoaWindow::windowDidChangeOcclusionState() @@ -1079,6 +1120,8 @@ void QCocoaWindow::handleGeometryChange() void QCocoaWindow::handleExposeEvent(const QRegion ®ion) { + const bool wasExposed = isExposed(); + // Ideally we'd implement isExposed() in terms of these properties, // plus the occlusionState of the NSWindow, and let the expose event // pull the exposed state out when needed. However, when the window @@ -1096,13 +1139,21 @@ void QCocoaWindow::handleExposeEvent(const QRegion ®ion) && !region.isEmpty() && !m_view.hiddenOrHasHiddenAncestor; - QWindowPrivate *windowPrivate = qt_window_private(window()); - if (m_isExposed && windowPrivate->updateRequestPending) { - // FIXME: Should this logic for expose events be in QGuiApplication? - qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::handleExposeEvent" << window() << region << "as update request"; - windowPrivate->deliverUpdateRequest(); - return; + if (windowPrivate->updateRequestPending) { + // We can only deliver update request events when the window is exposed, + // and we also have to make sure we deliver the first expose event after + // becoming exposed as a real expose event, otherwise the exposed state + // of the QWindow is never updated. + // FIXME: Should this logic live in QGuiApplication? + if (wasExposed && m_isExposed) { + qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::handleExposeEvent" << window() << region << "as update request"; + windowPrivate->deliverUpdateRequest(); + return; + } + + // FIXME: Should we re-trigger setNeedsDisplay in case of !wasExposed && m_isExposed? + // Or possibly send the expose event first, and then the update request? } qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::handleExposeEvent" << window() << region << "isExposed" << isExposed(); @@ -1189,7 +1240,7 @@ void QCocoaWindow::recreateWindowIfNeeded() if (m_windowModality != window()->modality()) recreateReason |= WindowModalityChanged; - const bool shouldBeContentView = !parentWindow && !m_viewIsEmbedded; + const bool shouldBeContentView = !parentWindow && !(m_viewIsToBeEmbedded || m_viewIsEmbedded); if (isContentView() != shouldBeContentView) recreateReason |= ContentViewChanged; @@ -1249,6 +1300,7 @@ void QCocoaWindow::recreateWindowIfNeeded() propagateSizeHints(); setWindowFlags(window()->flags()); setWindowTitle(window()->title()); + setWindowFilePath(window()->filePath()); setWindowState(window()->windowState()); } else { // Child windows have no NSWindow, link the NSViews instead. @@ -1412,15 +1464,15 @@ QRect QCocoaWindow::nativeWindowGeometry() const */ void QCocoaWindow::applyWindowState(Qt::WindowStates requestedState) { + if (!isContentView()) + return; + const Qt::WindowState currentState = windowState(); const Qt::WindowState newState = QWindowPrivate::effectiveState(requestedState); if (newState == currentState) return; - if (!isContentView()) - return; - const NSSize contentSize = m_view.frame.size; if (contentSize.width <= 0 || contentSize.height <= 0) { // If content view width or height is 0 then the window animations will crash so diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 643d3b3a30..054dca122f 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -1374,6 +1374,10 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) if (m_composingText.isEmpty()) { m_sendKeyEvent = !QWindowSystemInterface::handleShortcutEvent(window, timestamp, keyCode, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1); + + // Handling a shortcut may result in closing the window + if (!m_platformWindow) + return true; } QObject *fo = m_platformWindow->window()->focusObject(); diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm index 513c7f22b5..799704a407 100644 --- a/src/plugins/platforms/cocoa/qnswindow.mm +++ b/src/plugins/platforms/cocoa/qnswindow.mm @@ -232,7 +232,7 @@ static bool isMouseEvent(NSEvent *ev) NSApplication *application = [NSApplication sharedApplication]; #if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_12) - if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSSierra) { + if (__builtin_available(macOS 10.12, *)) { // Unfortunately there's no NSWindowListOrderedBackToFront, // so we have to manually reverse the order using an array. NSMutableArray *windows = [[[NSMutableArray alloc] init] autorelease]; diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index 1224d138d9..cdecd86dfb 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm @@ -44,6 +44,8 @@ #include <qpa/qplatformscreen.h> #include <qpa/qwindowsysteminterface.h> +static QRegExp whitespaceRegex = QRegExp(QStringLiteral("\\s*")); + @implementation QNSWindowDelegate - (id)initWithQCocoaWindow:(QCocoaWindow *)cocoaWindow @@ -98,7 +100,10 @@ { Q_UNUSED(window); Q_UNUSED(menu); - return m_cocoaWindow && m_cocoaWindow->m_hasWindowFilePath; + + // Only pop up document path if the filename is non-empty. We allow whitespace, to + // allow faking a window icon by setting the file path to a single space character. + return !whitespaceRegex.exactMatch(m_cocoaWindow->window()->filePath()); } - (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard @@ -107,6 +112,9 @@ Q_UNUSED(event); Q_UNUSED(dragImageLocation); Q_UNUSED(pasteboard); - return m_cocoaWindow && m_cocoaWindow->m_hasWindowFilePath; + + // Only allow drag if the filename is non-empty. We allow whitespace, to + // allow faking a window icon by setting the file path to a single space. + return !whitespaceRegex.exactMatch(m_cocoaWindow->window()->filePath()); } @end diff --git a/src/plugins/platforms/ios/qiosbackingstore.h b/src/plugins/platforms/ios/qiosbackingstore.h index a0fcb1a7a7..38006ba90b 100644 --- a/src/plugins/platforms/ios/qiosbackingstore.h +++ b/src/plugins/platforms/ios/qiosbackingstore.h @@ -55,9 +55,6 @@ public: ~QIOSBackingStore(); void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) override; - -private: - QOpenGLContext *m_context; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosbackingstore.mm b/src/plugins/platforms/ios/qiosbackingstore.mm index 74229684e3..db4dd81b2e 100644 --- a/src/plugins/platforms/ios/qiosbackingstore.mm +++ b/src/plugins/platforms/ios/qiosbackingstore.mm @@ -55,7 +55,6 @@ QT_BEGIN_NAMESPACE */ QIOSBackingStore::QIOSBackingStore(QWindow *window) : QRasterBackingStore(window) - , m_context(new QOpenGLContext) { // We use the surface both for raster operations and for GL drawing (when // we blit the raster image), so the type needs to cover both use cases. @@ -64,22 +63,10 @@ QIOSBackingStore::QIOSBackingStore(QWindow *window) Q_ASSERT_X(window->surfaceType() != QSurface::OpenGLSurface, "QIOSBackingStore", "QBackingStore on iOS can only be used with raster-enabled surfaces."); - - m_context->setFormat(window->requestedFormat()); - m_context->setScreen(window->screen()); - Q_ASSERT(QOpenGLContext::globalShareContext()); - m_context->setShareContext(QOpenGLContext::globalShareContext()); - m_context->create(); } QIOSBackingStore::~QIOSBackingStore() { - // We're using composeAndFlush from QPlatformBackingStore, which - // need to clean up any textures in its destructor, so make the - // context current and keep it alive until QPlatformBackingStore - // has cleaned up everything. - m_context->makeCurrent(window()); - m_context->deleteLater(); } void QIOSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) @@ -98,7 +85,7 @@ void QIOSBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin } static QPlatformTextureList emptyTextureList; - composeAndFlush(window, region, offset, &emptyTextureList, m_context, false); + composeAndFlush(window, region, offset, &emptyTextureList, false); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm index c733d99764..0e4bc62227 100644 --- a/src/plugins/platforms/ios/qiosintegration.mm +++ b/src/plugins/platforms/ios/qiosintegration.mm @@ -117,7 +117,7 @@ QIOSIntegration::QIOSIntegration() m_touchDevice = new QTouchDevice; m_touchDevice->setType(QTouchDevice::TouchScreen); QTouchDevice::Capabilities touchCapabilities = QTouchDevice::Position | QTouchDevice::NormalizedPosition; - if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 9)) { + if (__builtin_available(iOS 9, *)) { if (mainScreen.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) touchCapabilities |= QTouchDevice::Pressure; } diff --git a/src/plugins/platforms/ios/qiosservices.mm b/src/plugins/platforms/ios/qiosservices.mm index 0ecc8e123f..3c44e1d7d6 100644 --- a/src/plugins/platforms/ios/qiosservices.mm +++ b/src/plugins/platforms/ios/qiosservices.mm @@ -55,11 +55,13 @@ bool QIOSServices::openUrl(const QUrl &url) return openDocument(url); NSURL *nsUrl = url.toNSURL(); + UIApplication *application = [UIApplication sharedApplication]; - if (![[UIApplication sharedApplication] canOpenURL:nsUrl]) + if (![application canOpenURL:nsUrl]) return false; - return [[UIApplication sharedApplication] openURL:nsUrl]; + [application openURL:nsUrl options:@{} completionHandler:nil]; + return true; } bool QIOSServices::openDocument(const QUrl &url) diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index 84946a5c0f..7d48a012dd 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -238,7 +238,7 @@ self.inputAccessoryView = [[[WrapperView alloc] initWithView:accessoryView] autorelease]; #ifndef Q_OS_TVOS - if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_9_0) { + if (__builtin_available(iOS 9, *)) { if (platformData.value(kImePlatformDataHideShortcutsBar).toBool()) { // According to the docs, leadingBarButtonGroups/trailingBarButtonGroups should be set to nil to hide the shortcuts bar. // However, starting with iOS 10, the API has been surrounded with NS_ASSUME_NONNULL, which contradicts this and causes diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm index b07a24f154..ddfd2c46fd 100644 --- a/src/plugins/platforms/ios/quiview.mm +++ b/src/plugins/platforms/ios/quiview.mm @@ -48,7 +48,6 @@ #include "qiosmenu.h" #endif -#include <QtCore/qoperatingsystemversion.h> #include <QtGui/private/qguiapplication_p.h> #include <QtGui/private/qwindow_p.h> #include <qpa/qwindowsysteminterface_p.h> @@ -296,7 +295,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") QTouchDevice *touchDevice = QIOSIntegration::instance()->touchDevice(); QTouchDevice::Capabilities touchCapabilities = touchDevice->capabilities(); - if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 9)) { + if (__builtin_available(iOS 9, *)) { if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) touchCapabilities |= QTouchDevice::Pressure; else diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index d9c342be27..c8bdc1c93e 100644 --- a/src/plugins/platforms/windows/qtwindowsglobal.h +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -101,6 +101,8 @@ enum WindowsEventType // Simplify event types FocusOutEvent = WindowEventFlag + 18, WhatsThisEvent = WindowEventFlag + 19, DpiChangedEvent = WindowEventFlag + 21, + EnterSizeMoveEvent = WindowEventFlag + 22, + ExitSizeMoveEvent = WindowEventFlag + 23, MouseEvent = MouseEventFlag + 1, MouseWheelEvent = MouseEventFlag + 2, CursorEvent = MouseEventFlag + 3, @@ -282,6 +284,10 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI return HIWORD(wParamIn) ? QtWindows::AcceleratorCommandEvent : QtWindows::MenuCommandEvent; case WM_DPICHANGED: return QtWindows::DpiChangedEvent; + case WM_ENTERSIZEMOVE: + return QtWindows::EnterSizeMoveEvent; + case WM_EXITSIZEMOVE: + return QtWindows::ExitSizeMoveEvent; default: break; } diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index f3e3670e69..869f2b5272 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -1063,6 +1063,13 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, if (platformWindow->frameStrutEventsEnabled()) return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result); break; + case QtWindows::EnterSizeMoveEvent: + platformWindow->setFlag(QWindowsWindow::ResizeMoveActive); + return true; + case QtWindows::ExitSizeMoveEvent: + platformWindow->clearFlag(QWindowsWindow::ResizeMoveActive); + platformWindow->checkForScreenChanged(); + return true; case QtWindows::ScrollEvent: return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateScrollEvent(platformWindow->window(), hwnd, msg, result); case QtWindows::MouseWheelEvent: diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index 75190a19f7..b9c2db1c6a 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -209,6 +209,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, // Check for events synthesized from touch. Lower 7 bits are touch/pen index, bit 8 indicates touch. // However, when tablet support is active, extraInfo is a packet serial number. This is not a problem // since we do not want to ignore mouse events coming from a tablet. + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms703320.aspx const quint64 extraInfo = quint64(GetMessageExtraInfo()); if ((extraInfo & signatureMask) == miWpSignature) { if (extraInfo & 0x80) { // Bit 7 indicates touch event, else tablet pen. diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index 01b5e6510a..c0781df973 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -566,4 +566,19 @@ const QWindowsScreen *QWindowsScreenManager::screenAtDp(const QPoint &p) const return nullptr; } +const QWindowsScreen *QWindowsScreenManager::screenForHwnd(HWND hwnd) const +{ + HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL); + if (hMonitor == NULL) + return nullptr; + const auto it = + std::find_if(m_screens.cbegin(), m_screens.cend(), + [hMonitor](const QWindowsScreen *s) + { + return s->data().hMonitor == hMonitor + && (s->data().flags & QWindowsScreenData::VirtualDesktop) != 0; + }); + return it != m_screens.cend() ? *it : nullptr; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h index 9a8997326b..7cf73f03af 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.h +++ b/src/plugins/platforms/windows/qwindowsscreen.h @@ -134,6 +134,7 @@ public: const WindowsScreenList &screens() const { return m_screens; } const QWindowsScreen *screenAtDp(const QPoint &p) const; + const QWindowsScreen *screenForHwnd(HWND hwnd) const; private: void removeScreen(int index); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index f68327f62d..16df5974ad 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -903,7 +903,9 @@ void QWindowsBaseWindow::hide_sys() // Normal hide, do not activate other window void QWindowsBaseWindow::raise_sys() { qCDebug(lcQpaWindows) << __FUNCTION__ << this << window(); - if (window()->type() == Qt::Popup + const Qt::WindowType type = window()->type(); + if (type == Qt::Popup + || type == Qt::SubWindow // Special case for QTBUG-63121: MDI subwindows with WindowStaysOnTopHint || (window()->flags() & (Qt::WindowStaysOnTopHint | Qt::WindowStaysOnBottomHint)) == 0) { SetWindowPos(handle(), HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); } @@ -1636,6 +1638,26 @@ void QWindowsWindow::handleResized(int wParam) } } +void QWindowsWindow::checkForScreenChanged() +{ + if (parent()) + return; + + QPlatformScreen *currentScreen = screen(); + const auto &screenManager = QWindowsContext::instance()->screenManager(); + // QTBUG-62971: When dragging a window by its border, detect by mouse position + // to prevent it from oscillating between screens when it resizes + const QWindowsScreen *newScreen = testFlag(ResizeMoveActive) + ? screenManager.screenAtDp(QWindowsCursor::mousePosition()) + : screenManager.screenForHwnd(m_data.hwnd); + if (newScreen != nullptr && newScreen != currentScreen) { + qCDebug(lcQpaWindows).noquote().nospace() << __FUNCTION__ + << ' ' << window() << " \"" << currentScreen->name() + << "\"->\"" << newScreen->name() << '"'; + QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); + } +} + void QWindowsWindow::handleGeometryChange() { const QRect previousGeometry = m_data.geometry; @@ -1649,17 +1671,9 @@ void QWindowsWindow::handleGeometryChange() && !(m_data.geometry.width() > previousGeometry.width() || m_data.geometry.height() > previousGeometry.height())) { fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), true); } - if (!parent() && previousGeometry.topLeft() != m_data.geometry.topLeft()) { - HMONITOR hMonitor = MonitorFromWindow(m_data.hwnd, MONITOR_DEFAULTTONULL); - QPlatformScreen *currentScreen = screen(); - const auto screens = QWindowsContext::instance()->screenManager().screens(); - auto newScreenIt = std::find_if(screens.begin(), screens.end(), [&](QWindowsScreen *s) { - return s->data().hMonitor == hMonitor - && s->data().flags & QWindowsScreenData::VirtualDesktop; - }); - if (newScreenIt != screens.end() && *newScreenIt != currentScreen) - QWindowSystemInterface::handleWindowScreenChanged(window(), (*newScreenIt)->screen()); - } + + checkForScreenChanged(); + if (testFlag(SynchronousGeometryChangeEvent)) QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index f0789e5167..414d4a92f8 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -217,7 +217,8 @@ public: Compositing = 0x200000, HasBorderInFullScreen = 0x400000, WithinDpiChanged = 0x800000, - VulkanSurface = 0x1000000 + VulkanSurface = 0x1000000, + ResizeMoveActive = 0x2000000 }; QWindowsWindow(QWindow *window, const QWindowsWindowData &data); @@ -328,6 +329,8 @@ public: void alertWindow(int durationMs = 0); void stopAlertWindow(); + void checkForScreenChanged(); + static void setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes); void registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes = QWindowsWindowFunctions::NormalTouch); static void setHasBorderInFullScreenStatic(QWindow *window, bool border); diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp index 0369ef4d9f..32a381bc4f 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp +++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp @@ -600,10 +600,10 @@ void QXcbBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoin #ifndef QT_NO_OPENGL void QXcbBackingStore::composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset, - QPlatformTextureList *textures, QOpenGLContext *context, + QPlatformTextureList *textures, bool translucentBackground) { - QPlatformBackingStore::composeAndFlush(window, region, offset, textures, context, translucentBackground); + QPlatformBackingStore::composeAndFlush(window, region, offset, textures, translucentBackground); QXcbWindow *platformWindow = static_cast<QXcbWindow *>(window->handle()); if (platformWindow->needsSync()) { diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.h b/src/plugins/platforms/xcb/qxcbbackingstore.h index 94b5994004..2e8fbfb7fa 100644 --- a/src/plugins/platforms/xcb/qxcbbackingstore.h +++ b/src/plugins/platforms/xcb/qxcbbackingstore.h @@ -61,7 +61,7 @@ public: void flush(QWindow *window, const QRegion ®ion, const QPoint &offset) override; #ifndef QT_NO_OPENGL void composeAndFlush(QWindow *window, const QRegion ®ion, const QPoint &offset, - QPlatformTextureList *textures, QOpenGLContext *context, + QPlatformTextureList *textures, bool translucentBackground) override; #endif QImage toImage() const override; diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro index 6956d04083..a98a7892dd 100644 --- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro +++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro @@ -83,7 +83,6 @@ qtConfig(vulkan) { !qtConfig(system-xcb) { QMAKE_USE += xcb-static xcb } else { - LIBS += -lxcb-xinerama ### there is no configure test for this! qtConfig(xkb): QMAKE_USE += xcb_xkb qtConfig(xcb-render): QMAKE_USE += xcb_render QMAKE_USE += xcb_syslibs diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp index 3fa5f65ddc..f84a0081df 100644 --- a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp +++ b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp @@ -1159,16 +1159,22 @@ static void qLibraryInit() } # endif // MYSQL_VERSION_ID #endif // Q_NO_MYSQL_EMBEDDED + +#ifdef MARIADB_BASE_VERSION + qAddPostRoutine(mysql_server_end); +#endif } static void qLibraryEnd() { -#ifndef Q_NO_MYSQL_EMBEDDED -# if MYSQL_VERSION_ID > 40000 -# if (MYSQL_VERSION_ID >= 40110 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50003 - mysql_library_end(); -# else - mysql_server_end(); +#if !defined(MARIADB_BASE_VERSION) +# if !defined(Q_NO_MYSQL_EMBEDDED) +# if MYSQL_VERSION_ID > 40000 +# if (MYSQL_VERSION_ID >= 40110 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50003 + mysql_library_end(); +# else + mysql_server_end(); +# endif # endif # endif #endif diff --git a/src/plugins/sqldrivers/oci/qsql_oci.cpp b/src/plugins/sqldrivers/oci/qsql_oci.cpp index de47df10ce..5800b84fc6 100644 --- a/src/plugins/sqldrivers/oci/qsql_oci.cpp +++ b/src/plugins/sqldrivers/oci/qsql_oci.cpp @@ -258,6 +258,7 @@ protected: QVariant lastInsertId() const override; bool execBatch(bool arrayBind = false) override; void virtual_hook(int id, void *data) override; + bool fetchNext() override; }; class QOCIResultPrivate: public QSqlCachedResultPrivate @@ -2134,6 +2135,14 @@ void QOCIResult::virtual_hook(int id, void *data) QSqlCachedResult::virtual_hook(id, data); } +bool QOCIResult::fetchNext() +{ + Q_D(QOCIResult); + if (isForwardOnly()) + d->cache.clear(); + return QSqlCachedResult::fetchNext(); +} + //////////////////////////////////////////////////////////////////////////// diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 05585ba07c..b24ecee102 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -663,14 +663,6 @@ HIMutableShapeRef qt_mac_toHIMutableShape(const QRegion ®ion) return shape; } -QRegion qt_mac_fromHIShapeRef(HIShapeRef shape) -{ - QRegion returnRegion; - //returnRegion.detach(); - HIShapeEnumerate(shape, kHIShapeParseFromTopLeft, qt_mac_shape2QRegionHelper, &returnRegion); - return returnRegion; -} - bool qt_macWindowIsTextured(const QWidget *window) { if (QWindow *w = window->windowHandle()) @@ -928,24 +920,15 @@ static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg break; } case QStyle::CT_SizeGrip: + // Not HIG kosher: mimic what we were doing earlier until we support 4-edge resizing in MDI subwindows if (sz == QStyleHelper::SizeLarge || sz == QStyleHelper::SizeSmall) { - CGRect r; - CGPoint p = { 0, 0 }; - HIThemeGrowBoxDrawInfo gbi; - gbi.version = 0; - gbi.state = kThemeStateActive; - gbi.kind = kHIThemeGrowBoxKindNormal; - gbi.direction = QApplication::isRightToLeft() ? kThemeGrowLeft | kThemeGrowDown - : kThemeGrowRight | kThemeGrowDown; - gbi.size = sz == QStyleHelper::SizeSmall ? kHIThemeGrowBoxSizeSmall : kHIThemeGrowBoxSizeNormal; - if (HIThemeGetGrowBoxBounds(&p, &gbi, &r) == noErr) { - int width = 0; + int s = sz == QStyleHelper::SizeSmall ? 16 : 22; // large: pixel measured from HITheme, small: from my hat + int width = 0; #if QT_CONFIG(mdiarea) if (widg && qobject_cast<QMdiSubWindow *>(widg->parentWidget())) - width = r.size.width; + width = s; #endif - ret = QSize(width, r.size.height); - } + ret = QSize(width, s); } break; case QStyle::CT_ComboBox: @@ -1922,85 +1905,94 @@ static QCocoaWidget cocoaWidgetFromHIThemeButtonKind(ThemeButtonKind kind) return w; } +static NSButton *makeButton(NSButtonType type, NSBezelStyle style) +{ + NSButton *b = [[NSButton alloc] init]; + b.title = @""; + b.buttonType = type; + b.bezelStyle = style; + return b; +} + NSView *QMacStylePrivate::cocoaControl(QCocoaWidget widget) const { - NSView *bv = cocoaControls[widget]; - if (!bv) { + NSView *bv = cocoaControls.value(widget, nil); - if (widget.first == QCocoaPopupButton - || widget.first == QCocoaPullDownButton) - bv = [[NSPopUpButton alloc] init]; - else if (widget.first == QCocoaComboBox) + if (!bv) { + switch (widget.first) { + case QCocoaBox: { + NSBox *bc = [[NSBox alloc] init]; + bc.title = @""; + bc.titlePosition = NSNoTitle; + bc.boxType = NSBoxPrimary; + bc.borderType = NSBezelBorder; + bv = bc; + break; + } + case QCocoaCheckBox: + bv = makeButton(NSSwitchButton, NSRegularSquareBezelStyle); + break; + case QCocoaDisclosureButton: + bv = makeButton(NSOnOffButton, NSDisclosureBezelStyle); + break; + case QCocoaPopupButton: + case QCocoaPullDownButton: { + NSPopUpButton *bc = [[NSPopUpButton alloc] init]; + bc.title = @""; + if (widget.first == QCocoaPullDownButton) + bc.pullsDown = YES; + bv = bc; + break; + } + case QCocoaPushButton: + bv = makeButton(NSMomentaryLightButton, NSRoundedBezelStyle); + break; + case QCocoaRadioButton: + bv = makeButton(NSRadioButton, NSRegularSquareBezelStyle); + break; + case QCocoaComboBox: bv = [[NSComboBox alloc] init]; - else if (widget.first == QCocoaProgressIndicator) + break; + case QCocoaProgressIndicator: bv = [[NSProgressIndicator alloc] init]; - else if (widget.first == QCocoaIndeterminateProgressIndicator) + break; + case QCocoaIndeterminateProgressIndicator: bv = [[QIndeterminateProgressIndicator alloc] init]; - else if (widget.first == QCocoaHorizontalScroller) + break; + case QCocoaHorizontalScroller: bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)]; - else if (widget.first == QCocoaVerticalScroller) + break; + case QCocoaVerticalScroller: // Cocoa sets the orientation from the view's frame // at construction time, and it cannot be changed later. bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)]; - else if (widget.first == QCocoaHorizontalSlider) + break; + case QCocoaHorizontalSlider: bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)]; - else if (widget.first == QCocoaVerticalSlider) + break; + case QCocoaVerticalSlider: // Cocoa sets the orientation from the view's frame // at construction time, and it cannot be changed later. bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)]; - else - bv = [[NSButton alloc] init]; - - switch (widget.first) { - case QCocoaDisclosureButton: { - NSButton *bc = (NSButton *)bv; - bc.buttonType = NSOnOffButton; - bc.bezelStyle = NSDisclosureBezelStyle; - break; - } - case QCocoaCheckBox: { - NSButton *bc = (NSButton *)bv; - bc.buttonType = NSSwitchButton; - break; - } - case QCocoaRadioButton: { - NSButton *bc = (NSButton *)bv; - bc.buttonType = NSRadioButton; - break; - } - case QCocoaPushButton: { - NSButton *bc = (NSButton *)bv; - bc.buttonType = NSMomentaryLightButton; - bc.bezelStyle = NSRoundedBezelStyle; break; - } - case QCocoaPullDownButton: { - NSPopUpButton *bc = (NSPopUpButton *)bv; - bc.pullsDown = YES; - break; - } default: break; } - if ([bv isKindOfClass:[NSButton class]]) { - NSButton *bc = (NSButton *)bv; - bc.title = @""; - } - if ([bv isKindOfClass:[NSControl class]]) { - NSCell *bcell = [(NSControl *)bv cell]; + auto *ctrl = static_cast<NSControl *>(bv); switch (widget.second) { case QStyleHelper::SizeSmall: - bcell.controlSize = NSSmallControlSize; + ctrl.controlSize = NSSmallControlSize; break; case QStyleHelper::SizeMini: - bcell.controlSize = NSMiniControlSize; + ctrl.controlSize = NSMiniControlSize; break; default: break; } - } else if ([bv isKindOfClass:[NSProgressIndicator class]]) { + } else if (widget.first == QCocoaProgressIndicator || + widget.first == QCocoaIndeterminateProgressIndicator) { auto *pi = static_cast<NSProgressIndicator *>(bv); pi.indeterminate = (widget.first == QCocoaIndeterminateProgressIndicator); switch (widget.second) { @@ -2015,7 +2007,7 @@ NSView *QMacStylePrivate::cocoaControl(QCocoaWidget widget) const } } - const_cast<QMacStylePrivate *>(this)->cocoaControls.insert(widget, bv); + cocoaControls.insert(widget, bv); } return bv; @@ -2051,7 +2043,7 @@ NSCell *QMacStylePrivate::cocoaCell(QCocoaWidget widget) const break; } - const_cast<QMacStylePrivate *>(this)->cocoaCells.insert(widget, cell); + cocoaCells.insert(widget, cell); } return cell; @@ -2089,7 +2081,7 @@ void QMacStylePrivate::drawNSViewInRect(QCocoaWidget widget, NSView *view, const CGContextTranslateCTM(ctx, offset.x(), offset.y()); - const CGRect rect = CGRectMake(qtRect.x() + 1, qtRect.y(), qtRect.width(), qtRect.height()); + const CGRect rect = CGRectMake(qtRect.x(), qtRect.y(), qtRect.width(), qtRect.height()); [backingStoreNSView addSubview:view]; view.frame = rect; @@ -2291,24 +2283,7 @@ void QMacStyle::polish(QWidget* w) || qobject_cast<QComboBoxPrivateContainer *>(w) #endif ) { - w->setWindowOpacity(0.985); - if (!w->testAttribute(Qt::WA_SetPalette)) { - QPixmap px(64, 64); - px.fill(Qt::white); - HIThemeMenuDrawInfo mtinfo; - mtinfo.version = qt_mac_hitheme_version; - mtinfo.menuType = kThemeMenuTypePopUp; - // HIRect rect = CGRectMake(0, 0, px.width(), px.height()); - // ### - //HIThemeDrawMenuBackground(&rect, &mtinfo, QMacCGContext(&px)), - // kHIThemeOrientationNormal); - QPalette pal = w->palette(); - QBrush background(px); - pal.setBrush(QPalette::All, QPalette::Window, background); - pal.setBrush(QPalette::All, QPalette::Button, background); - w->setPalette(pal); - w->setAttribute(Qt::WA_SetPalette, false); - } + w->setAttribute(Qt::WA_TranslucentBackground, true); } #endif @@ -3023,7 +2998,7 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w ret = Qt::AlignRight; break; case SH_ComboBox_PopupFrameStyle: - ret = QFrame::NoFrame | QFrame::Plain; + ret = QFrame::NoFrame; break; case SH_MessageBox_TextInteractionFlags: ret = Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard; @@ -3057,27 +3032,6 @@ int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w case SH_Menu_FadeOutOnHide: ret = true; break; - case SH_Menu_Mask: - if (opt) { - if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) { - ret = true; - CGRect menuRect = CGRectMake(opt->rect.x(), opt->rect.y() + 4, - opt->rect.width(), opt->rect.height() - 8); - HIThemeMenuDrawInfo mdi; - mdi.version = 0; -#if QT_CONFIG(menu) - if (w && qobject_cast<QMenu *>(w->parentWidget())) - mdi.menuType = kThemeMenuTypeHierarchical; - else -#endif - mdi.menuType = kThemeMenuTypePopUp; - QCFType<HIShapeRef> shape; - HIThemeGetMenuBackgroundShape(&menuRect, &mdi, &shape); - - mask->region = qt_mac_fromHIShapeRef(shape); - } - } - break; case SH_ItemView_PaintAlternatingRowColorsForEmptyArea: ret = true; break; @@ -3257,17 +3211,13 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai if (groupBox->features & QStyleOptionFrame::Flat) { QCommonStyle::drawPrimitive(pe, groupBox, p, w); } else { - HIThemeGroupBoxDrawInfo gdi; - gdi.version = qt_mac_hitheme_version; - gdi.state = tds; -#if QT_CONFIG(groupbox) - if (w && qobject_cast<QGroupBox *>(w->parentWidget())) - gdi.kind = kHIThemeGroupBoxKindSecondary; - else -#endif - gdi.kind = kHIThemeGroupBoxKindPrimary; - CGRect cgRect = opt->rect.toCGRect(); - HIThemeDrawGroupBox(&cgRect, &gdi, cg, kHIThemeOrientationNormal); + const auto cw = QCocoaWidget(QCocoaBox, QStyleHelper::SizeDefault); + auto *box = static_cast<NSBox *>(d->cocoaControl(cw)); + d->drawNSViewInRect(cw, box, groupBox->rect, p, w != nullptr, ^(CGContextRef ctx, const CGRect &rect) { + CGContextTranslateCTM(ctx, 0, rect.origin.y + rect.size.height); + CGContextScaleCTM(ctx, 1, -1); + [box drawRect:rect]; + }); } } break; @@ -3591,6 +3541,40 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai break; } + case PE_PanelMenu: { + p->save(); + p->fillRect(opt->rect, Qt::transparent); + p->setPen(Qt::transparent); + p->setBrush(opt->palette.window()); + p->setRenderHint(QPainter::Antialiasing, true); + QPainterPath path; + static const qreal CornerPointOffset = 5.5; + static const qreal CornerControlOffset = 2.1; + QRectF r = opt->rect; + // Top-left corner + path.moveTo(r.left(), r.top() + CornerPointOffset); + path.cubicTo(r.left(), r.top() + CornerControlOffset, + r.left() + CornerControlOffset, r.top(), + r.left() + CornerPointOffset, r.top()); + // Top-right corner + path.lineTo(r.right() - CornerPointOffset, r.top()); + path.cubicTo(r.right() - CornerControlOffset, r.top(), + r.right(), r.top() + CornerControlOffset, + r.right(), r.top() + CornerPointOffset); + // Bottom-right corner + path.lineTo(r.right(), r.bottom() - CornerPointOffset); + path.cubicTo(r.right(), r.bottom() - CornerControlOffset, + r.right() - CornerControlOffset, r.bottom(), + r.right() - CornerPointOffset, r.bottom()); + // Bottom-right corner + path.lineTo(r.left() + CornerPointOffset, r.bottom()); + path.cubicTo(r.left() + CornerControlOffset, r.bottom(), + r.left(), r.bottom() - CornerControlOffset, + r.left(), r.bottom() - CornerPointOffset); + path.lineTo(r.left(), r.top() + CornerPointOffset); + p->drawPath(path); + p->restore(); + } break; default: QCommonStyle::drawPrimitive(pe, opt, p, w); @@ -4273,16 +4257,18 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter const int vMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin, opt, w); d->drawFocusRing(p, opt->rect, hMargin, vMargin); break; } + case CE_MenuEmptyArea: + // Skip: PE_PanelMenu fills in everything + break; case CE_MenuItem: case CE_MenuHMargin: case CE_MenuVMargin: - case CE_MenuEmptyArea: case CE_MenuTearoff: case CE_MenuScroller: if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) { const bool active = mi->state & State_Selected; - const QBrush bg = active ? mi->palette.highlight() : mi->palette.background(); - p->fillRect(mi->rect, bg); + if (active) + p->fillRect(mi->rect, mi->palette.highlight()); const QStyleHelper::WidgetSizePolicy widgetSize = d->aquaSizeConstrain(opt, w); @@ -4505,39 +4491,35 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter } break; case CE_SizeGrip: { - if (w && w->testAttribute(Qt::WA_MacOpaqueSizeGrip)) { - HIThemeGrowBoxDrawInfo gdi; - gdi.version = qt_mac_hitheme_version; - gdi.state = tds; - gdi.kind = kHIThemeGrowBoxKindNormal; - gdi.direction = kThemeGrowRight | kThemeGrowDown; - gdi.size = kHIThemeGrowBoxSizeNormal; - CGPoint pt = CGPointMake(opt->rect.x(), opt->rect.y()); - HIThemeDrawGrowBox(&pt, &gdi, cg, kHIThemeOrientationNormal); - } else { - // It isn't possible to draw a transparent size grip with the - // native API, so we do it ourselves here. - QPen lineColor = QColor(82, 82, 82, 192); - lineColor.setWidth(1); - p->save(); - p->setRenderHint(QPainter::Antialiasing); - p->setPen(lineColor); - const Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : qApp->layoutDirection(); - const int NumLines = 3; - for (int l = 0; l < NumLines; ++l) { - const int offset = (l * 4 + 3); - QPoint start, end; - if (layoutDirection == Qt::LeftToRight) { - start = QPoint(opt->rect.width() - offset, opt->rect.height() - 1); - end = QPoint(opt->rect.width() - 1, opt->rect.height() - offset); - } else { - start = QPoint(offset, opt->rect.height() - 1); - end = QPoint(1, opt->rect.height() - offset); - } - p->drawLine(start, end); + // This is not HIG kosher: Fall back to the old stuff until we decide what to do. +#ifndef QT_NO_MDIAREA + if (!w || !qobject_cast<QMdiSubWindow *>(w->parentWidget())) +#endif + break; + + if (w->testAttribute(Qt::WA_MacOpaqueSizeGrip)) + p->fillRect(opt->rect, opt->palette.window()); + + QPen lineColor = QColor(82, 82, 82, 192); + lineColor.setWidth(1); + p->save(); + p->setRenderHint(QPainter::Antialiasing); + p->setPen(lineColor); + const Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : qApp->layoutDirection(); + const int NumLines = 3; + for (int l = 0; l < NumLines; ++l) { + const int offset = (l * 4 + 3); + QPoint start, end; + if (layoutDirection == Qt::LeftToRight) { + start = QPoint(opt->rect.width() - offset, opt->rect.height() - 1); + end = QPoint(opt->rect.width() - 1, opt->rect.height() - offset); + } else { + start = QPoint(offset, opt->rect.height() - 1); + end = QPoint(1, opt->rect.height() - offset); } - p->restore(); + p->drawLine(start, end); } + p->restore(); break; } case CE_Splitter: diff --git a/src/plugins/styles/mac/qmacstyle_mac_p_p.h b/src/plugins/styles/mac/qmacstyle_mac_p_p.h index 399edd82d4..528edfcda1 100644 --- a/src/plugins/styles/mac/qmacstyle_mac_p_p.h +++ b/src/plugins/styles/mac/qmacstyle_mac_p_p.h @@ -168,6 +168,7 @@ QT_BEGIN_NAMESPACE #define CT2(c1, c2) ((uint(c1) << 16) | uint(c2)) enum QCocoaWidgetKind { + QCocoaBox, // QGroupBox QCocoaCheckBox, QCocoaComboBox, // Editable QComboBox QCocoaDisclosureButton, // Disclosure triangle, like in QTreeView @@ -283,8 +284,8 @@ public: mutable QPointer<QFocusFrame> focusWidget; QT_MANGLE_NAMESPACE(NotificationReceiver) *receiver; NSView *backingStoreNSView; - QHash<QCocoaWidget, NSView *> cocoaControls; - QHash<QCocoaWidget, NSCell *> cocoaCells; + mutable QHash<QCocoaWidget, NSView *> cocoaControls; + mutable QHash<QCocoaWidget, NSCell *> cocoaCells; QFont smallSystemFont; QFont miniSystemFont; diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp index 9e6880098f..078875033f 100644 --- a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp @@ -1430,7 +1430,8 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption verticalTitleBar ? titleRect.height() : titleRect.width()); const int indent = 4; drawItemText(painter, rect.adjusted(indent + 1, 1, -indent - 1, -1), - Qt::AlignLeft | Qt::AlignVCenter, dwOpt->palette, + Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, + dwOpt->palette, dwOpt->state & State_Enabled, titleText, QPalette::WindowText); } |