1/**************************************************************************** 2** 3** Copyright (C) 2016 The Qt Company Ltd. 4** Contact: https://www.qt.io/licensing/ 5** 6** This file is part of the plugins of the Qt Toolkit. 7** 8** $QT_BEGIN_LICENSE:LGPL$ 9** Commercial License Usage 10** Licensees holding valid commercial Qt licenses may use this file in 11** accordance with the commercial license agreement provided with the 12** Software or, alternatively, in accordance with the terms contained in 13** a written agreement between you and The Qt Company. For licensing terms 14** and conditions see https://www.qt.io/terms-conditions. For further 15** information use the contact form at https://www.qt.io/contact-us. 16** 17** GNU Lesser General Public License Usage 18** Alternatively, this file may be used under the terms of the GNU Lesser 19** General Public License version 3 as published by the Free Software 20** Foundation and appearing in the file LICENSE.LGPL3 included in the 21** packaging of this file. Please review the following information to 22** ensure the GNU Lesser General Public License version 3 requirements 23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 24** 25** GNU General Public License Usage 26** Alternatively, this file may be used under the terms of the GNU 27** General Public License version 2.0 or (at your option) the GNU General 28** Public license version 3 or any later version approved by the KDE Free 29** Qt Foundation. The licenses are as published by the Free Software 30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 31** included in the packaging of this file. Please review the following 32** information to ensure the GNU General Public License requirements will 33** be met: https://www.gnu.org/licenses/gpl-2.0.html and 34** https://www.gnu.org/licenses/gpl-3.0.html. 35** 36** $QT_END_LICENSE$ 37** 38****************************************************************************/ 39 40#include "qcocoanativeinterface.h" 41#include "qcocoawindow.h" 42#include "qcocoamenu.h" 43#include "qcocoamenubar.h" 44#include "qcocoahelpers.h" 45#include "qcocoaapplicationdelegate.h" 46#include "qcocoaintegration.h" 47#include "qcocoaeventdispatcher.h" 48 49#include <qbytearray.h> 50#include <qwindow.h> 51#include <qpixmap.h> 52#include <qpa/qplatformwindow.h> 53#include <QtGui/qsurfaceformat.h> 54#ifndef QT_NO_OPENGL 55#include <qpa/qplatformopenglcontext.h> 56#include <QtGui/qopenglcontext.h> 57#include "qcocoaglcontext.h" 58#endif 59#include <QtGui/qguiapplication.h> 60#include <qdebug.h> 61 62#if !defined(QT_NO_WIDGETS) && defined(QT_PRINTSUPPORT_LIB) 63#include "qcocoaprintersupport.h" 64#include "qprintengine_mac_p.h" 65#include <qpa/qplatformprintersupport.h> 66#endif 67 68#include <QtGui/private/qcoregraphics_p.h> 69 70#include <QtPlatformHeaders/qcocoawindowfunctions.h> 71 72#include <AppKit/AppKit.h> 73 74#if QT_CONFIG(vulkan) 75#include <MoltenVK/mvk_vulkan.h> 76#endif 77 78QT_BEGIN_NAMESPACE 79 80QCocoaNativeInterface::QCocoaNativeInterface() 81{ 82} 83 84#ifndef QT_NO_OPENGL 85void *QCocoaNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context) 86{ 87 if (!context) 88 return nullptr; 89 if (resourceString.toLower() == "nsopenglcontext") 90 return nsOpenGLContextForContext(context); 91 if (resourceString.toLower() == "cglcontextobj") 92 return cglContextForContext(context); 93 94 return nullptr; 95} 96#endif 97 98void *QCocoaNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) 99{ 100 if (!window->handle()) 101 return nullptr; 102 103 if (resourceString == "nsview") { 104 return static_cast<QCocoaWindow *>(window->handle())->m_view; 105 } else if (resourceString == "nswindow") { 106 return static_cast<QCocoaWindow *>(window->handle())->nativeWindow(); 107#if QT_CONFIG(vulkan) 108 } else if (resourceString == "vkSurface") { 109 if (QVulkanInstance *instance = window->vulkanInstance()) 110 return static_cast<QCocoaVulkanInstance *>(instance->handle())->surface(window); 111#endif 112 } 113 return nullptr; 114} 115 116QPlatformNativeInterface::NativeResourceForIntegrationFunction QCocoaNativeInterface::nativeResourceFunctionForIntegration(const QByteArray &resource) 117{ 118 if (resource.toLower() == "addtomimelist") 119 return NativeResourceForIntegrationFunction(QCocoaNativeInterface::addToMimeList); 120 if (resource.toLower() == "removefrommimelist") 121 return NativeResourceForIntegrationFunction(QCocoaNativeInterface::removeFromMimeList); 122 if (resource.toLower() == "registerdraggedtypes") 123 return NativeResourceForIntegrationFunction(QCocoaNativeInterface::registerDraggedTypes); 124 if (resource.toLower() == "setdockmenu") 125 return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setDockMenu); 126 if (resource.toLower() == "qmenutonsmenu") 127 return NativeResourceForIntegrationFunction(QCocoaNativeInterface::qMenuToNSMenu); 128 if (resource.toLower() == "qmenubartonsmenu") 129 return NativeResourceForIntegrationFunction(QCocoaNativeInterface::qMenuBarToNSMenu); 130 if (resource.toLower() == "qimagetocgimage") 131 return NativeResourceForIntegrationFunction(QCocoaNativeInterface::qImageToCGImage); 132 if (resource.toLower() == "cgimagetoqimage") 133 return NativeResourceForIntegrationFunction(QCocoaNativeInterface::cgImageToQImage); 134 if (resource.toLower() == "registertouchwindow") 135 return NativeResourceForIntegrationFunction(QCocoaNativeInterface::registerTouchWindow); 136 if (resource.toLower() == "setembeddedinforeignview") 137 return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setEmbeddedInForeignView); 138 if (resource.toLower() == "setcontentborderthickness") 139 return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setContentBorderThickness); 140 if (resource.toLower() == "registercontentborderarea") 141 return NativeResourceForIntegrationFunction(QCocoaNativeInterface::registerContentBorderArea); 142 if (resource.toLower() == "setcontentborderareaenabled") 143 return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setContentBorderAreaEnabled); 144 if (resource.toLower() == "setcontentborderenabled") 145 return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setContentBorderEnabled); 146 if (resource.toLower() == "setnstoolbar") 147 return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setNSToolbar); 148 if (resource.toLower() == "testcontentborderposition") 149 return NativeResourceForIntegrationFunction(QCocoaNativeInterface::testContentBorderPosition); 150 151 return nullptr; 152} 153 154QPlatformPrinterSupport *QCocoaNativeInterface::createPlatformPrinterSupport() 155{ 156#if !defined(QT_NO_WIDGETS) && !defined(QT_NO_PRINTER) && defined(QT_PRINTSUPPORT_LIB) 157 return new QCocoaPrinterSupport(); 158#else 159 qFatal("Printing is not supported when Qt is configured with -no-widgets or -no-feature-printer"); 160 return nullptr; 161#endif 162} 163 164void *QCocoaNativeInterface::NSPrintInfoForPrintEngine(QPrintEngine *printEngine) 165{ 166#if !defined(QT_NO_WIDGETS) && !defined(QT_NO_PRINTER) && defined(QT_PRINTSUPPORT_LIB) 167 QMacPrintEnginePrivate *macPrintEnginePriv = static_cast<QMacPrintEngine *>(printEngine)->d_func(); 168 if (macPrintEnginePriv->state == QPrinter::Idle && !macPrintEnginePriv->isPrintSessionInitialized()) 169 macPrintEnginePriv->initialize(); 170 return macPrintEnginePriv->printInfo; 171#else 172 Q_UNUSED(printEngine); 173 qFatal("Printing is not supported when Qt is configured with -no-widgets or -no-feature-printer"); 174 return nullptr; 175#endif 176} 177 178QPixmap QCocoaNativeInterface::defaultBackgroundPixmapForQWizard() 179{ 180 // Note: starting with macOS 10.14, the KeyboardSetupAssistant app bundle no 181 // longer contains the "Background.png" image. This function then returns a 182 // null pixmap. 183 const int ExpectedImageWidth = 242; 184 const int ExpectedImageHeight = 414; 185 QCFType<CFArrayRef> urls = LSCopyApplicationURLsForBundleIdentifier( 186 CFSTR("com.apple.KeyboardSetupAssistant"), nullptr); 187 if (urls && CFArrayGetCount(urls) > 0) { 188 CFURLRef url = (CFURLRef)CFArrayGetValueAtIndex(urls, 0); 189 QCFType<CFBundleRef> bundle = CFBundleCreate(kCFAllocatorDefault, url); 190 if (bundle) { 191 url = CFBundleCopyResourceURL(bundle, CFSTR("Background"), CFSTR("png"), nullptr); 192 if (url) { 193 QCFType<CGImageSourceRef> imageSource = CGImageSourceCreateWithURL(url, nullptr); 194 QCFType<CGImageRef> image = CGImageSourceCreateImageAtIndex(imageSource, 0, nullptr); 195 if (image) { 196 int width = CGImageGetWidth(image); 197 int height = CGImageGetHeight(image); 198 if (width == ExpectedImageWidth && height == ExpectedImageHeight) 199 return QPixmap::fromImage(qt_mac_toQImage(image)); 200 } 201 } 202 } 203 } 204 return QPixmap(); 205} 206 207void QCocoaNativeInterface::clearCurrentThreadCocoaEventDispatcherInterruptFlag() 208{ 209 QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag(); 210} 211 212void QCocoaNativeInterface::onAppFocusWindowChanged(QWindow *window) 213{ 214 Q_UNUSED(window); 215 QCocoaMenuBar::updateMenuBarImmediately(); 216} 217 218#ifndef QT_NO_OPENGL 219void *QCocoaNativeInterface::cglContextForContext(QOpenGLContext* context) 220{ 221 NSOpenGLContext *nsOpenGLContext = static_cast<NSOpenGLContext*>(nsOpenGLContextForContext(context)); 222 if (nsOpenGLContext) 223 return [nsOpenGLContext CGLContextObj]; 224 return nullptr; 225} 226 227void *QCocoaNativeInterface::nsOpenGLContextForContext(QOpenGLContext* context) 228{ 229 if (context) { 230 if (QCocoaGLContext *cocoaGLContext = static_cast<QCocoaGLContext *>(context->handle())) 231 return cocoaGLContext->nativeContext(); 232 } 233 return nullptr; 234} 235#endif 236 237QFunctionPointer QCocoaNativeInterface::platformFunction(const QByteArray &function) const 238{ 239 if (function == QCocoaWindowFunctions::bottomLeftClippedByNSWindowOffsetIdentifier()) 240 return QFunctionPointer(QCocoaWindowFunctions::BottomLeftClippedByNSWindowOffset(QCocoaWindow::bottomLeftClippedByNSWindowOffsetStatic)); 241 242 return nullptr; 243} 244 245void QCocoaNativeInterface::addToMimeList(void *macPasteboardMime) 246{ 247 qt_mac_addToGlobalMimeList(reinterpret_cast<QMacInternalPasteboardMime *>(macPasteboardMime)); 248} 249 250void QCocoaNativeInterface::removeFromMimeList(void *macPasteboardMime) 251{ 252 qt_mac_removeFromGlobalMimeList(reinterpret_cast<QMacInternalPasteboardMime *>(macPasteboardMime)); 253} 254 255void QCocoaNativeInterface::registerDraggedTypes(const QStringList &types) 256{ 257 qt_mac_registerDraggedTypes(types); 258} 259 260void QCocoaNativeInterface::setDockMenu(QPlatformMenu *platformMenu) 261{ 262 QMacAutoReleasePool pool; 263 QCocoaMenu *cocoaPlatformMenu = static_cast<QCocoaMenu *>(platformMenu); 264 NSMenu *menu = cocoaPlatformMenu->nsMenu(); 265 [QCocoaApplicationDelegate sharedDelegate].dockMenu = menu; 266} 267 268void *QCocoaNativeInterface::qMenuToNSMenu(QPlatformMenu *platformMenu) 269{ 270 QCocoaMenu *cocoaPlatformMenu = static_cast<QCocoaMenu *>(platformMenu); 271 NSMenu *menu = cocoaPlatformMenu->nsMenu(); 272 return reinterpret_cast<void *>(menu); 273} 274 275void *QCocoaNativeInterface::qMenuBarToNSMenu(QPlatformMenuBar *platformMenuBar) 276{ 277 QCocoaMenuBar *cocoaPlatformMenuBar = static_cast<QCocoaMenuBar *>(platformMenuBar); 278 NSMenu *menu = cocoaPlatformMenuBar->nsMenu(); 279 return reinterpret_cast<void *>(menu); 280} 281 282CGImageRef QCocoaNativeInterface::qImageToCGImage(const QImage &image) 283{ 284 return qt_mac_toCGImage(image); 285} 286 287QImage QCocoaNativeInterface::cgImageToQImage(CGImageRef image) 288{ 289 return qt_mac_toQImage(image); 290} 291 292void QCocoaNativeInterface::setEmbeddedInForeignView(QPlatformWindow *window, bool embedded) 293{ 294 Q_UNUSED(embedded); // "embedded" state is now automatically detected 295 QCocoaWindow *cocoaPlatformWindow = static_cast<QCocoaWindow *>(window); 296 cocoaPlatformWindow->setEmbeddedInForeignView(); 297} 298 299void QCocoaNativeInterface::registerTouchWindow(QWindow *window, bool enable) 300{ 301 if (!window) 302 return; 303 304 QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); 305 if (cocoaWindow) 306 cocoaWindow->registerTouch(enable); 307} 308 309void QCocoaNativeInterface::setContentBorderThickness(QWindow *window, int topThickness, int bottomThickness) 310{ 311 if (!window) 312 return; 313 314 QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); 315 if (cocoaWindow) 316 cocoaWindow->setContentBorderThickness(topThickness, bottomThickness); 317} 318 319void QCocoaNativeInterface::registerContentBorderArea(QWindow *window, quintptr identifier, int upper, int lower) 320{ 321 if (!window) 322 return; 323 324 QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); 325 if (cocoaWindow) 326 cocoaWindow->registerContentBorderArea(identifier, upper, lower); 327} 328 329void QCocoaNativeInterface::setContentBorderAreaEnabled(QWindow *window, quintptr identifier, bool enable) 330{ 331 if (!window) 332 return; 333 334 QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); 335 if (cocoaWindow) 336 cocoaWindow->setContentBorderAreaEnabled(identifier, enable); 337} 338 339void QCocoaNativeInterface::setContentBorderEnabled(QWindow *window, bool enable) 340{ 341 if (!window) 342 return; 343 344 QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); 345 if (cocoaWindow) 346 cocoaWindow->setContentBorderEnabled(enable); 347} 348 349void QCocoaNativeInterface::setNSToolbar(QWindow *window, void *nsToolbar) 350{ 351 QCocoaIntegration::instance()->setToolbar(window, static_cast<NSToolbar *>(nsToolbar)); 352 353 QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); 354 if (cocoaWindow) 355 cocoaWindow->updateNSToolbar(); 356} 357 358bool QCocoaNativeInterface::testContentBorderPosition(QWindow *window, int position) 359{ 360 if (!window) 361 return false; 362 363 QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle()); 364 if (cocoaWindow) 365 return cocoaWindow->testContentBorderAreaPosition(position); 366 return false; 367} 368 369QT_END_NAMESPACE 370