summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/cocoa
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/cocoa')
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm49
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.h4
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm71
-rw-r--r--src/plugins/platforms/cocoa/qnsview_drawing.mm11
-rw-r--r--src/plugins/platforms/cocoa/qprintengine_mac.mm2
5 files changed, 70 insertions, 67 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index 33a45985a8..9b0a6b1b86 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -88,10 +88,13 @@
#include <qpa/qwindowsysteminterface.h>
#include <qwindowdefs.h>
+QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaApplication, "qt.qpa.application");
+QT_END_NAMESPACE
+
QT_USE_NAMESPACE
@implementation QCocoaApplicationDelegate {
- bool startedQuit;
NSObject <NSApplicationDelegate> *reflectionDelegate;
bool inLaunch;
}
@@ -140,46 +143,30 @@ QT_USE_NAMESPACE
return [[self.dockMenu retain] autorelease];
}
-- (BOOL)canQuit
-{
- QCloseEvent ev;
- QGuiApplication::sendEvent(qGuiApp, &ev);
- return ev.isAccepted();
-}
-
// This function will only be called when NSApp is actually running.
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
if ([reflectionDelegate respondsToSelector:_cmd])
return [reflectionDelegate applicationShouldTerminate:sender];
- if ([self canQuit]) {
- if (!startedQuit) {
- startedQuit = true;
- // Close open windows. This is done in order to deliver de-expose
- // events while the event loop is still running.
- const QWindowList topLevels = QGuiApplication::topLevelWindows();
- for (int i = 0; i < topLevels.size(); ++i) {
- QWindow *topLevelWindow = topLevels.at(i);
- // Already closed windows will not have a platform window, skip those
- if (topLevelWindow->handle())
- QWindowSystemInterface::handleCloseEvent(topLevelWindow);
- }
- QWindowSystemInterface::flushWindowSystemEvents();
-
- QGuiApplication::exit(0);
- startedQuit = false;
- }
- }
-
if (QGuiApplicationPrivate::instance()->threadData->eventLoops.isEmpty()) {
- // INVARIANT: No event loop is executing. This probably
- // means that Qt is used as a plugin, or as a part of a native
- // Cocoa application. In any case it should be fine to
- // terminate now:
+ // No event loop is executing. This probably means that Qt is used as a plugin,
+ // or as a part of a native Cocoa application. In any case it should be fine to
+ // terminate now.
+ qCDebug(lcQpaApplication) << "No running event loops, terminating now";
return NSTerminateNow;
}
+ if (!QWindowSystemInterface::handleApplicationTermination<QWindowSystemInterface::SynchronousDelivery>()) {
+ qCDebug(lcQpaApplication) << "Application termination canceled";
+ return NSTerminateCancel;
+ }
+
+ // Even if the application termination was accepted by the application we can't
+ // return NSTerminateNow, as that would trigger AppKit to ultimately call exit().
+ // We need to ensure that the runloop continues spinning so that we can return
+ // from our own event loop back to main(), and exit from there.
+ qCDebug(lcQpaApplication) << "Termination accepted, but returning to runloop for exit through main()";
return NSTerminateCancel;
}
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h
index bb309c0713..4210a4ed3f 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.h
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h
@@ -50,6 +50,8 @@
QT_BEGIN_NAMESPACE
+class QCocoaWindow;
+
class QCocoaGLContext : public QPlatformOpenGLContext
{
public:
@@ -76,12 +78,12 @@ private:
static NSOpenGLPixelFormat *pixelFormatForSurfaceFormat(const QSurfaceFormat &format);
bool setDrawable(QPlatformSurface *surface);
+ void prepareDrawable(QCocoaWindow *platformWindow);
void updateSurfaceFormat();
NSOpenGLContext *m_context = nil;
NSOpenGLContext *m_shareContext = nil;
QSurfaceFormat m_format;
- bool m_didCheckForSoftwareContext = false;
QVarLengthArray<QMacNotificationObserver, 3> m_updateObservers;
QAtomicInt m_needsUpdate = false;
};
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index ba7d12ce30..b312e033cd 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -223,12 +223,10 @@ NSOpenGLPixelFormat *QCocoaGLContext::pixelFormatForSurfaceFormat(const QSurface
attrs << NSOpenGLPFAAllowOfflineRenderers;
}
- // FIXME: Pull this information out of the NSView
- QByteArray useLayer = qgetenv("QT_MAC_WANTS_LAYER");
- if (!useLayer.isEmpty() && useLayer.toInt() > 0) {
- // Disable the software rendering fallback. This makes compositing
- // OpenGL and raster NSViews using Core Animation layers possible.
- attrs << NSOpenGLPFANoRecovery;
+ if (qGuiApp->testAttribute(Qt::AA_UseSoftwareOpenGL)) {
+ // kCGLRendererGenericFloatID is the modern software renderer on macOS,
+ // as opposed to kCGLRendererGenericID, which is deprecated.
+ attrs << NSOpenGLPFARendererID << kCGLRendererGenericFloatID;
}
attrs << 0; // 0-terminate array
@@ -368,23 +366,6 @@ bool QCocoaGLContext::makeCurrent(QPlatformSurface *surface)
[m_context makeCurrentContext];
if (surface->surface()->surfaceClass() == QSurface::Window) {
- // Disable high-resolution surfaces when using the software renderer, which has the
- // problem that the system silently falls back to a to using a low-resolution buffer
- // when a high-resolution buffer is requested. This is not detectable using the NSWindow
- // convertSizeToBacking and backingScaleFactor APIs. A typical result of this is that Qt
- // will display a quarter of the window content when running in a virtual machine.
- if (!m_didCheckForSoftwareContext) {
- // FIXME: This ensures we check only once per context,
- // but the context may be used for multiple surfaces.
- m_didCheckForSoftwareContext = true;
-
- const GLubyte* renderer = glGetString(GL_RENDERER);
- if (qstrcmp((const char *)renderer, "Apple Software Renderer") == 0) {
- NSView *view = static_cast<QCocoaWindow *>(surface)->m_view;
- [view setWantsBestResolutionOpenGLSurface:NO];
- }
- }
-
if (m_needsUpdate.fetchAndStoreRelaxed(false))
update();
}
@@ -413,11 +394,14 @@ bool QCocoaGLContext::setDrawable(QPlatformSurface *surface)
}
Q_ASSERT(surface->surface()->surfaceClass() == QSurface::Window);
- QNSView *view = qnsview_cast(static_cast<QCocoaWindow *>(surface)->view());
+ auto *cocoaWindow = static_cast<QCocoaWindow *>(surface);
+ QNSView *view = qnsview_cast(cocoaWindow->view());
if (view == 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
@@ -460,6 +444,30 @@ 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;
+ }
+ }
+
+ 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
@@ -491,6 +499,21 @@ void QCocoaGLContext::swapBuffers(QPlatformSurface *surface)
return;
}
+ if (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<QCocoaWindow *>(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);
[m_context flushBuffer];
}
diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm
index eb9286519d..2fd63fad67 100644
--- a/src/plugins/platforms/cocoa/qnsview_drawing.mm
+++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm
@@ -44,17 +44,6 @@
- (void)initDrawing
{
[self updateLayerBacking];
-
- // 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
diff --git a/src/plugins/platforms/cocoa/qprintengine_mac.mm b/src/plugins/platforms/cocoa/qprintengine_mac.mm
index 58ad53a6e1..dcb9a85a3c 100644
--- a/src/plugins/platforms/cocoa/qprintengine_mac.mm
+++ b/src/plugins/platforms/cocoa/qprintengine_mac.mm
@@ -59,6 +59,8 @@ QMacPrintEngine::QMacPrintEngine(QPrinter::PrinterMode mode, const QString &devi
QString id = deviceId;
if (id.isEmpty())
id = QCocoaPrinterSupport().defaultPrintDeviceId();
+ else
+ setProperty(QPrintEngine::PPK_PrinterName, deviceId);
d->m_printDevice.reset(new QCocoaPrintDevice(id));
d->m_pageLayout.setPageSize(d->m_printDevice->defaultPageSize());
d->initialize();