mirror of
https://github.com/crystalidea/qt-build-tools.git
synced 2024-11-22 19:00:04 +08:00
5.13.2: qnsview_drawing.mm original
This commit is contained in:
parent
bd0feee96a
commit
b08f00b3e3
227
5.13.2/qtbase/src/plugins/platforms/cocoa/qnsview_drawing.mm
Normal file
227
5.13.2/qtbase/src/plugins/platforms/cocoa/qnsview_drawing.mm
Normal file
@ -0,0 +1,227 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2018 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
// This file is included from qnsview.mm, and only used to organize the code
|
||||
|
||||
@implementation QT_MANGLE_NAMESPACE(QNSView) (Drawing)
|
||||
|
||||
- (void)initDrawing
|
||||
{
|
||||
self.wantsLayer = [self layerExplicitlyRequested]
|
||||
|| [self shouldUseMetalLayer]
|
||||
|| [self layerEnabledByMacOS];
|
||||
|
||||
// Enable high-DPI OpenGL for retina displays. Enabling has the side
|
||||
// effect that Cocoa will start calling glViewport(0, 0, width, height),
|
||||
// overriding any glViewport calls in application code. This is usually not a
|
||||
// problem, except if the application wants to have a "custom" viewport.
|
||||
// (like the hellogl example)
|
||||
if (m_platformWindow->window()->supportsOpenGL()) {
|
||||
self.wantsBestResolutionOpenGLSurface = qt_mac_resolveOption(YES, m_platformWindow->window(),
|
||||
"_q_mac_wantsBestResolutionOpenGLSurface", "QT_MAC_WANTS_BEST_RESOLUTION_OPENGL_SURFACE");
|
||||
// See also QCocoaGLContext::makeCurrent for software renderer workarounds.
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isOpaque
|
||||
{
|
||||
if (!m_platformWindow)
|
||||
return true;
|
||||
return m_platformWindow->isOpaque();
|
||||
}
|
||||
|
||||
- (BOOL)isFlipped
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)dirtyRect
|
||||
{
|
||||
Q_UNUSED(dirtyRect);
|
||||
|
||||
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();
|
||||
|
||||
qCDebug(lcQpaDrawing) << "[QNSView drawRect:]" << m_platformWindow->window() << exposedRegion;
|
||||
m_platformWindow->handleExposeEvent(exposedRegion);
|
||||
}
|
||||
|
||||
- (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)
|
||||
QSurface::SurfaceType surfaceType = m_platformWindow->window()->surfaceType();
|
||||
return surfaceType == QWindow::MetalSurface || surfaceType == QWindow::VulkanSurface;
|
||||
}
|
||||
|
||||
- (CALayer *)makeBackingLayer
|
||||
{
|
||||
if ([self shouldUseMetalLayer]) {
|
||||
// Check if Metal is supported. If it isn't then it's most likely
|
||||
// too late at this point and the QWindow will be non-functional,
|
||||
// but we can at least print a warning.
|
||||
if (![MTLCreateSystemDefaultDevice() autorelease]) {
|
||||
qWarning() << "QWindow initialization error: Metal is not supported";
|
||||
return [super makeBackingLayer];
|
||||
}
|
||||
|
||||
CAMetalLayer *layer = [CAMetalLayer layer];
|
||||
|
||||
// Set the contentsScale for the layer. This is normally done in
|
||||
// viewDidChangeBackingProperties, however on startup that function
|
||||
// is called before the layer is created here. The layer's drawableSize
|
||||
// is updated from layoutSublayersOfLayer as usual.
|
||||
layer.contentsScale = self.window.backingScaleFactor;
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
return [super makeBackingLayer];
|
||||
}
|
||||
|
||||
- (void)setLayer:(CALayer *)layer
|
||||
{
|
||||
qCDebug(lcQpaDrawing) << "Making" << self << "layer-backed with" << layer
|
||||
<< "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested"
|
||||
: [self shouldUseMetalLayer] ? "needed by surface type" : "enabled by macOS");
|
||||
[super setLayer:layer];
|
||||
layer.delegate = self;
|
||||
}
|
||||
|
||||
- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy
|
||||
{
|
||||
// We need to set this explicitly since the super implementation
|
||||
// returns LayerContentsRedrawNever for custom layers like CAMetalLayer.
|
||||
return NSViewLayerContentsRedrawDuringViewResize;
|
||||
}
|
||||
|
||||
#if 0 // Disabled until we enable lazy backingstore resizing
|
||||
- (NSViewLayerContentsPlacement)layerContentsPlacement
|
||||
{
|
||||
// Always place the layer at top left without any automatic scaling,
|
||||
// so that we can re-use larger layers when resizing a window down.
|
||||
return NSViewLayerContentsPlacementTopLeft;
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)updateMetalLayerDrawableSize:(CAMetalLayer *)layer
|
||||
{
|
||||
CGSize drawableSize = layer.bounds.size;
|
||||
drawableSize.width *= layer.contentsScale;
|
||||
drawableSize.height *= layer.contentsScale;
|
||||
layer.drawableSize = drawableSize;
|
||||
}
|
||||
|
||||
- (void)layoutSublayersOfLayer:(CALayer *)layer
|
||||
{
|
||||
if ([layer isKindOfClass:CAMetalLayer.class])
|
||||
[self updateMetalLayerDrawableSize:static_cast<CAMetalLayer* >(layer)];
|
||||
}
|
||||
|
||||
- (void)displayLayer:(CALayer *)layer
|
||||
{
|
||||
if (!NSThread.isMainThread) {
|
||||
// Qt is calling AppKit APIs such as -[NSOpenGLContext setView:] on secondary threads,
|
||||
// which we shouldn't do. This may result in AppKit (wrongly) triggering a display on
|
||||
// the thread where we made the call, so block it here and defer to the main thread.
|
||||
qCWarning(lcQpaDrawing) << "Display non non-main thread! Deferring to main thread";
|
||||
dispatch_async(dispatch_get_main_queue(), ^{ self.needsDisplay = YES; });
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT(layer == self.layer);
|
||||
|
||||
if (!m_platformWindow)
|
||||
return;
|
||||
|
||||
qCDebug(lcQpaDrawing) << "[QNSView displayLayer]" << m_platformWindow->window();
|
||||
|
||||
// FIXME: Find out if there's a way to resolve the dirty rect like in drawRect:
|
||||
m_platformWindow->handleExposeEvent(QRectF::fromCGRect(self.bounds).toRect());
|
||||
}
|
||||
|
||||
- (void)viewDidChangeBackingProperties
|
||||
{
|
||||
CALayer *layer = self.layer;
|
||||
if (!layer)
|
||||
return;
|
||||
|
||||
layer.contentsScale = self.window.backingScaleFactor;
|
||||
|
||||
// Metal layers must be manually updated on e.g. screen change
|
||||
if ([layer isKindOfClass:CAMetalLayer.class]) {
|
||||
[self updateMetalLayerDrawableSize:static_cast<CAMetalLayer* >(layer)];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
Loading…
Reference in New Issue
Block a user