diff --git a/src/qcocoa-qpa/patches/28-patch-use-fontconfig.diff b/src/qcocoa-qpa/patches/28-patch-use-fontconfig.diff new file mode 100644 index 0000000..72166ef --- /dev/null +++ b/src/qcocoa-qpa/patches/28-patch-use-fontconfig.diff @@ -0,0 +1,263 @@ +diff --git a/src/qcocoa-qpa/qcocoaintegration.h b/src/qcocoa-qpa/qcocoaintegration.h +index 11a1038..87d240c 100644 +--- a/src/qcocoa-qpa/qcocoaintegration.h ++++ b/src/qcocoa-qpa/qcocoaintegration.h +@@ -54,6 +54,10 @@ + + #include + #include ++ ++#if QT_CONFIG(fontconfig) ++#include ++#endif + #include + + QT_BEGIN_NAMESPACE +@@ -114,7 +118,8 @@ class QCocoaIntegration : public QPlatformIntegration + { + public: + enum Option { +- UseFreeTypeFontEngine = 0x1 ++ UseFreeTypeFontEngine = 0x1, ++ UseFontConfigDatabase = 0x2 + }; + Q_DECLARE_FLAGS(Options, Option) + +@@ -134,7 +139,7 @@ public: + + QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE; + +- QCoreTextFontDatabase *fontDatabase() const Q_DECL_OVERRIDE; ++ QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE; + QCocoaNativeInterface *nativeInterface() const Q_DECL_OVERRIDE; + QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE; + #ifndef QT_NO_ACCESSIBILITY +@@ -170,12 +175,15 @@ public: + void beep() const Q_DECL_OVERRIDE; + + bool freeTypeFontEngine(bool enabled); ++ bool fontConfigFontEngine(bool enabled); + bool mCanReplaceFontDatabase; ++ qreal m_fontSmoothingGamma; ++ + private: + static QCocoaIntegration *mInstance; + Options mOptions; + +- QScopedPointer mFontDb; ++ QScopedPointer mFontDb; + + QScopedPointer mInputContext; + #ifndef QT_NO_ACCESSIBILITY +diff --git a/src/qcocoa-qpa/qcocoaintegration.mm b/src/qcocoa-qpa/qcocoaintegration.mm +index ecf54b4..db9d19a 100644 +--- a/src/qcocoa-qpa/qcocoaintegration.mm ++++ b/src/qcocoa-qpa/qcocoaintegration.mm +@@ -300,6 +300,13 @@ static QCocoaIntegration::Options parseOptions(const QStringList ¶mList) + #ifndef QT_NO_FREETYPE + if (param == QLatin1String("fontengine=freetype")) + options |= QCocoaIntegration::UseFreeTypeFontEngine; ++#if QT_CONFIG(fontconfig) ++ // "fontconfig" is actually a font database instead of a font engine, ++ // but let's present it as a fontengine to the user, for the sake of ++ // consistency and simplicity. ++ else if (param == QLatin1String("fontengine=fontconfig")) ++ options |= QCocoaIntegration::UseFontConfigDatabase; ++#endif + else + #endif + qWarning() << "Unknown option" << param; +@@ -332,17 +339,47 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) + if (qt_mac_resolveOption(false, "QT_MAC_USE_FREETYPE")) { + mOptions |= QCocoaIntegration::UseFreeTypeFontEngine; + } ++# if QT_CONFIG(fontconfig) ++ if (qt_mac_resolveOption(false, "QT_MAC_USE_FONTCONFIG")) { ++ mOptions |= QCocoaIntegration::UseFontConfigDatabase; ++ } ++# endif + #endif ++ if (mOptions.testFlag(UseFontConfigDatabase)) { ++ // has to be: ++ mOptions |= QCocoaIntegration::UseFreeTypeFontEngine; ++ } ++ + #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) +-#ifndef QT_NO_FREETYPE +- if (mOptions.testFlag(UseFreeTypeFontEngine)) +- mFontDb.reset(new QCoreTextFontDatabaseEngineFactory); +- else ++ m_fontSmoothingGamma = mOptions.testFlag(UseFontConfigDatabase) ? 0.9 : 1.5; ++#else ++ m_fontSmoothingGamma = 0.975 + #endif +- mFontDb.reset(new QCoreTextFontDatabaseEngineFactory); ++ if (qEnvironmentVariableIsSet("QT_MAC_FREETYPE_FONT_GAMMA")) { ++ bool ok = false; ++ qreal fontgamma = qgetenv("QT_MAC_FREETYPE_FONT_GAMMA").toDouble(&ok); ++ if (ok) { ++ m_fontSmoothingGamma = fontgamma; ++ } ++ } ++ // UseFontConfigDatabase can only be set when !QT_NO_FREETYPE and QT_CONFIG(fontconfig) ++ // IOW, we can test it safely without any compile-time conditionals. ++ if (!mOptions.testFlag(UseFontConfigDatabase)) { ++#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) ++# ifndef QT_NO_FREETYPE ++ if (mOptions.testFlag(UseFreeTypeFontEngine)) ++ mFontDb.reset(new QCoreTextFontDatabaseEngineFactory); ++ else ++# endif ++ mFontDb.reset(new QCoreTextFontDatabaseEngineFactory); + #else +- mFontDb.reset(new QCoreTextFontDatabase(mOptions.testFlag(UseFreeTypeFontEngine))); ++ mFontDb.reset(new QCoreTextFontDatabase(mOptions.testFlag(UseFreeTypeFontEngine))); + #endif ++ } else { ++#if QT_CONFIG(fontconfig) ++ mFontDb.reset(new QFontconfigDatabase); ++#endif ++ } + + QString icStr = QPlatformInputContextFactory::requested(); + icStr.isNull() ? mInputContext.reset(new QCocoaInputContext) +@@ -576,7 +613,7 @@ QAbstractEventDispatcher *QCocoaIntegration::createEventDispatcher() const + return new QCocoaEventDispatcher; + } + +-QCoreTextFontDatabase *QCocoaIntegration::fontDatabase() const ++QPlatformFontDatabase *QCocoaIntegration::fontDatabase() const + { + QCocoaIntegration::instance()->mCanReplaceFontDatabase = false; + return mFontDb.data(); +@@ -636,13 +673,12 @@ QCocoaServices *QCocoaIntegration::services() const + + QVariant QCocoaIntegration::styleHint(StyleHint hint) const + { +-#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) +- #define FREETYPEGAMMA 1.5 ++ if (hint == QPlatformIntegration::FontSmoothingGamma) ++#ifdef QT_MAC_USE_FONTCONFIG ++ return m_fontSmoothingGamma; + #else +- #define FREETYPEGAMMA 0.975 ++ return mOptions.testFlag(UseFreeTypeFontEngine)? m_fontSmoothingGamma : 2.0; + #endif +- if (hint == QPlatformIntegration::FontSmoothingGamma) +- return mOptions.testFlag(UseFreeTypeFontEngine)? FREETYPEGAMMA : 2.0; + + return QPlatformIntegration::styleHint(hint); + } +@@ -724,6 +760,10 @@ void QCocoaIntegration::beep() const + + bool QCocoaIntegration::freeTypeFontEngine(bool enabled) + { ++ if (mOptions.testFlag(UseFontConfigDatabase)) { ++ // can't be any other way ++ return true; ++ } + if (!mCanReplaceFontDatabase) { + return false; + } +@@ -733,6 +773,8 @@ bool QCocoaIntegration::freeTypeFontEngine(bool enabled) + options |= QCocoaIntegration::UseFreeTypeFontEngine; + } else { + options &= ~QCocoaIntegration::UseFreeTypeFontEngine; ++ // FontConfig can no longer be used either. ++ options &= ~QCocoaIntegration::UseFontConfigDatabase; + } + if (options != mOptions) { + mOptions = options; +@@ -746,8 +788,38 @@ bool QCocoaIntegration::freeTypeFontEngine(bool enabled) + #endif + return true; + } ++ return false; + #endif ++} ++ ++bool QCocoaIntegration::fontConfigFontEngine(bool enabled) ++{ ++#if QT_CONFIG(fontconfig) ++ if (!mCanReplaceFontDatabase) { ++ return false; ++ } ++ auto options = mOptions; ++ bool ret = false; ++ if (enabled) { ++ options |= QCocoaIntegration::UseFreeTypeFontEngine | QCocoaIntegration::UseFontConfigDatabase; ++ if (options != mOptions) { ++ mOptions = options; ++ mFontDb.reset(new QFontconfigDatabase); ++ ret = true; ++ } ++ } else { ++ options &= ~QCocoaIntegration::UseFontConfigDatabase; ++ if (options != mOptions) { ++ mOptions = options; ++ // UseFreeTypeFontEngine is still set: ++ ret = freeTypeFontEngine(false); ++ } ++ } ++ return ret; ++#else ++ // can't be any other way + return false; ++#endif + } + + QT_END_NAMESPACE +diff --git a/src/qcocoa-qpa/qcocoanativeinterface.mm b/src/qcocoa-qpa/qcocoanativeinterface.mm +index 612b9e4..3191b38 100644 +--- a/src/qcocoa-qpa/qcocoanativeinterface.mm ++++ b/src/qcocoa-qpa/qcocoanativeinterface.mm +@@ -78,6 +78,11 @@ static bool qt_mac_use_freetype(bool enabled) + return QCocoaIntegration::instance()->freeTypeFontEngine(enabled); + } + ++static bool qt_mac_use_fontconfig(bool enabled) ++{ ++ return QCocoaIntegration::instance()->fontConfigFontEngine(enabled); ++} ++ + + QCocoaNativeInterface::QCocoaNativeInterface() + { +@@ -152,6 +157,9 @@ QPlatformNativeInterface::NativeResourceForIntegrationFunction QCocoaNativeInter + if (resource.toLower() == "qt_mac_use_freetype") { + return NativeResourceForIntegrationFunction(qt_mac_use_freetype); + } ++ if (resource.toLower() == "qt_mac_use_fontconfig") { ++ return NativeResourceForIntegrationFunction(qt_mac_use_fontconfig); ++ } + + return 0; + } +diff --git a/src/qcocoa-qpa/qcocoatheme.mm b/src/qcocoa-qpa/qcocoatheme.mm +index 4212801..ec48be2 100644 +--- a/src/qcocoa-qpa/qcocoatheme.mm ++++ b/src/qcocoa-qpa/qcocoatheme.mm +@@ -50,6 +50,7 @@ + #include "qcocoamenu.h" + #include "qcocoamenubar.h" + #include "qcocoahelpers.h" ++#include "qcocoaintegration.h" + + #include + #include +@@ -189,8 +190,13 @@ const QPalette *QCocoaTheme::palette(Palette type) const + + QHash qt_mac_createRoleFonts() + { +- QCoreTextFontDatabase *ctfd = static_cast(QGuiApplicationPrivate::platformIntegration()->fontDatabase()); +- return ctfd->themeFonts(); ++ QPlatformFontDatabase *db = QGuiApplicationPrivate::platformIntegration()->fontDatabase(); ++ if (!dynamic_cast(db)) { ++ // ctfd must point to a QFontconfigDatabase instance; create a temp QCoreTextFontDatabase ++ // (no need to cache things here, we're called once only) ++ return QCoreTextFontDatabase().themeFonts(); ++ } ++ return static_cast(db)->themeFonts(); + } + + const QFont *QCocoaTheme::font(Font type) const diff --git a/src/qcocoa-qpa/qcocoaintegration.h b/src/qcocoa-qpa/qcocoaintegration.h index 9d5d13f..87d240c 100644 --- a/src/qcocoa-qpa/qcocoaintegration.h +++ b/src/qcocoa-qpa/qcocoaintegration.h @@ -1,216 +1,211 @@ /**************************************************************************** ** ** Copyright (C) 2016 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 QPLATFORMINTEGRATION_COCOA_H #define QPLATFORMINTEGRATION_COCOA_H #include #include "qcocoacursor.h" #include "qcocoawindow.h" #include "qcocoanativeinterface.h" #include "qcocoainputcontext.h" #include "qcocoaaccessibility.h" #include "qcocoaclipboard.h" #include "qcocoadrag.h" #include "qcocoaservices.h" #include "qcocoakeymapper.h" #include #include -#define QT_MAC_USE_FONTCONFIG -#ifdef QT_MAC_USE_FONTCONFIG +#if QT_CONFIG(fontconfig) #include -typedef QFontconfigDatabase QCocoaFontDatabase; -#else -#include -typedef QCoreTextFontDatabase QCocoaFontDatabase; #endif +#include 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 Q_DECL_OVERRIDE; QRect geometry() const Q_DECL_OVERRIDE { return m_geometry; } QRect availableGeometry() const Q_DECL_OVERRIDE { return m_availableGeometry; } int depth() const Q_DECL_OVERRIDE { return m_depth; } QImage::Format format() const Q_DECL_OVERRIDE { return m_format; } qreal devicePixelRatio() const Q_DECL_OVERRIDE; QSizeF physicalSize() const Q_DECL_OVERRIDE { return m_physicalSize; } QDpi logicalDpi() const Q_DECL_OVERRIDE { return m_logicalDpi; } qreal refreshRate() const Q_DECL_OVERRIDE { return m_refreshRate; } QString name() const Q_DECL_OVERRIDE { return m_name; } QPlatformCursor *cursor() const Q_DECL_OVERRIDE { return m_cursor; } QWindow *topLevelAt(const QPoint &point) const Q_DECL_OVERRIDE; QList virtualSiblings() const Q_DECL_OVERRIDE { return m_siblings; } QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const Q_DECL_OVERRIDE; // ---------------------------------------------------- // Additional methods void setVirtualSiblings(const QList &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); } 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 m_siblings; }; class QCocoaIntegration : public QPlatformIntegration { public: enum Option { - UseFreeTypeFontEngine = 0x1 + UseFreeTypeFontEngine = 0x1, + UseFontConfigDatabase = 0x2 }; Q_DECLARE_FLAGS(Options, Option) QCocoaIntegration(const QStringList ¶mList); ~QCocoaIntegration(); static QCocoaIntegration *instance(); Options options() const; bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE; QPlatformWindow *createPlatformWindow(QWindow *window) const Q_DECL_OVERRIDE; QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const Q_DECL_MAYBE_OVERRIDE; #ifndef QT_NO_OPENGL QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const Q_DECL_OVERRIDE; #endif QPlatformBackingStore *createPlatformBackingStore(QWindow *widget) const Q_DECL_OVERRIDE; QAbstractEventDispatcher *createEventDispatcher() const Q_DECL_OVERRIDE; QPlatformFontDatabase *fontDatabase() const Q_DECL_OVERRIDE; QCocoaNativeInterface *nativeInterface() const Q_DECL_OVERRIDE; QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE; #ifndef QT_NO_ACCESSIBILITY QCocoaAccessibility *accessibility() const Q_DECL_OVERRIDE; #endif #ifndef QT_NO_CLIPBOARD QCocoaClipboard *clipboard() const Q_DECL_OVERRIDE; #endif QCocoaDrag *drag() const Q_DECL_OVERRIDE; QStringList themeNames() const Q_DECL_OVERRIDE; QPlatformTheme *createPlatformTheme(const QString &name) const Q_DECL_OVERRIDE; QCocoaServices *services() const Q_DECL_OVERRIDE; QVariant styleHint(StyleHint hint) const Q_DECL_OVERRIDE; Qt::KeyboardModifiers queryKeyboardModifiers() const Q_DECL_OVERRIDE; QList possibleKeys(const QKeyEvent *event) const Q_DECL_OVERRIDE; void updateScreens(); QCocoaScreen *screenForNSScreen(NSScreen *nsScreen); void setToolbar(QWindow *window, NSToolbar *toolbar); NSToolbar *toolbar(QWindow *window) const; void clearToolbars(); void pushPopupWindow(QCocoaWindow *window); QCocoaWindow *popPopupWindow(); QCocoaWindow *activePopupWindow() const; QList *popupWindowStack(); void setApplicationIcon(const QIcon &icon) const Q_DECL_OVERRIDE; void beep() const Q_DECL_OVERRIDE; bool freeTypeFontEngine(bool enabled); + bool fontConfigFontEngine(bool enabled); bool mCanReplaceFontDatabase; - bool fontDatabaseIsCoreText() const; -#ifdef QT_MAC_USE_FONTCONFIG qreal m_fontSmoothingGamma; -#endif private: static QCocoaIntegration *mInstance; Options mOptions; QScopedPointer mFontDb; QScopedPointer mInputContext; #ifndef QT_NO_ACCESSIBILITY QScopedPointer mAccessibility; #endif QScopedPointer mPlatformTheme; QList mScreens; #ifndef QT_NO_CLIPBOARD QCocoaClipboard *mCocoaClipboard; #endif QScopedPointer mCocoaDrag; QScopedPointer mNativeInterface; QScopedPointer mServices; QScopedPointer mKeyboardMapper; QHash mToolbars; QList m_popupWindowStack; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QCocoaIntegration::Options) QT_END_NAMESPACE #endif diff --git a/src/qcocoa-qpa/qcocoaintegration.mm b/src/qcocoa-qpa/qcocoaintegration.mm index 48215b2..db9d19a 100644 --- a/src/qcocoa-qpa/qcocoaintegration.mm +++ b/src/qcocoa-qpa/qcocoaintegration.mm @@ -1,780 +1,825 @@ /**************************************************************************** ** ** Copyright (C) 2016 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 "qcocoaintegration.h" #include "qcocoawindow.h" #include "qcocoabackingstore.h" #include "qcocoanativeinterface.h" #include "qcocoamenuloader.h" #include "qcocoaeventdispatcher.h" #include "qcocoahelpers.h" #include "qcocoaapplication.h" #include "qcocoaapplicationdelegate.h" #include "qcocoatheme.h" #include "qcocoainputcontext.h" #include "qcocoamimetypes.h" #include "qcocoaaccessibility.h" #include #include #include #include #include #ifdef QT_WIDGETS_LIB #include #if QT_CONFIG(filedialog) #include "qcocoafiledialoghelper.h" #endif #endif #include static void initResources() { Q_INIT_RESOURCE(qcocoaresources); } 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 : static_cast(QGuiApplication::primaryScreen()->handle()); 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 proto = static_cast >(nsWindow); QCocoaWindow *cocoaWindow = proto.helper.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 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; } static QCocoaIntegration::Options parseOptions(const QStringList ¶mList) { QCocoaIntegration::Options options; foreach (const QString ¶m, paramList) { #ifndef QT_NO_FREETYPE if (param == QLatin1String("fontengine=freetype")) options |= QCocoaIntegration::UseFreeTypeFontEngine; +#if QT_CONFIG(fontconfig) + // "fontconfig" is actually a font database instead of a font engine, + // but let's present it as a fontengine to the user, for the sake of + // consistency and simplicity. + else if (param == QLatin1String("fontengine=fontconfig")) + options |= QCocoaIntegration::UseFontConfigDatabase; +#endif else #endif qWarning() << "Unknown option" << param; } return options; } QCocoaIntegration *QCocoaIntegration::mInstance = 0; QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) : mOptions(parseOptions(paramList)) , mFontDb(0) #ifndef QT_NO_ACCESSIBILITY , mAccessibility(new QCocoaAccessibility) #endif #ifndef QT_NO_CLIPBOARD , mCocoaClipboard(new QCocoaClipboard) #endif , mCocoaDrag(new QCocoaDrag) , mNativeInterface(new QCocoaNativeInterface) , mServices(new QCocoaServices) , mKeyboardMapper(new QCocoaKeyMapper) , mCanReplaceFontDatabase(true) { if (mInstance != 0) qWarning("Creating multiple Cocoa platform integrations is not supported"); mInstance = this; #ifndef QT_NO_FREETYPE if (qt_mac_resolveOption(false, "QT_MAC_USE_FREETYPE")) { mOptions |= QCocoaIntegration::UseFreeTypeFontEngine; } +# if QT_CONFIG(fontconfig) + if (qt_mac_resolveOption(false, "QT_MAC_USE_FONTCONFIG")) { + mOptions |= QCocoaIntegration::UseFontConfigDatabase; + } +# endif #endif -#ifndef QT_MAC_USE_FONTCONFIG + if (mOptions.testFlag(UseFontConfigDatabase)) { + // has to be: + mOptions |= QCocoaIntegration::UseFreeTypeFontEngine; + } + #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) -#ifndef QT_NO_FREETYPE - if (mOptions.testFlag(UseFreeTypeFontEngine)) - mFontDb.reset(new QCoreTextFontDatabaseEngineFactory); - else -#endif - mFontDb.reset(new QCoreTextFontDatabaseEngineFactory); + m_fontSmoothingGamma = mOptions.testFlag(UseFontConfigDatabase) ? 0.9 : 1.5; #else - mFontDb.reset(new QCoreTextFontDatabase(mOptions.testFlag(UseFreeTypeFontEngine))); + m_fontSmoothingGamma = 0.975 #endif -#else - mFontDb.reset(new QCocoaFontDatabase); - m_fontSmoothingGamma = 0.9; - if (qEnvironmentVariableIsSet("QT_MAC_FONT_GAMMA")) { + if (qEnvironmentVariableIsSet("QT_MAC_FREETYPE_FONT_GAMMA")) { bool ok = false; - qreal fontgamma = qgetenv("QT_MAC_FONT_GAMMA").toDouble(&ok); + qreal fontgamma = qgetenv("QT_MAC_FREETYPE_FONT_GAMMA").toDouble(&ok); if (ok) { m_fontSmoothingGamma = fontgamma; } } + // UseFontConfigDatabase can only be set when !QT_NO_FREETYPE and QT_CONFIG(fontconfig) + // IOW, we can test it safely without any compile-time conditionals. + if (!mOptions.testFlag(UseFontConfigDatabase)) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) +# ifndef QT_NO_FREETYPE + if (mOptions.testFlag(UseFreeTypeFontEngine)) + mFontDb.reset(new QCoreTextFontDatabaseEngineFactory); + else +# endif + mFontDb.reset(new QCoreTextFontDatabaseEngineFactory); +#else + mFontDb.reset(new QCoreTextFontDatabase(mOptions.testFlag(UseFreeTypeFontEngine))); #endif + } else { +#if QT_CONFIG(fontconfig) + mFontDb.reset(new QFontconfigDatabase); +#endif + } QString icStr = QPlatformInputContextFactory::requested(); icStr.isNull() ? mInputContext.reset(new QCocoaInputContext) : mInputContext.reset(QPlatformInputContextFactory::create(icStr)); initResources(); QMacAutoReleasePool pool; NSApplication *cocoaApplication = [QNSApplication sharedApplication]; qt_redirectNSApplicationSendEvent(); if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) { // Applications launched from plain executables (without an app // bundle) are "background" applications that does not take keybaord // focus or have a dock icon or task switcher entry. Qt Gui apps generally // wants to be foreground applications so change the process type. (But // see the function implementation for exceptions.) qt_mac_transformProccessToForegroundApplication(); // 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) { // 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.) [cocoaApplication activateIgnoringOtherApps : YES]; } } // ### For AA_MacPluginApplication we don't want to load the menu nib. // Qt 4 also does not set the application delegate, so that behavior // is matched here. if (!QCoreApplication::testAttribute(Qt::AA_PluginApplication)) { // Set app delegate, link to the current delegate (if any) QCocoaApplicationDelegate *newDelegate = [QCocoaApplicationDelegate sharedDelegate]; [newDelegate setReflectionDelegate:[cocoaApplication delegate]]; [cocoaApplication setDelegate:newDelegate]; // Load the application menu. This menu contains Preferences, Hide, Quit. QCocoaMenuLoader *qtMenuLoader = [QCocoaMenuLoader sharedMenuLoader]; [cocoaApplication setMenu:[qtMenuLoader menu]]; } // The presentation options such as whether or not the dock and/or menu bar is // hidden (automatically by the system) affects the main screen's available // geometry. Since we're initializing the screens synchronously at application // startup we need to ensure that the presentation options have been propagated // to the screen before we read out its properties. Normally OS X does this in // an asynchronous callback, but that's too late for us. We force the propagation // by explicitly setting the presentation option to the magic 'default value', // which will resolve to an actual value and result in screen invalidation. cocoaApplication.presentationOptions = NSApplicationPresentationDefault; updateScreens(); QMacInternalPasteboardMime::initializeMimeTypes(); QCocoaMimeTypes::initializeMimeTypes(); QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false); } QCocoaIntegration::~QCocoaIntegration() { mInstance = 0; qt_resetNSApplicationSendEvent(); QMacAutoReleasePool pool; if (!QCoreApplication::testAttribute(Qt::AA_PluginApplication)) { // remove the apple event handlers installed by QCocoaApplicationDelegate QCocoaApplicationDelegate *delegate = [QCocoaApplicationDelegate sharedDelegate]; [delegate removeAppleEventHandlers]; // reset the application delegate [[NSApplication sharedApplication] setDelegate: 0]; } #ifndef QT_NO_CLIPBOARD // Delete the clipboard integration and destroy mime type converters. // Deleting the clipboard integration flushes promised pastes using // the mime converters - the ordering here is important. delete mCocoaClipboard; QMacInternalPasteboardMime::destroyMimeTypes(); #endif // Delete screens in reverse order to avoid crash in case of multiple screens while (!mScreens.isEmpty()) { destroyScreen(mScreens.takeLast()); } clearToolbars(); } QCocoaIntegration *QCocoaIntegration::instance() { return mInstance; } QCocoaIntegration::Options QCocoaIntegration::options() const { return mOptions; } /*! \brief Synchronizes the screen list, adds new screens, removes deleted ones */ void QCocoaIntegration::updateScreens() { NSArray *scrs = [NSScreen screens]; NSMutableArray *screens = [NSMutableArray arrayWithArray:scrs]; if ([screens count] == 0) if ([NSScreen mainScreen]) [screens addObject:[NSScreen mainScreen]]; if ([screens count] == 0) return; QSet remainingScreens = QSet::fromList(mScreens); QList siblings; uint screenCount = [screens count]; for (uint i = 0; i < screenCount; i++) { NSScreen* scr = [screens objectAtIndex:i]; CGDirectDisplayID dpy = [[[scr deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue]; // If this screen is a mirror and is not the primary one of the mirror set, ignore it. // Exception: The NSScreen API has been observed to a return a screen list with one // mirrored, non-primary screen when Qt is running as a startup item. Always use the // screen if there's only one screen in the list. if (screenCount > 1 && CGDisplayIsInMirrorSet(dpy)) { CGDirectDisplayID primary = CGDisplayMirrorsDisplay(dpy); if (primary != kCGNullDirectDisplay && primary != dpy) continue; } QCocoaScreen* screen = NULL; foreach (QCocoaScreen* existingScr, mScreens) // NSScreen documentation says do not cache the array returned from [NSScreen screens]. // However in practice, we can identify a screen by its pointer: if resolution changes, // the NSScreen object will be the same instance, just with different values. if (existingScr->nativeScreen() == scr) { screen = existingScr; break; } if (screen) { remainingScreens.remove(screen); screen->updateGeometry(); } else { screen = new QCocoaScreen(i); mScreens.append(screen); screenAdded(screen); } siblings << screen; } // Set virtual siblings list. All screens in mScreens are siblings, because we ignored the // mirrors. Note that some of the screens we update the siblings list for here may be deleted // below, but update anyway to keep the to-be-deleted screens out of the siblings list. foreach (QCocoaScreen* screen, mScreens) screen->setVirtualSiblings(siblings); // Now the leftovers in remainingScreens are no longer current, so we can delete them. foreach (QCocoaScreen* screen, remainingScreens) { mScreens.removeOne(screen); // Prevent stale references to NSScreen during destroy screen->m_screenIndex = -1; destroyScreen(screen); } } QCocoaScreen *QCocoaIntegration::screenForNSScreen(NSScreen *nsScreen) { NSUInteger index = [[NSScreen screens] indexOfObject:nsScreen]; if (index == NSNotFound) return 0; if (index >= unsigned(mScreens.count())) updateScreens(); for (QCocoaScreen *screen : mScreens) { if (screen->nativeScreen() == nsScreen) return screen; } return 0; } bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) const { switch (cap) { case ThreadedPixmaps: #ifndef QT_NO_OPENGL case OpenGL: case ThreadedOpenGL: case BufferQueueingOpenGL: #endif case WindowMasks: case MultipleWindows: case ForeignWindows: case RasterGLSurface: case ApplicationState: case ApplicationIcon: return true; default: return QPlatformIntegration::hasCapability(cap); } } QPlatformWindow *QCocoaIntegration::createPlatformWindow(QWindow *window) const { return new QCocoaWindow(window); } QPlatformWindow *QCocoaIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const { return new QCocoaWindow(window, nativeHandle); } #ifndef QT_NO_OPENGL QPlatformOpenGLContext *QCocoaIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { QCocoaGLContext *glContext = new QCocoaGLContext(context->format(), context->shareHandle(), context->nativeHandle()); context->setNativeHandle(glContext->nativeHandle()); return glContext; } #endif QPlatformBackingStore *QCocoaIntegration::createPlatformBackingStore(QWindow *window) const { return new QCocoaBackingStore(window); } QAbstractEventDispatcher *QCocoaIntegration::createEventDispatcher() const { return new QCocoaEventDispatcher; } QPlatformFontDatabase *QCocoaIntegration::fontDatabase() const { QCocoaIntegration::instance()->mCanReplaceFontDatabase = false; return mFontDb.data(); } QCocoaNativeInterface *QCocoaIntegration::nativeInterface() const { return mNativeInterface.data(); } QPlatformInputContext *QCocoaIntegration::inputContext() const { return mInputContext.data(); } #ifndef QT_NO_ACCESSIBILITY QCocoaAccessibility *QCocoaIntegration::accessibility() const { return mAccessibility.data(); } #endif #ifndef QT_NO_CLIPBOARD QCocoaClipboard *QCocoaIntegration::clipboard() const { return mCocoaClipboard; } #endif QCocoaDrag *QCocoaIntegration::drag() const { return mCocoaDrag.data(); } QStringList QCocoaIntegration::themeNames() const { QStringList themes; themes.push_back(QLatin1String(QCocoaTheme::name)); const QByteArray kdeSessionVersion = qgetenv("KDE_SESSION_VERSION"); const int kdeVersion = kdeSessionVersion.toInt(); if (kdeVersion >= 4) themes.push_back(QLatin1String("kde")); return themes; } QPlatformTheme *QCocoaIntegration::createPlatformTheme(const QString &name) const { if (name == QLatin1String(QCocoaTheme::name)) return new QCocoaTheme; return QPlatformIntegration::createPlatformTheme(name); } QCocoaServices *QCocoaIntegration::services() const { return mServices.data(); } QVariant QCocoaIntegration::styleHint(StyleHint hint) const { -#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) - #define FREETYPEGAMMA 1.5 -#else - #define FREETYPEGAMMA 0.975 -#endif if (hint == QPlatformIntegration::FontSmoothingGamma) #ifdef QT_MAC_USE_FONTCONFIG return m_fontSmoothingGamma; #else - return mOptions.testFlag(UseFreeTypeFontEngine)? FREETYPEGAMMA : 2.0; + return mOptions.testFlag(UseFreeTypeFontEngine)? m_fontSmoothingGamma : 2.0; #endif return QPlatformIntegration::styleHint(hint); } Qt::KeyboardModifiers QCocoaIntegration::queryKeyboardModifiers() const { return QCocoaKeyMapper::queryKeyboardModifiers(); } QList QCocoaIntegration::possibleKeys(const QKeyEvent *event) const { return mKeyboardMapper->possibleKeys(event); } void QCocoaIntegration::setToolbar(QWindow *window, NSToolbar *toolbar) { if (NSToolbar *prevToolbar = mToolbars.value(window)) [prevToolbar release]; [toolbar retain]; mToolbars.insert(window, toolbar); } NSToolbar *QCocoaIntegration::toolbar(QWindow *window) const { return mToolbars.value(window); } void QCocoaIntegration::clearToolbars() { QHash::const_iterator it = mToolbars.constBegin(); while (it != mToolbars.constEnd()) { [it.value() release]; ++it; } mToolbars.clear(); } void QCocoaIntegration::pushPopupWindow(QCocoaWindow *window) { m_popupWindowStack.append(window); } QCocoaWindow *QCocoaIntegration::popPopupWindow() { if (m_popupWindowStack.isEmpty()) return 0; return m_popupWindowStack.takeLast(); } QCocoaWindow *QCocoaIntegration::activePopupWindow() const { if (m_popupWindowStack.isEmpty()) return 0; return m_popupWindowStack.front(); } QList *QCocoaIntegration::popupWindowStack() { return &m_popupWindowStack; } void QCocoaIntegration::setApplicationIcon(const QIcon &icon) const { NSImage *image = nil; if (!icon.isNull()) { NSSize size = [[[NSApplication sharedApplication] dockTile] size]; QPixmap pixmap = icon.pixmap(size.width, size.height); image = static_cast(qt_mac_create_nsimage(pixmap)); } [[NSApplication sharedApplication] setApplicationIconImage:image]; [image release]; } void QCocoaIntegration::beep() const { NSBeep(); } bool QCocoaIntegration::freeTypeFontEngine(bool enabled) { -#ifndef QT_MAC_USE_FONTCONFIG + if (mOptions.testFlag(UseFontConfigDatabase)) { + // can't be any other way + return true; + } if (!mCanReplaceFontDatabase) { return false; } #ifndef QT_NO_FREETYPE auto options = mOptions; if (enabled) { options |= QCocoaIntegration::UseFreeTypeFontEngine; } else { options &= ~QCocoaIntegration::UseFreeTypeFontEngine; + // FontConfig can no longer be used either. + options &= ~QCocoaIntegration::UseFontConfigDatabase; } if (options != mOptions) { mOptions = options; #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) if (mOptions.testFlag(UseFreeTypeFontEngine)) mFontDb.reset(new QCoreTextFontDatabaseEngineFactory); else mFontDb.reset(new QCoreTextFontDatabaseEngineFactory); #else mFontDb.reset(new QCoreTextFontDatabase(mOptions.testFlag(UseFreeTypeFontEngine))); #endif return true; } -#endif -#endif //FONTCONFIG return false; +#endif } -bool QCocoaIntegration::fontDatabaseIsCoreText() const +bool QCocoaIntegration::fontConfigFontEngine(bool enabled) { -#ifdef QT_MAC_USE_FONTCONFIG - return false; +#if QT_CONFIG(fontconfig) + if (!mCanReplaceFontDatabase) { + return false; + } + auto options = mOptions; + bool ret = false; + if (enabled) { + options |= QCocoaIntegration::UseFreeTypeFontEngine | QCocoaIntegration::UseFontConfigDatabase; + if (options != mOptions) { + mOptions = options; + mFontDb.reset(new QFontconfigDatabase); + ret = true; + } + } else { + options &= ~QCocoaIntegration::UseFontConfigDatabase; + if (options != mOptions) { + mOptions = options; + // UseFreeTypeFontEngine is still set: + ret = freeTypeFontEngine(false); + } + } + return ret; #else - return true; + // can't be any other way + return false; #endif } QT_END_NAMESPACE diff --git a/src/qcocoa-qpa/qcocoanativeinterface.mm b/src/qcocoa-qpa/qcocoanativeinterface.mm index 612b9e4..3191b38 100644 --- a/src/qcocoa-qpa/qcocoanativeinterface.mm +++ b/src/qcocoa-qpa/qcocoanativeinterface.mm @@ -1,389 +1,397 @@ /**************************************************************************** ** ** Copyright (C) 2016 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 "qcocoanativeinterface.h" #include "qcocoawindow.h" #include "qcocoamenu.h" #include "qcocoamenubar.h" #include "qcocoahelpers.h" #include "qcocoaapplication.h" #include "qcocoaintegration.h" #include "qcocoaeventdispatcher.h" #include #include #include #include #include "qsurfaceformat.h" #ifndef QT_NO_OPENGL #include #include "qopenglcontext.h" #include "qcocoaglcontext.h" #endif #include "qguiapplication.h" #include #ifndef QT_NO_WIDGETS #include "qcocoaprintersupport.h" #include "qprintengine_mac_p.h" #include #endif #include #include #include QT_BEGIN_NAMESPACE static bool qt_mac_use_freetype(bool enabled) { return QCocoaIntegration::instance()->freeTypeFontEngine(enabled); } +static bool qt_mac_use_fontconfig(bool enabled) +{ + return QCocoaIntegration::instance()->fontConfigFontEngine(enabled); +} + QCocoaNativeInterface::QCocoaNativeInterface() { } #ifndef QT_NO_OPENGL void *QCocoaNativeInterface::nativeResourceForContext(const QByteArray &resourceString, QOpenGLContext *context) { if (!context) return 0; if (resourceString.toLower() == "nsopenglcontext") return nsOpenGLContextForContext(context); if (resourceString.toLower() == "cglcontextobj") return cglContextForContext(context); return 0; } #endif void *QCocoaNativeInterface::nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) { if (!window->handle()) return 0; if (resourceString == "nsview") { return static_cast(window->handle())->m_view; #ifndef QT_NO_OPENGL } else if (resourceString == "nsopenglcontext") { return static_cast(window->handle())->currentContext()->nsOpenGLContext(); #endif } else if (resourceString == "nswindow") { return static_cast(window->handle())->m_nsWindow; } return 0; } QPlatformNativeInterface::NativeResourceForIntegrationFunction QCocoaNativeInterface::nativeResourceFunctionForIntegration(const QByteArray &resource) { if (resource.toLower() == "addtomimelist") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::addToMimeList); if (resource.toLower() == "removefrommimelist") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::removeFromMimeList); if (resource.toLower() == "registerdraggedtypes") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::registerDraggedTypes); if (resource.toLower() == "setdockmenu") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setDockMenu); if (resource.toLower() == "qmenutonsmenu") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::qMenuToNSMenu); if (resource.toLower() == "qmenubartonsmenu") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::qMenuBarToNSMenu); if (resource.toLower() == "qimagetocgimage") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::qImageToCGImage); if (resource.toLower() == "cgimagetoqimage") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::cgImageToQImage); if (resource.toLower() == "registertouchwindow") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::registerTouchWindow); if (resource.toLower() == "setembeddedinforeignview") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setEmbeddedInForeignView); if (resource.toLower() == "setcontentborderthickness") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setContentBorderThickness); if (resource.toLower() == "registercontentborderarea") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::registerContentBorderArea); if (resource.toLower() == "setcontentborderareaenabled") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setContentBorderAreaEnabled); if (resource.toLower() == "setcontentborderenabled") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setContentBorderEnabled); if (resource.toLower() == "setnstoolbar") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setNSToolbar); if (resource.toLower() == "testcontentborderposition") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::testContentBorderPosition); if (resource.toLower() == "qt_mac_use_freetype") { return NativeResourceForIntegrationFunction(qt_mac_use_freetype); } + if (resource.toLower() == "qt_mac_use_fontconfig") { + return NativeResourceForIntegrationFunction(qt_mac_use_fontconfig); + } return 0; } QPlatformPrinterSupport *QCocoaNativeInterface::createPlatformPrinterSupport() { #if !defined(QT_NO_WIDGETS) && !defined(QT_NO_PRINTER) return new QCocoaPrinterSupport(); #else qFatal("Printing is not supported when Qt is configured with -no-widgets"); return 0; #endif } void *QCocoaNativeInterface::NSPrintInfoForPrintEngine(QPrintEngine *printEngine) { #if !defined(QT_NO_WIDGETS) && !defined(QT_NO_PRINTER) QMacPrintEnginePrivate *macPrintEnginePriv = static_cast(printEngine)->d_func(); if (macPrintEnginePriv->state == QPrinter::Idle && !macPrintEnginePriv->isPrintSessionInitialized()) macPrintEnginePriv->initialize(); return macPrintEnginePriv->printInfo; #else Q_UNUSED(printEngine); qFatal("Printing is not supported when Qt is configured with -no-widgets"); return 0; #endif } QPixmap QCocoaNativeInterface::defaultBackgroundPixmapForQWizard() { QCFType url109; CFURLRef url = nullptr; const int ExpectedImageWidth = 242; const int ExpectedImageHeight = 414; bool ok = false; if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_10) { if (LSFindApplicationForInfo(kLSUnknownCreator, CFSTR("com.apple.KeyboardSetupAssistant"), 0, 0, &url109) == noErr) { url = url109; ok = true; } } else { #if QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_10) QCFType urls = LSCopyApplicationURLsForBundleIdentifier( CFSTR("com.apple.KeyboardSetupAssistant"), nullptr); if (urls && CFArrayGetCount(urls) > 0) { url = (CFURLRef)CFArrayGetValueAtIndex(urls, 0); ok = true; } #endif } if (ok) { QCFType bundle = CFBundleCreate(kCFAllocatorDefault, url); if (bundle) { url = CFBundleCopyResourceURL(bundle, CFSTR("Background"), CFSTR("png"), 0); if (url) { QCFType imageSource = CGImageSourceCreateWithURL(url, 0); QCFType image = CGImageSourceCreateImageAtIndex(imageSource, 0, 0); if (image) { int width = CGImageGetWidth(image); int height = CGImageGetHeight(image); if (width == ExpectedImageWidth && height == ExpectedImageHeight) return QPixmap::fromImage(qt_mac_toQImage(image)); } } } } return QPixmap(); } void QCocoaNativeInterface::clearCurrentThreadCocoaEventDispatcherInterruptFlag() { QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag(); } void QCocoaNativeInterface::onAppFocusWindowChanged(QWindow *window) { Q_UNUSED(window); QCocoaMenuBar::updateMenuBarImmediately(); } #ifndef QT_NO_OPENGL void *QCocoaNativeInterface::cglContextForContext(QOpenGLContext* context) { NSOpenGLContext *nsOpenGLContext = static_cast(nsOpenGLContextForContext(context)); if (nsOpenGLContext) return [nsOpenGLContext CGLContextObj]; return 0; } void *QCocoaNativeInterface::nsOpenGLContextForContext(QOpenGLContext* context) { if (context) { QCocoaGLContext *cocoaGLContext = static_cast(context->handle()); if (cocoaGLContext) { return cocoaGLContext->nsOpenGLContext(); } } return 0; } #endif QFunctionPointer QCocoaNativeInterface::platformFunction(const QByteArray &function) const { if (function == QCocoaWindowFunctions::bottomLeftClippedByNSWindowOffsetIdentifier()) return QFunctionPointer(QCocoaWindowFunctions::BottomLeftClippedByNSWindowOffset(QCocoaWindow::bottomLeftClippedByNSWindowOffsetStatic)); return Q_NULLPTR; } void QCocoaNativeInterface::addToMimeList(void *macPasteboardMime) { qt_mac_addToGlobalMimeList(reinterpret_cast(macPasteboardMime)); } void QCocoaNativeInterface::removeFromMimeList(void *macPasteboardMime) { qt_mac_removeFromGlobalMimeList(reinterpret_cast(macPasteboardMime)); } void QCocoaNativeInterface::registerDraggedTypes(const QStringList &types) { qt_mac_registerDraggedTypes(types); } void QCocoaNativeInterface::setDockMenu(QPlatformMenu *platformMenu) { QMacAutoReleasePool pool; QCocoaMenu *cocoaPlatformMenu = static_cast(platformMenu); NSMenu *menu = cocoaPlatformMenu->nsMenu(); [NSApp QT_MANGLE_NAMESPACE(qt_setDockMenu): menu]; } void *QCocoaNativeInterface::qMenuToNSMenu(QPlatformMenu *platformMenu) { QMacAutoReleasePool pool; QCocoaMenu *cocoaPlatformMenu = static_cast(platformMenu); NSMenu *menu = cocoaPlatformMenu->nsMenu(); return reinterpret_cast(menu); } void *QCocoaNativeInterface::qMenuBarToNSMenu(QPlatformMenuBar *platformMenuBar) { QCocoaMenuBar *cocoaPlatformMenuBar = static_cast(platformMenuBar); NSMenu *menu = cocoaPlatformMenuBar->nsMenu(); return reinterpret_cast(menu); } CGImageRef QCocoaNativeInterface::qImageToCGImage(const QImage &image) { return qt_mac_toCGImage(image); } QImage QCocoaNativeInterface::cgImageToQImage(CGImageRef image) { return qt_mac_toQImage(image); } void QCocoaNativeInterface::setEmbeddedInForeignView(QPlatformWindow *window, bool embedded) { QCocoaWindow *cocoaPlatformWindow = static_cast(window); cocoaPlatformWindow->setEmbeddedInForeignView(embedded); } void QCocoaNativeInterface::registerTouchWindow(QWindow *window, bool enable) { if (!window) return; QCocoaWindow *cocoaWindow = static_cast(window->handle()); if (cocoaWindow) cocoaWindow->registerTouch(enable); } void QCocoaNativeInterface::setContentBorderThickness(QWindow *window, int topThickness, int bottomThickness) { if (!window) return; QCocoaWindow *cocoaWindow = static_cast(window->handle()); if (cocoaWindow) cocoaWindow->setContentBorderThickness(topThickness, bottomThickness); } void QCocoaNativeInterface::registerContentBorderArea(QWindow *window, quintptr identifier, int upper, int lower) { if (!window) return; QCocoaWindow *cocoaWindow = static_cast(window->handle()); if (cocoaWindow) cocoaWindow->registerContentBorderArea(identifier, upper, lower); } void QCocoaNativeInterface::setContentBorderAreaEnabled(QWindow *window, quintptr identifier, bool enable) { if (!window) return; QCocoaWindow *cocoaWindow = static_cast(window->handle()); if (cocoaWindow) cocoaWindow->setContentBorderAreaEnabled(identifier, enable); } void QCocoaNativeInterface::setContentBorderEnabled(QWindow *window, bool enable) { if (!window) return; QCocoaWindow *cocoaWindow = static_cast(window->handle()); if (cocoaWindow) cocoaWindow->setContentBorderEnabled(enable); } void QCocoaNativeInterface::setNSToolbar(QWindow *window, void *nsToolbar) { QCocoaIntegration::instance()->setToolbar(window, static_cast(nsToolbar)); QCocoaWindow *cocoaWindow = static_cast(window->handle()); if (cocoaWindow) cocoaWindow->updateNSToolbar(); } bool QCocoaNativeInterface::testContentBorderPosition(QWindow *window, int position) { if (!window) return false; QCocoaWindow *cocoaWindow = static_cast(window->handle()); if (cocoaWindow) return cocoaWindow->testContentBorderAreaPosition(position); return false; } QT_END_NAMESPACE diff --git a/src/qcocoa-qpa/qcocoatheme.mm b/src/qcocoa-qpa/qcocoatheme.mm index 901beff..ec48be2 100644 --- a/src/qcocoa-qpa/qcocoatheme.mm +++ b/src/qcocoa-qpa/qcocoatheme.mm @@ -1,400 +1,398 @@ /**************************************************************************** ** ** Copyright (C) 2016 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$ ** ****************************************************************************/ #import #include "qcocoatheme.h" #include "messages.h" #include #include "qcocoasystemsettings.h" #include "qcocoasystemtrayicon.h" #include "qcocoamenuitem.h" #include "qcocoamenu.h" #include "qcocoamenubar.h" #include "qcocoahelpers.h" #include "qcocoaintegration.h" #include #include #include #include #include #include #include #include #include #ifdef QT_WIDGETS_LIB #include #if QT_CONFIG(colordialog) #include "qcocoacolordialoghelper.h" #endif #if QT_CONFIG(filedialog) #include "qcocoafiledialoghelper.h" #endif #if QT_CONFIG(fontdialog) #include "qcocoafontdialoghelper.h" #endif #endif #include @interface QT_MANGLE_NAMESPACE(QCocoaThemeNotificationReceiver) : NSObject { QCocoaTheme *mPrivate; } - (id)initWithPrivate:(QCocoaTheme *)priv; - (void)systemColorsDidChange:(NSNotification *)notification; @end QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaThemeNotificationReceiver); @implementation QCocoaThemeNotificationReceiver - (id)initWithPrivate:(QCocoaTheme *)priv { self = [super init]; mPrivate = priv; return self; } - (void)systemColorsDidChange:(NSNotification *)notification { Q_UNUSED(notification); mPrivate->reset(); QWindowSystemInterface::handleThemeChange(Q_NULLPTR); } @end QT_BEGIN_NAMESPACE const char *QCocoaTheme::name = "cocoa"; QCocoaTheme::QCocoaTheme() :m_systemPalette(0) { m_notificationReceiver = [[QT_MANGLE_NAMESPACE(QCocoaThemeNotificationReceiver) alloc] initWithPrivate:this]; [[NSNotificationCenter defaultCenter] addObserver:m_notificationReceiver selector:@selector(systemColorsDidChange:) name:NSSystemColorsDidChangeNotification object:nil]; } QCocoaTheme::~QCocoaTheme() { [[NSNotificationCenter defaultCenter] removeObserver:m_notificationReceiver]; [m_notificationReceiver release]; reset(); qDeleteAll(m_fonts); } void QCocoaTheme::reset() { delete m_systemPalette; m_systemPalette = Q_NULLPTR; qDeleteAll(m_palettes); m_palettes.clear(); } bool QCocoaTheme::usePlatformNativeDialog(DialogType dialogType) const { if (dialogType == QPlatformTheme::FileDialog) return true; #if defined(QT_WIDGETS_LIB) && QT_CONFIG(colordialog) if (dialogType == QPlatformTheme::ColorDialog) return true; #endif #if defined(QT_WIDGETS_LIB) && QT_CONFIG(fontdialog) if (dialogType == QPlatformTheme::FontDialog) return true; #endif return false; } QPlatformDialogHelper * QCocoaTheme::createPlatformDialogHelper(DialogType dialogType) const { switch (dialogType) { #if defined(QT_WIDGETS_LIB) && QT_CONFIG(filedialog) case QPlatformTheme::FileDialog: return new QCocoaFileDialogHelper(); #endif #if defined(QT_WIDGETS_LIB) && QT_CONFIG(colordialog) case QPlatformTheme::ColorDialog: return new QCocoaColorDialogHelper(); #endif #if defined(QT_WIDGETS_LIB) && QT_CONFIG(fontdialog) case QPlatformTheme::FontDialog: return new QCocoaFontDialogHelper(); #endif default: return 0; } } #ifndef QT_NO_SYSTEMTRAYICON QPlatformSystemTrayIcon *QCocoaTheme::createPlatformSystemTrayIcon() const { return new QCocoaSystemTrayIcon; } #endif const QPalette *QCocoaTheme::palette(Palette type) const { if (type == SystemPalette) { if (!m_systemPalette) m_systemPalette = qt_mac_createSystemPalette(); return m_systemPalette; } else { if (m_palettes.isEmpty()) m_palettes = qt_mac_createRolePalettes(); return m_palettes.value(type, 0); } return 0; } QHash qt_mac_createRoleFonts() { - static QCoreTextFontDatabase *ctfd = NULL; - if (!ctfd) { - if (QCocoaIntegration::instance()->fontDatabaseIsCoreText()) { - ctfd = static_cast(QGuiApplicationPrivate::platformIntegration()->fontDatabase()); - } else { - ctfd = new QCoreTextFontDatabase; - } + QPlatformFontDatabase *db = QGuiApplicationPrivate::platformIntegration()->fontDatabase(); + if (!dynamic_cast(db)) { + // ctfd must point to a QFontconfigDatabase instance; create a temp QCoreTextFontDatabase + // (no need to cache things here, we're called once only) + return QCoreTextFontDatabase().themeFonts(); } - return ctfd->themeFonts(); + return static_cast(db)->themeFonts(); } const QFont *QCocoaTheme::font(Font type) const { if (m_fonts.isEmpty()) { m_fonts = qt_mac_createRoleFonts(); } return m_fonts.value(type, 0); } //! \internal QPixmap qt_mac_convert_iconref(const IconRef icon, int width, int height) { QPixmap ret(width, height); ret.fill(QColor(0, 0, 0, 0)); CGRect rect = CGRectMake(0, 0, width, height); QMacCGContext ctx(&ret); CGAffineTransform old_xform = CGContextGetCTM(ctx); CGContextConcatCTM(ctx, CGAffineTransformInvert(old_xform)); CGContextConcatCTM(ctx, CGAffineTransformIdentity); ::RGBColor b; b.blue = b.green = b.red = 255*255; PlotIconRefInContext(ctx, &rect, kAlignNone, kTransformNone, &b, kPlotIconRefNormalFlags, icon); return ret; } QPixmap QCocoaTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const { OSType iconType = 0; switch (sp) { case MessageBoxQuestion: iconType = kQuestionMarkIcon; break; case MessageBoxInformation: iconType = kAlertNoteIcon; break; case MessageBoxWarning: iconType = kAlertCautionIcon; break; case MessageBoxCritical: iconType = kAlertStopIcon; break; case DesktopIcon: iconType = kDesktopIcon; break; case TrashIcon: iconType = kTrashIcon; break; case ComputerIcon: iconType = kComputerIcon; break; case DriveFDIcon: iconType = kGenericFloppyIcon; break; case DriveHDIcon: iconType = kGenericHardDiskIcon; break; case DriveCDIcon: case DriveDVDIcon: iconType = kGenericCDROMIcon; break; case DriveNetIcon: iconType = kGenericNetworkIcon; break; case DirOpenIcon: iconType = kOpenFolderIcon; break; case DirClosedIcon: case DirLinkIcon: iconType = kGenericFolderIcon; break; case FileLinkIcon: case FileIcon: iconType = kGenericDocumentIcon; break; default: break; } if (iconType != 0) { QPixmap pixmap; IconRef icon = Q_NULLPTR; GetIconRef(kOnSystemDisk, kSystemIconsCreator, iconType, &icon); if (icon) { pixmap = qt_mac_convert_iconref(icon, size.width(), size.height()); ReleaseIconRef(icon); } return pixmap; } return QPlatformTheme::standardPixmap(sp, size); } class QCocoaFileIconEngine : public QAbstractFileIconEngine { public: explicit QCocoaFileIconEngine(const QFileInfo &info, QPlatformTheme::IconOptions opts) : QAbstractFileIconEngine(info, opts) {} static QList availableIconSizes() { const qreal devicePixelRatio = qGuiApp->devicePixelRatio(); const int sizes[] = { qRound(16 * devicePixelRatio), qRound(32 * devicePixelRatio), qRound(64 * devicePixelRatio), qRound(128 * devicePixelRatio), qRound(256 * devicePixelRatio) }; return QAbstractFileIconEngine::toSizeList(sizes, sizes + sizeof(sizes) / sizeof(sizes[0])); } QList availableSizes(QIcon::Mode = QIcon::Normal, QIcon::State = QIcon::Off) const override { return QCocoaFileIconEngine::availableIconSizes(); } protected: QPixmap filePixmap(const QSize &size, QIcon::Mode, QIcon::State) override { QMacAutoReleasePool pool; NSImage *iconImage = [[NSWorkspace sharedWorkspace] iconForFile:fileInfo().canonicalFilePath().toNSString()]; if (!iconImage) return QPixmap(); return qt_mac_toQPixmap(iconImage, size); } }; QIcon QCocoaTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions) const { return QIcon(new QCocoaFileIconEngine(fileInfo, iconOptions)); } QVariant QCocoaTheme::themeHint(ThemeHint hint) const { switch (hint) { case QPlatformTheme::StyleNames: return QStringList({QStringLiteral("aqua"), QStringLiteral("macintosh")}); case QPlatformTheme::DialogButtonBoxLayout: return QVariant(QPlatformDialogHelper::MacLayout); case KeyboardScheme: return QVariant(int(MacKeyboardScheme)); case TabFocusBehavior: return QVariant([[NSApplication sharedApplication] isFullKeyboardAccessEnabled] ? int(Qt::TabFocusAllControls) : int(Qt::TabFocusTextControls | Qt::TabFocusListControls)); case IconPixmapSizes: return QVariant::fromValue(QCocoaFileIconEngine::availableIconSizes()); case QPlatformTheme::PasswordMaskCharacter: return QVariant(QChar(kBulletUnicode)); case QPlatformTheme::UiEffects: return QVariant(int(HoverEffect)); default: break; } return QPlatformTheme::themeHint(hint); } QString QCocoaTheme::standardButtonText(int button) const { return button == QPlatformDialogHelper::Discard ? msgDialogButtonDiscard() : QPlatformTheme::standardButtonText(button); } QKeySequence QCocoaTheme::standardButtonShortcut(int button) const { #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) return button == QPlatformDialogHelper::Discard ? QKeySequence(Qt::CTRL | Qt::Key_Delete) : QPlatformTheme::standardButtonShortcut(button); #else return button == QPlatformDialogHelper::Discard ? QKeySequence(Qt::CTRL | Qt::Key_Delete) : QKeySequence(); #endif } QPlatformMenuItem *QCocoaTheme::createPlatformMenuItem() const { return new QCocoaMenuItem(); } QPlatformMenu *QCocoaTheme::createPlatformMenu() const { return new QCocoaMenu(); } QPlatformMenuBar *QCocoaTheme::createPlatformMenuBar() const { static bool haveMenubar = false; if (!haveMenubar) { haveMenubar = true; QObject::connect(qGuiApp, SIGNAL(focusWindowChanged(QWindow*)), QGuiApplicationPrivate::platformIntegration()->nativeInterface(), SLOT(onAppFocusWindowChanged(QWindow*))); } return new QCocoaMenuBar(); } QT_END_NAMESPACE