From 1fc7ca091b3fdda52381a383318a3a752ec21132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Wed, 5 Aug 2020 11:07:45 +0200 Subject: macOS: Remove support for surface-backed views MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Our deployment target is 10.14, which enables layer-backing by default, and our layer-backing support nowadays is stable enough that we don't need to maintain any of the old code paths for compatibility. The wantsBestResolutionOpenGLSurface property on NSView is only relevant for surface-backed views, so we no longer need to deal with it. Change-Id: I8aef4ac99371113d463ac35eee648a8a2fd1ea72 Reviewed-by: Timur Pocheptsov Reviewed-by: Morten Johan Sørvig --- src/plugins/platforms/cocoa/qcocoabackingstore.h | 15 -- src/plugins/platforms/cocoa/qcocoabackingstore.mm | 270 ---------------------- src/plugins/platforms/cocoa/qcocoaglcontext.h | 1 - src/plugins/platforms/cocoa/qcocoaglcontext.mm | 58 ++--- src/plugins/platforms/cocoa/qcocoaintegration.mm | 12 +- src/plugins/platforms/cocoa/qcocoawindow.h | 2 - src/plugins/platforms/cocoa/qcocoawindow.mm | 29 +-- src/plugins/platforms/cocoa/qnsview_drawing.mm | 61 +---- 8 files changed, 32 insertions(+), 416 deletions(-) (limited to 'src/plugins/platforms/cocoa') diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index 4a5b3886f2..b96bb1e3dc 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -58,21 +58,6 @@ protected: QCFType colorSpace() const; }; -class QNSWindowBackingStore : public QCocoaBackingStore -{ -public: - QNSWindowBackingStore(QWindow *window); - ~QNSWindowBackingStore(); - - void resize(const QSize &size, const QRegion &staticContents) override; - void flush(QWindow *, const QRegion &, const QPoint &) override; - -private: - bool windowHasUnifiedToolbar() const; - QImage::Format format() const override; - void redrawRoundedBottomCorners(CGRect) const; -}; - class QCALayerBackingStore : public QObject, public QCocoaBackingStore { Q_OBJECT diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index 9ee6ab5b4f..01787da1af 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -64,276 +64,6 @@ QCFType QCocoaBackingStore::colorSpace() const // ---------------------------------------------------------------------------- -QNSWindowBackingStore::QNSWindowBackingStore(QWindow *window) - : QCocoaBackingStore(window) -{ - // Choose an appropriate window depth based on the requested surface format. - // On deep color displays the default bit depth is 16-bit, so unless we need - // that level of precision we opt out of it (and the expensive RGB32 -> RGB64 - // conversions that come with it if our backingstore depth does not match). - - NSWindow *nsWindow = static_cast(window->handle())->view().window; - auto colorSpaceName = NSColorSpaceFromDepth(nsWindow.depthLimit); - - static const int kDefaultBitDepth = 8; - auto surfaceFormat = window->requestedFormat(); - auto bitsPerSample = qMax(kDefaultBitDepth, qMax(surfaceFormat.redBufferSize(), - qMax(surfaceFormat.greenBufferSize(), surfaceFormat.blueBufferSize()))); - - // NSBestDepth does not seem to guarantee a window depth deep enough for the - // given bits per sample, even if documented as such. For example, requesting - // 10 bits per sample will not give us a 16-bit format, even if that's what's - // available. Work around this by manually bumping the bit depth. - bitsPerSample = !(bitsPerSample & (bitsPerSample - 1)) - ? bitsPerSample : qNextPowerOfTwo(bitsPerSample); - - auto bestDepth = NSBestDepth(colorSpaceName, bitsPerSample, 0, NO, nullptr); - - // Disable dynamic depth limit, otherwise our depth limit will be overwritten - // by AppKit if the window moves to a screen with a different depth. We call - // this before setting the depth limit, as the call will reset the depth to 0. - [nsWindow setDynamicDepthLimit:NO]; - - qCDebug(lcQpaBackingStore) << "Using" << NSBitsPerSampleFromDepth(bestDepth) - << "bit window depth for" << nsWindow; - - nsWindow.depthLimit = bestDepth; -} - -QNSWindowBackingStore::~QNSWindowBackingStore() -{ -} - -bool QNSWindowBackingStore::windowHasUnifiedToolbar() const -{ - Q_ASSERT(window()->handle()); - return static_cast(window()->handle())->m_drawContentBorderGradient; -} - -QImage::Format QNSWindowBackingStore::format() const -{ - if (windowHasUnifiedToolbar()) - return QImage::Format_ARGB32_Premultiplied; - - return QRasterBackingStore::format(); -} - -void QNSWindowBackingStore::resize(const QSize &size, const QRegion &staticContents) -{ - qCDebug(lcQpaBackingStore) << "Resize requested to" << size; - QRasterBackingStore::resize(size, staticContents); - - // The window shadow rendered by AppKit is based on the shape/content of the - // NSWindow surface. Technically any flush of the backingstore can result in - // a potentially new shape of the window, and would need a shadow invalidation, - // but this is likely too expensive to do at every flush for the few cases where - // clients change the shape dynamically. One case where we do know that the shadow - // likely needs invalidation, if the window has partially transparent content, - // is after a resize, where AppKit's default shadow may be based on the previous - // window content. - QCocoaWindow *cocoaWindow = static_cast(window()->handle()); - if (cocoaWindow->isContentView() && !cocoaWindow->isOpaque()) - cocoaWindow->m_needsInvalidateShadow = true; -} - -/*! - Flushes the given \a region from the specified \a window onto the - screen. - - The \a window is the top level window represented by this backingstore, - or a non-transient child of that window. - - If the \a window is a child window, the \a region will be in child window - coordinates, and the \a offset will be the child window's offset in relation - to the backingstore's top level window. -*/ -void QNSWindowBackingStore::flush(QWindow *window, const QRegion ®ion, const QPoint &offset) -{ - 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()); - Q_ASSERT(!topLevelWindow->handle()->isForeignWindow() && !window->handle()->isForeignWindow()); - - QNSView *topLevelView = qnsview_cast(static_cast(topLevelWindow->handle())->view()); - QNSView *view = qnsview_cast(static_cast(window->handle())->view()); - - if (lcQpaBackingStore().isDebugEnabled()) { - QString targetViewDescription; - if (view != topLevelView) { - QDebug targetDebug(&targetViewDescription); - targetDebug << "onto" << topLevelView << "at" << offset; - } - qCDebug(lcQpaBackingStore) << "Flushing" << region << "of" << view << qPrintable(targetViewDescription); - } - - // Normally a NSView is drawn via drawRect, as part of the display cycle in the - // main runloop, via setNeedsDisplay and friends. AppKit will lock focus on each - // individual view, starting with the top level and then traversing any subviews, - // calling drawRect for each of them. This pull model results in expose events - // sent to Qt, which result in drawing to the backingstore and flushing it. - // Qt may also decide to paint and flush the backingstore via e.g. timers, - // or other events such as mouse events, in which case we're in a push model. - // If there is no focused view, it means we're in the latter case, and need - // to manually flush the NSWindow after drawing to its graphic context. - const bool drawingOutsideOfDisplayCycle = ![NSView focusView]; - - // We also need to ensure the flushed view has focus, so that the graphics - // context is set up correctly (coordinate system, clipping, etc). Outside - // of the normal display cycle there is no focused view, as explained above, - // so we have to handle it manually. There's also a corner case inside the - // normal display cycle due to way QWidgetRepaintManager composits native child - // widgets, where we'll get a flush of a native child during the drawRect of - // its parent/ancestor, and the parent/ancestor being the one locked by AppKit. - // In this case we also need to lock and unlock focus manually. - const bool shouldHandleViewLockManually = [NSView focusView] != view; - if (shouldHandleViewLockManually && !QT_IGNORE_DEPRECATIONS([view lockFocusIfCanDraw])) { - qWarning() << "failed to lock focus of" << view; - return; - } - - const qreal devicePixelRatio = m_image.devicePixelRatio(); - - // If the flushed window is a content view, and we're filling the drawn area - // completely, or it doesn't have a window background we need to preserve, - // we can get away with copying instead of blending the backing store. - QCocoaWindow *cocoaWindow = static_cast(window->handle()); - const NSCompositingOperation compositingOperation = cocoaWindow->isContentView() - && (cocoaWindow->isOpaque() || view.window.backgroundColor == NSColor.clearColor) - ? NSCompositingOperationCopy : NSCompositingOperationSourceOver; - -#ifdef QT_DEBUG - static bool debugBackingStoreFlush = [[NSUserDefaults standardUserDefaults] - boolForKey:@"QtCocoaDebugBackingStoreFlush"]; -#endif - - // ------------------------------------------------------------------------- - - // The current contexts is typically a NSWindowGraphicsContext, but can be - // NSBitmapGraphicsContext e.g. when debugging the view hierarchy in Xcode. - // If we need to distinguish things here in the future, we can use e.g. - // [NSGraphicsContext drawingToScreen], or the attributes of the context. - NSGraphicsContext *graphicsContext = [NSGraphicsContext currentContext]; - Q_ASSERT_X(graphicsContext, "QCocoaBackingStore", - "Focusing the view should give us a current graphics context"); - - // Tag backingstore image with color space based on the window. - // Note: This does not copy the underlying image data. - QCFType cgImage = CGImageCreateCopyWithColorSpace( - QCFType(m_image.toCGImage()), colorSpace()); - - // Create temporary image to use for blitting, without copying image data - NSImage *backingStoreImage = [[[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize] autorelease]; - - QRegion clippedRegion = region; - for (QWindow *w = window; w; w = w->parent()) { - if (!w->mask().isEmpty()) { - clippedRegion &= w == window ? w->mask() - : w->mask().translated(window->mapFromGlobal(w->mapToGlobal(QPoint(0, 0)))); - } - } - - for (const QRect &viewLocalRect : clippedRegion) { - QPoint backingStoreOffset = viewLocalRect.topLeft() + offset; - QRect backingStoreRect(backingStoreOffset * devicePixelRatio, viewLocalRect.size() * devicePixelRatio); - if (graphicsContext.flipped) // Flip backingStoreRect to match graphics context - backingStoreRect.moveTop(m_image.height() - (backingStoreRect.y() + backingStoreRect.height())); - - CGRect viewRect = viewLocalRect.toCGRect(); - - [backingStoreImage drawInRect:viewRect fromRect:backingStoreRect.toCGRect() - operation:compositingOperation fraction:1.0 respectFlipped:YES hints:nil]; - -#ifdef QT_DEBUG - if (Q_UNLIKELY(debugBackingStoreFlush)) { - [[NSColor colorWithCalibratedRed:drand48() green:drand48() blue:drand48() alpha:0.3] set]; - [NSBezierPath fillRect:viewRect]; - - if (drawingOutsideOfDisplayCycle) { - [[[NSColor magentaColor] colorWithAlphaComponent:0.5] set]; - [NSBezierPath strokeLineFromPoint:viewLocalRect.topLeft().toCGPoint() - toPoint:viewLocalRect.bottomRight().toCGPoint()]; - } - } -#endif - } - - // ------------------------------------------------------------------------- - - if (shouldHandleViewLockManually) - QT_IGNORE_DEPRECATIONS([view unlockFocus]); - - if (drawingOutsideOfDisplayCycle) { - redrawRoundedBottomCorners([view convertRect:region.boundingRect().toCGRect() toView:nil]); - QT_IGNORE_DEPRECATIONS([view.window flushWindow]); - } - - // Done flushing to NSWindow backingstore - - QCocoaWindow *topLevelCocoaWindow = static_cast(topLevelWindow->handle()); - if (Q_UNLIKELY(topLevelCocoaWindow->m_needsInvalidateShadow)) { - qCDebug(lcQpaBackingStore) << "Invalidating window shadow for" << topLevelCocoaWindow; - [topLevelView.window invalidateShadow]; - topLevelCocoaWindow->m_needsInvalidateShadow = false; - } -} - -/* - When drawing outside of the display cycle, which Qt Widget does a lot, - we end up drawing over the NSThemeFrame, losing the rounded corners of - windows in the process. - - To work around this, until we've enabled updates via setNeedsDisplay and/or - enabled layer-backed views, we ask the NSWindow to redraw the bottom corners - if they intersect with the flushed region. - - This is the same logic used internally by e.g [NSView displayIfNeeded], - [NSRulerView _scrollToMatchContentView], and [NSClipView _immediateScrollToPoint:], - as well as the workaround used by WebKit to fix a similar bug: - - https://trac.webkit.org/changeset/85376/webkit -*/ -void QNSWindowBackingStore::redrawRoundedBottomCorners(CGRect windowRect) const -{ -#if !defined(QT_APPLE_NO_PRIVATE_APIS) - Q_ASSERT(this->window()->handle()); - NSWindow *window = static_cast(this->window()->handle())->nativeWindow(); - - static SEL intersectBottomCornersWithRect = NSSelectorFromString( - [NSString stringWithFormat:@"_%s%s:", "intersectBottomCorners", "WithRect"]); - if (NSMethodSignature *signature = [window methodSignatureForSelector:intersectBottomCornersWithRect]) { - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; - invocation.target = window; - invocation.selector = intersectBottomCornersWithRect; - [invocation setArgument:&windowRect atIndex:2]; - [invocation invoke]; - - NSRect cornerOverlap = NSZeroRect; - [invocation getReturnValue:&cornerOverlap]; - if (!NSIsEmptyRect(cornerOverlap)) { - static SEL maskRoundedBottomCorners = NSSelectorFromString( - [NSString stringWithFormat:@"_%s%s:", "maskRounded", "BottomCorners"]); - if ((signature = [window methodSignatureForSelector:maskRoundedBottomCorners])) { - invocation = [NSInvocation invocationWithMethodSignature:signature]; - invocation.target = window; - invocation.selector = maskRoundedBottomCorners; - [invocation setArgument:&cornerOverlap atIndex:2]; - [invocation invoke]; - } - } - } -#else - Q_UNUSED(windowRect); -#endif -} - -// ---------------------------------------------------------------------------- - QCALayerBackingStore::QCALayerBackingStore(QWindow *window) : QCocoaBackingStore(window) { diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h index 9dbd1a11bf..ab8e9d3012 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.h +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h @@ -81,7 +81,6 @@ private: static NSOpenGLPixelFormat *pixelFormatForSurfaceFormat(const QSurfaceFormat &format); bool setDrawable(QPlatformSurface *surface); - void prepareDrawable(QCocoaWindow *platformWindow); void updateSurfaceFormat(); NSOpenGLContext *m_context = nil; diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index c2fcb6cdbc..7b0cc3fac3 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -393,8 +393,6 @@ bool QCocoaGLContext::setDrawable(QPlatformSurface *surface) if (view == QT_IGNORE_DEPRECATIONS(m_context.view)) return true; - prepareDrawable(cocoaWindow); - // Setting the drawable may happen on a separate thread as a result of // a call to makeCurrent, so we need to set up the observers before we // associate the view with the context. That way we will guarantee that @@ -410,12 +408,8 @@ bool QCocoaGLContext::setDrawable(QPlatformSurface *surface) m_updateObservers.clear(); - if (view.layer) { - m_updateObservers.append(QMacNotificationObserver(view, NSViewFrameDidChangeNotification, updateCallback)); - m_updateObservers.append(QMacNotificationObserver(view.window, NSWindowDidChangeScreenNotification, updateCallback)); - } else { - m_updateObservers.append(QMacNotificationObserver(view, QT_IGNORE_DEPRECATIONS(NSViewGlobalFrameDidChangeNotification), updateCallback)); - } + m_updateObservers.append(QMacNotificationObserver(view, NSViewFrameDidChangeNotification, updateCallback)); + m_updateObservers.append(QMacNotificationObserver(view.window, NSWindowDidChangeScreenNotification, updateCallback)); m_updateObservers.append(QMacNotificationObserver([NSApplication sharedApplication], NSApplicationDidChangeScreenParametersNotification, updateCallback)); @@ -437,30 +431,6 @@ bool QCocoaGLContext::setDrawable(QPlatformSurface *surface) return true; } -void QCocoaGLContext::prepareDrawable(QCocoaWindow *platformWindow) -{ - // We generally want high-DPI GL surfaces, unless the user has explicitly disabled them - bool prefersBestResolutionOpenGLSurface = qt_mac_resolveOption(YES, - platformWindow->window(), "_q_mac_wantsBestResolutionOpenGLSurface", - "QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE"); - - auto *view = platformWindow->view(); - - // The only case we have to opt out ourselves is when using the Apple software renderer - // in combination with surface-backed views, as these together do not support high-DPI. - if (prefersBestResolutionOpenGLSurface) { - int rendererID = 0; - [m_context getValues:&rendererID forParameter:NSOpenGLContextParameterCurrentRendererID]; - bool isSoftwareRenderer = (rendererID & kCGLRendererIDMatchingMask) == kCGLRendererGenericFloatID; - if (isSoftwareRenderer && !view.layer) { - qCInfo(lcQpaOpenGLContext) << "Disabling high resolution GL surface due to software renderer"; - prefersBestResolutionOpenGLSurface = false; - } - } - - QT_IGNORE_DEPRECATIONS(view.wantsBestResolutionOpenGLSurface) = prefersBestResolutionOpenGLSurface; -} - // NSOpenGLContext is not re-entrant. Even when using separate contexts per thread, // view, and window, calls into the API will still deadlock. For more information // see https://openradar.appspot.com/37064579 @@ -494,19 +464,17 @@ void QCocoaGLContext::swapBuffers(QPlatformSurface *surface) return; } - if (QT_IGNORE_DEPRECATIONS(m_context.view).layer) { - // Flushing an NSOpenGLContext will hit the screen immediately, ignoring - // any Core Animation transactions in place. This may result in major - // visual artifacts if the flush happens out of sync with the size - // of the layer, view, and window reflected by other parts of the UI, - // e.g. if the application flushes in the resize event or a timer during - // window resizing, instead of in the expose event. - auto *cocoaWindow = static_cast(surface); - if (cocoaWindow->geometry().size() != cocoaWindow->m_exposedRect.size()) { - qCInfo(lcQpaOpenGLContext) << "Window exposed size does not match geometry (yet)." - << "Skipping flush to avoid visual artifacts."; - return; - } + // Flushing an NSOpenGLContext will hit the screen immediately, ignoring + // any Core Animation transactions in place. This may result in major + // visual artifacts if the flush happens out of sync with the size + // of the layer, view, and window reflected by other parts of the UI, + // e.g. if the application flushes in the resize event or a timer during + // window resizing, instead of in the expose event. + auto *cocoaWindow = static_cast(surface); + if (cocoaWindow->geometry().size() != cocoaWindow->m_exposedRect.size()) { + qCInfo(lcQpaOpenGLContext) << "Window exposed size does not match geometry (yet)." + << "Skipping flush to avoid visual artifacts."; + return; } QMutexLocker locker(&s_reentrancyMutex); diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 4f4373fbac..250d9fc6e5 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -259,8 +259,8 @@ bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) cons // AppKit expects rendering to happen on the main thread, and we can // easily end up in situations where rendering on secondary threads // will result in visual artifacts, bugs, or even deadlocks, when - // building with SDK 10.14 or higher which enbles view layer-backing. - return QMacVersion::buildSDK() < QOperatingSystemVersion(QOperatingSystemVersion::MacOSMojave); + // layer-backed. + return false; case OpenGL: case BufferQueueingOpenGL: #endif @@ -333,13 +333,7 @@ QPlatformBackingStore *QCocoaIntegration::createPlatformBackingStore(QWindow *wi return nullptr; } - QPlatformBackingStore *backingStore = nullptr; - if (platformWindow->view().layer) - backingStore = new QCALayerBackingStore(window); - else - backingStore = new QNSWindowBackingStore(window); - - return backingStore; + return new QCALayerBackingStore(window); } QAbstractEventDispatcher *QCocoaIntegration::createEventDispatcher() const diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 927c3bd751..d7c4a66514 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -261,8 +261,6 @@ public: // for QNSView bool m_inSetStyleMask; QCocoaMenuBar *m_menubar; - bool m_needsInvalidateShadow; - bool m_frameStrutEventsEnabled; QRect m_exposedRect; int m_registerTouchCount; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 9a6555ca8c..b07844819d 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -145,7 +145,6 @@ QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle) , m_inSetGeometry(false) , m_inSetStyleMask(false) , m_menubar(nullptr) - , m_needsInvalidateShadow(false) , m_frameStrutEventsEnabled(false) , m_registerTouchCount(0) , m_resizableTransientParent(false) @@ -1056,27 +1055,15 @@ void QCocoaWindow::setMask(const QRegion ®ion) { qCDebug(lcQpaWindow) << "QCocoaWindow::setMask" << window() << region; - if (m_view.layer) { - if (!region.isEmpty()) { - QCFType maskPath = CGPathCreateMutable(); - for (const QRect &r : region) - CGPathAddRect(maskPath, nullptr, r.toCGRect()); - CAShapeLayer *maskLayer = [CAShapeLayer layer]; - maskLayer.path = maskPath; - m_view.layer.mask = maskLayer; - } else { - m_view.layer.mask = nil; - } + if (!region.isEmpty()) { + QCFType maskPath = CGPathCreateMutable(); + for (const QRect &r : region) + CGPathAddRect(maskPath, nullptr, r.toCGRect()); + CAShapeLayer *maskLayer = [CAShapeLayer layer]; + maskLayer.path = maskPath; + m_view.layer.mask = maskLayer; } else { - if (isContentView()) { - // Setting the mask requires invalidating the NSWindow shadow, but that needs - // to happen after the backingstore has been redrawn, so that AppKit can pick - // up the new window shape based on the backingstore content. Doing a display - // directly here is not an option, as the window might not be exposed at this - // time, and so would not result in an updated backingstore. - m_needsInvalidateShadow = true; - [m_view setNeedsDisplay:YES]; - } + m_view.layer.mask = nil; } } diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm index 2b9cffa714..1b4178d4a3 100644 --- a/src/plugins/platforms/cocoa/qnsview_drawing.mm +++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm @@ -43,7 +43,13 @@ - (void)initDrawing { - [self updateLayerBacking]; + if (qt_mac_resolveOption(-1, m_platformWindow->window(), + "_q_mac_wantsLayer", "QT_MAC_WANTS_LAYER") != -1) { + qCWarning(lcQpaDrawing) << "Layer-backing is always enabled." + << " QT_MAC_WANTS_LAYER/_q_mac_wantsLayer has no effect."; + } + + self.wantsLayer = YES; } - (BOOL)isOpaque @@ -60,40 +66,6 @@ // ----------------------- Layer setup ----------------------- -- (void)updateLayerBacking -{ - self.wantsLayer = [self layerEnabledByMacOS] - || [self layerExplicitlyRequested] - || [self shouldUseMetalLayer]; -} - -- (BOOL)layerEnabledByMacOS -{ - // AppKit has its own logic for this, but if we rely on that, our layers are created - // by AppKit at a point where we've already set up other parts of the platform plugin - // based on the presence of layers or not. Once we've rewritten these parts to support - // dynamically picking up layer enablement we can let AppKit do its thing. - return QMacVersion::buildSDK() >= QOperatingSystemVersion::MacOSMojave - && QMacVersion::currentRuntime() >= QOperatingSystemVersion::MacOSMojave; -} - -- (BOOL)layerExplicitlyRequested -{ - static bool wantsLayer = [&]() { - int wantsLayer = qt_mac_resolveOption(-1, m_platformWindow->window(), - "_q_mac_wantsLayer", "QT_MAC_WANTS_LAYER"); - - if (wantsLayer != -1 && [self layerEnabledByMacOS]) { - qCWarning(lcQpaDrawing) << "Layer-backing cannot be explicitly controlled on 10.14 when built against the 10.14 SDK"; - return true; - } - - return wantsLayer == 1; - }(); - - return wantsLayer; -} - - (BOOL)shouldUseMetalLayer { // MetalSurface needs a layer, and so does VulkanSurface (via MoltenVK) @@ -146,8 +118,7 @@ { qCDebug(lcQpaDrawing) << "Making" << self << (self.wantsLayer ? "layer-backed" : "layer-hosted") - << "with" << layer << "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested" - : [self shouldUseMetalLayer] ? "needed by surface type" : "enabled by macOS"); + << "with" << layer; if (layer.delegate && layer.delegate != self) { qCWarning(lcQpaDrawing) << "Layer already has delegate" << layer.delegate @@ -244,22 +215,6 @@ { Q_ASSERT_X(!self.layer, "QNSView", "The drawRect code path should not be hit when we are layer backed"); - - if (!m_platformWindow) - return; - - QRegion exposedRegion; - const NSRect *dirtyRects; - NSInteger numDirtyRects; - [self getRectsBeingDrawn:&dirtyRects count:&numDirtyRects]; - for (int i = 0; i < numDirtyRects; ++i) - exposedRegion += QRectF::fromCGRect(dirtyRects[i]).toRect(); - - if (exposedRegion.isEmpty()) - exposedRegion = QRectF::fromCGRect(dirtyBoundingRect).toRect(); - - qCDebug(lcQpaDrawing) << "[QNSView drawRect:]" << m_platformWindow->window() << exposedRegion; - m_platformWindow->handleExposeEvent(exposedRegion); } /* -- cgit v1.2.3