diff --git a/src/qcocoa-qpa/README.ALT b/src/qcocoa-qpa/README.ALT index 434a447..be344f0 100644 --- a/src/qcocoa-qpa/README.ALT +++ b/src/qcocoa-qpa/README.ALT @@ -1,383 +1,387 @@ +20171231 +Improved control over selecting the FreeType fontengine and equivalent options +to select the use of a FontConfig fontdatabase with FreeType fontengine. + 20171219 : upstream head (5.9): b0938cb6c1fa29ec2d2a4fb9273e515cd0d6c08e src/plugins/platforms/cocoa/qcocoamenuloader.mm | 8 +- patch: patches/26-sync-upstream-171219.diff Changes: git log 6a9d076e87f0c8aa4fb49bbcc2f56eefd85af2e3..b0938cb6c1fa29ec2d2a4fb9273e515cd0d6c08e src/plugins/platforms/cocoa commit 29104c85db53e7c0c0aaf3fe78f84b737fce4886 Cocoa: Disable “Hide” menu item on open popups 20171126 : upstream head (5.9): 6a9d076e87f0c8aa4fb49bbcc2f56eefd85af2e3 / v5.9.3-43-g6a9d076 src/plugins/platforms/cocoa/qcocoamenu.h | 2 + src/plugins/platforms/cocoa/qcocoamenu.mm | 16 ++- src/plugins/platforms/cocoa/qcocoamenubar.h | 2 + src/plugins/platforms/cocoa/qcocoamenubar.mm | 11 +- src/plugins/platforms/cocoa/qcocoamenuitem.mm | 4 - src/plugins/platforms/cocoa/qcocoawindow.mm | 15 +++ src/plugins/platforms/cocoa/qnsview.mm | 1 + patch: patches/25-sync-upstream-171126.diff Changes: git log 01c7b474f5ad2c9fcf4b90c71048624070811618..6a9d076e87f0c8aa4fb49bbcc2f56eefd85af2e3 src/plugins/platforms/cocoa commit d0736e9d17d0b3ec2f7aa3f323a1edf70aa83e27 Cocoa: Make High DPI drag cursor work commit 3f519ffa150ce5a2d9e3ad3f147745b312d29afb QCocoaMenuItem: Don't clear NSMenuItem.action when setting submenu commit 5194817941985c766bbc7f80039a58e0cf504b55 Cocoa: optimize backingstore flush on 10-bit displays commit 385589ef458715fcaa533bbd01ca421dc1040eba QCocoaMenu: Attach menu items when updating the menubar 20171030 : upstream head (5.9): 01c7b474f5ad2c9fcf4b90c71048624070811618 src/plugins/platforms/cocoa/cocoa.pro | 11 +- src/plugins/platforms/cocoa/messages.cpp | 2 +- src/plugins/platforms/cocoa/messages.h | 11 + src/plugins/platforms/cocoa/qcocoamenuitem.mm | 10 +- src/plugins/platforms/cocoa/qcocoamenuloader.mm | 20 +- src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm | 31 --- src/plugins/platforms/cocoa/qcocoawindow.mm | 2 + patches: patches/24-sync-upstream-171030.diff patches/24b-patch-build-on-OSX109.diff Changes: git log e03b64c5b1eeebfbbb94d67eb9a9c1d35eaba0bb..01c7b474f5ad2c9fcf4b90c71048624070811618 commit 37a1478787d64b34a0716421c8a47f3246e41bfd Cocoa QPA: Code clean up, make some bits more readable commit c99d8532c892f72f897c9e686be75d1ebba67618 QCocoaSystemTrayIcon: Remove unused classes Both QNSMenu and QSystemTrayIconQMenu aren't referenced anywhere else, including within qcocoasystemtrayicon.mm, since the QPA backend was added. commit f13e75345d035ec906846aaa3540454787edbd3f Cocoa QPA: Remove usage of OBJECTIVE_SOURCES commit 8ac9addd946637401e4685c6e91d1a3cd5b2d768 QCocoaWindow: Toggle titlebar transparency to support unified toolbar This is need from macOS 10.13 onwards. See NSWindow related notes on https://developer.apple.com/library/content/releasenotes/AppKit/RN-AppKit/ NB: that NSWindow change required runtime checking for 10.9 support. 20171011 : upstream head (5.9): e03b64c5b1eeebfbbb94d67eb9a9c1d35eaba0bb src/plugins/platforms/cocoa/qnsview.mm | 4 + patch: patches/23-sync-upstream-171011.diff Changes: git log e0c2d328b11ab893538393fad66ad61d22d823c6..e03b64c5b1eeebfbbb94d67eb9a9c1d35eaba0bb src/plugins/platforms/cocoa/qnsview.mm | cat commit cbbf843e96de3067e4cb7c0a7b4e59a6c27b10f7 macOS: Bail out early when handling shortcut event results in closing window NB: this protection has been added to the contextmenu handling block just above, too. 20170920 : upstream head (5.9): e0c2d328b11ab893538393fad66ad61d22d823c6 src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm | 12 +- src/plugins/platforms/cocoa/qcocoainputcontext.mm | 17 +- src/plugins/platforms/cocoa/qcocoamenubar.mm | 10 +- src/plugins/platforms/cocoa/qnsview.h | 2 + src/plugins/platforms/cocoa/qnsview.mm | 41 ++- patch: patches/22-sync-upstream-170920.diff Changes: git log e81f430e30635f975dd4635ffb64d66fc1bce355..HEAD src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm src/plugins/platforms/cocoa/qcocoainputcontext.mm src/plugins/platforms/cocoa/qcocoamenubar.mm src/plugins/platforms/cocoa/qnsview.h src/plugins/platforms/cocoa/qnsview.mm commit 689606de91faecf91f1f92e8d355789d9be62d2f Cocoa: Update the known menu items when the QCocoaMenuBar is deleted Task-number: QTBUG-62193 commit 202d3ba3e6c9982608f41f5e7d836825c8664c93 Cocoa: Check if charactersIgnoringModifiers is not empty too Task-number: QTBUG-57933 commit 0adc14d8dbdd9e28ccb72c49d865009dd8df1b1c macOS: Don‚Äôt color convert the backing store Task-number: QTBUG-61384 commit 52bda430af2749da1a0467b71d9cca5208f22402 macOS: Reset composition when focus object changes inside window Task-number: QTBUG-59222 commit 0270651dda8e247164a8dccd71fb65712c7d1480 Cocoa integration: do not use released session Task-number: QTBUG-62589 20170829 : upstream head (5.9): e81f430e30635f975dd4635ffb64d66fc1bce355 touched: src/plugins/platforms/cocoa/qcocoamenu.h | 4 + src/plugins/platforms/cocoa/qcocoamenu.mm | 26 +- src/plugins/platforms/cocoa/qcocoamenubar.mm | 2 +- src/plugins/platforms/cocoa/qcocoaprintersupport.h | 2 +- src/plugins/platforms/cocoa/qcocoaprintersupport.mm | 4 +- src/plugins/platforms/cocoa/qcocoawindow.mm | 14 +- src/plugins/platforms/cocoa/qnsview.h | 2 + src/plugins/platforms/cocoa/qnsview.mm | 4 + src/plugins/platforms/cocoa/qprintengine_mac.mm | 8 +- src/plugins/platforms/cocoa/qprintengine_mac_p.h | 2 +- patch: patches/21-sync-upstream-170828.diff Changes: git log 0a5f71c6062d575602ff041fb1b88ec2d8ad92bc..HEAD src/plugins/platforms/cocoa commit 48784486a36f60dea882baabc6923f4b59d2bfe6 QCocoaMenu: Stop update timer commit dbaa4de28e5cdfa1787af77d236586833786ee61 Cocoa: Fix compile when using QT_NO_TABLETEVENT commit 8ebfe00f4ab79516a8276929a682c24f4c675b5f Initialize the print engine with the given printer name QAltCocoa: only on Qt >= 5.9.0 Task-number: QTBUG-62221 commit 306071e50eac8290d234caab90985ddf705a5fc6 QCocoaMenu: Sync menubar menu when adding items Task-number: QTBUG-62260 commit f27d1ccbb24ec2fd4098f2976503478831006cc8 QCocoaMenu: De-pessimize the number of calls to validateMenuItem: Task-number: QTBUG-62396 >>> change enabled for Qt >= 5.9.2 commit c35fc435950437d3d046b17d06593873d7b82011 macOS: Make alpha-based click-trough work again Restore 5.6 behavior by not modifying ignoresMouseEvent if we can. Toggling WindowTransparentForInput on and off again is still broken. Task-number: QTBUG-54830 20180801: upstream head (5.9): 0a5f71c6062d575602ff041fb1b88ec2d8ad92bc touched: src/plugins/platforms/cocoa/cocoa.pro | 7 +- src/plugins/platforms/cocoa/qcocoafontdialoghelper.h | 3 + src/plugins/platforms/cocoa/qcocoafontdialoghelper.mm | 4 - src/plugins/platforms/cocoa/qcocoahelpers.h | 7 +- src/plugins/platforms/cocoa/qcocoahelpers.mm | 5 ++ src/plugins/platforms/cocoa/qcocoatheme.mm | 13 +-- src/plugins/platforms/cocoa/qnswindowdelegate.mm | 7 +- > patch: patches/20-sync-upstream-170801.diff Changes: Fix 32-bit build on macOS macOS: Don't assume the proposed fullscreen size matches the screen size Sometimes AppKit will pass in a proposed size that's smaller than the geometry of the screen. We don't know why, but shouldn't assert. Add missing #include for -no-widgets macOS: Fix unused variable in window:willUseFullScreenContentSize: Convert features.fontdialog to QT_[REQUIRE_]CONFIG Fix macOS build for -no-widgets, take 2 20170707: upstream head (5.9): 9d3cd2268ce3beafcf6fa886bb70d8463260d602 touched: src/plugins/platforms/cocoa/qcocoatheme.mm src/plugins/platforms/cocoa/qnswindowdelegate.mm > patch: patches/19.2-sync-upstream-170707.diff Changes: from git log 03b4838cb51513bd5d2edf76dccc4bc4a1181681..HEAD src/plugins/platforms/cocoa/{qcocoatheme.mm,qnswindowdelegate.mm} commit 9d3cd2268ce3beafcf6fa886bb70d8463260d602 Author: Tor Arne Vestb#c3#b8 Date: Thu Jul 6 17:03:41 2017 +0200 macOS: Account for fullscreen geometry bug in AppKit on OS X 10.10 commit 6a1046e17691c6e35c7384590ba241edb4082707 Author: Stephan Binner qq Date: Tue Jul 4 19:08:55 2017 +0200 Fix macOS build for -no-widgets 20170705: upstream head (5.9 branch): 03b4838cb51513bd5d2edf76dccc4bc4a1181681 touched: src/plugins/platforms/cocoa/cocoa.pro | 16 +++-- src/plugins/platforms/cocoa/qcocoacolordialoghelper.h | 4 ++ src/plugins/platforms/cocoa/qcocoacolordialoghelper.mm | 4 -- src/plugins/platforms/cocoa/qcocoafiledialoghelper.h | 3 + src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm | 4 -- src/plugins/platforms/cocoa/qcocoaintegration.mm | 8 ++- src/plugins/platforms/cocoa/qcocoamenubar.mm | 18 ++++- src/plugins/platforms/cocoa/qcocoatheme.mm | 14 ++-- src/plugins/platforms/cocoa/qnsview.mm | 33 +++++---- > patch: patches/19-sync-upstream-170705.diff Main changes from `cd src/plugins/platforms/cocoa && git log b2cb83ecbb1eec29268852d1b230f37e4c8592e9..HEAD cocoa.pro qcocoacolordialoghelper.h qcocoacolordialoghelper.mm qcocoafiledialoghelper.h qcocoafiledialoghelper.mm qcocoaintegration.mm qcocoamenubar.mm qcocoatheme.mm qnsview.mm ` commit 3e8ebea95b634c7ded9ee0b884768155e9e7f686 Author: Andy Shaw Date: Fri Jun 23 09:08:19 2017 +0200 Cocoa: Reset the target + action for a menuitem after showing a dialog To make it more reliable and efficient we now do the reverse of what we are doing when redirecting the items. This will ensure that the actions are correctly reset to the original target and action. The original approach of updateMenubarImmediately() was not always doing this and it also does other unnecessary things as a result when all we need is to just reset the things we changed. commit 198b67d14bf3ca76d6bdf8901348da0838cf3b8d Author: Tor Arne Vestb#c3#b8 Date: Mon Jun 12 17:58:41 2017 +0200 macOS: Send text input and key events to focus object of window, not app The key events and input method callbacks coming from Cocoa are targeted at our specific NSView, so we should deliver them to the focus object of the corresponding QWindow, not the global application focus object. This means that we'll deliver key events to windows also when they are not key (active), but this is intentional, as we would otherwise fail to deliver input method events coming from e.g. the emoji/symbol picker, which steals the key window when active. Task-number: QTBUG-61359 commit 3851a8ff20c6aed0807bfdc4588ae108a2b108ec Author: Tor Arne Vestb#c3#b8 Date: Fri Jun 23 13:32:25 2017 +0200 macOS: Work around buildup of NSDisplayCycle objects during rapid painting Task-number: QTBUG-60012 commit e6ccc8e56fdaf402602130176064ffb1a0ce29bf Author: R.J.V. Bertin Date: Wed Jun 21 18:16:04 2017 +0200 sync with upstream Cocoa QPA changes in the 5.9 branch (qtbase v5.9.0-208-gb2cb83e) commit 12e9ff4bed9513fe8ed390a1f421d8f73c45960a Author: R.J.V. Bertin Date: Mon Jun 5 17:40:51 2017 +0200 sync with upstream Cocoa QPA changes in the 5.9 branch (qtbase v5.9.0-119-g934235e) commit 0ecceaf6d7871b fc42141909af210f6bb408ac61 Author: R.J.V. Bertin Date: Thu Apr 20 20:50:58 2017 +0200 15-patch-restore-legacy-fullscreen-mode.diff alternative fullscreen mode: simplified and restore window icons commit d4ce302e7c08dcf38a0f0f40b7e9183cab2fc2b1 Author: R.J.V. Bertin Date: Wed Apr 19 23:58:24 2017 +0200 AltCocoa QPA: add a legacy fullscreen mode When windows don't have the fullscreen titlebar button or the env. var. QT_LEGACY_FULLSCREEN is set, toggleFullScreen() adopts a legacy mode. Windows are then made fullscreen by converting them to frame-less and resizing them to the current screen size. This is faster (instantaneous) and preserves display content on other screens in multi-head set-ups. commit 85bb84969c6922667ff83e1483a7ef71628c046e Author: R.J.V. Bertin Date: Tue Apr 11 20:16:12 2017 +0200 qmacstyle : really build against Qt 5.8.0 commit 934afde2c352b401cfffed83cb0877462dc27787 Author: R.J.V. Bertin Date: Mon Apr 10 23:56:13 2017 +0200 modified (Alt) 5.9.0 commit c8dd86fd23c6787f949c2849ccb20eaf22e118ae Author: R.J.V. Bertin Date: Mon Apr 10 23:45:31 2017 +0200 13-themehint-add-aqua.diff commit cbf229875c49c2a57d7b62b641d866134e569a1a Author: R.J.V. Bertin Date: Thu Apr 6 21:57:00 2017 +0200 12-deactivate-menurole-heuristics.patch this patch deactivates the worst of the TextHeuristic menu role guessmatics that can lead to putting the wrong QAction under the Mac's About or Preferences menu items in the Application menu. Many KDE applications have more than 1 About and Configure menu actions and are thus especially at risk. KDE applications that use KStandardActions to create the standard menu items will see the appropriate actions assigned to the About and Preferences menu items because their roles are set explicitly. commit af7c4544d1883e9978609742b48dbb152e880c34 Author: R.J.V. Bertin Date: Thu Apr 6 21:50:46 2017 +0200 11-patch-keyboard-support-menukey.diff this patch introduces support for a Menu key. Macs don't normally have one but the SDKs do provide a special keysym (NSMenuFunctionKey) which might be used (generated) by 3rd party keyboard drivers or even a native event filter. The patch completes the pre-existing support and generates a ContextMenu event at an appropriate location when the keysym is received. commit c45430fc3c1827b44dd9002932b7b582da19729e Author: R.J.V. Bertin Date: Thu Apr 6 19:22:14 2017 +0200 10-patch-keyboard-mapping.diff From 3ee093b47109e2b24ab77ccdecde84437c5aced9 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Wed, 2 Nov 2016 14:19:26 +0100 Subject: [PATCH] WIP - Cocoa integration: fix incorrect keyboard mapping When switching between different input sources, we have to update layouts. Task-number: QTBUG-50865 Change-Id: I19ee45feabf014e61dfef7454b5468e596ce2786 Committed from host : Portia.local commit 65de5666d5574a08a2fe49b82f29fd0b8a6b3cbf Author: R.J.V. Bertin Date: Thu Apr 6 19:21:36 2017 +0200 09-patch-silence-setscreen-warning.diff Prevent an unnecessary warning commit 07527d713953a417b93393558cfb44475bc42d23 Author: R.J.V. Bertin Date: Thu Apr 6 19:20:56 2017 +0200 08-patch-freetype-gamma-cocoa.diff Adapt the font smoothing gamma when using the FreeType rendering engine. commit a7b0481d07c592c1a1810160e317d6792eeb7a5d Author: R.J.V. Bertin Date: Thu Apr 6 19:19:32 2017 +0200 06-patch-respect-DontSwapCtrlMeta.diff From ce953f011356257c1e1862d0353f785453559028 Mon Sep 17 00:00:00 2001 From: Dyami Caliri Date: Tue, 16 Sep 2014 17:32:22 -0700 Subject: [PATCH] OS X: Handle Qt::AA_MacDontSwapCtrlAndMeta for regular key events The flag Qt::AA_MacDontSwapCtrlAndMeta was only being used with shortcut detection. Now trying to incorporate flag in normal key events. Task-number: QTBUG-22775 Change-Id: I9edf97d0de93aa225435c9802372e33641cdac73 Committed from host : Portia.local commit 5ffc2fff1bd729ec9e54120e424fdfd51197f438 Author: R.J.V. Bertin Date: Thu Apr 6 19:18:46 2017 +0200 05-patch-improve-fontweight-support9.diff part of a more comprehensive patch improving support for less-common font weights. I'm not sure how much effect it has on its own but it should not have adverse effects when used without the companion modifications. commit 658f1d0e2fe5a9a678bdae712cc5a47878bc59de Author: R.J.V. Bertin Date: Thu Apr 6 19:16:29 2017 +0200 04-patch-qmenuAddSection.diff add support for named menu sections ("texted separators") in menus that are part of the native menubar. This requires the companion patch to the "native" Macintosh theme otherwise named sections won't appear when they are the 1st item in a menu. commit 42f58e14282bf4beae408f5440397dd5a6b30471 Author: R.J.V. Bertin Date: Thu Apr 6 19:14:00 2017 +0200 03-patch-better-menuitem-insert-warning.diff Provide a more helpful warning when adding an item to an additional menu or removing it from the wrong menu. commit f5bbcfc20e52dfcfa27eedb4a1240e2fccf5fb93 Author: R.J.V. Bertin Date: Thu Apr 6 19:12:01 2017 +0200 02-patch-enable-kde-theme.diff advertise the existence of support for the KDE platform theme plugin when KDE_SESSION_VERSION is set to at least 4 in the environment. commit f3707f1516f1393235c178d5829cf3f88d5844e1 Author: R.J.V. Bertin Date: Thu Apr 6 19:03:23 2017 +0200 01-patch-missing-autoreleasepools.diff Add autorelease pools to functions that (used to) need them. This is safe and comes at almost no cost. diff --git a/src/qcocoa-qpa/patches/27-patch-freetype-improvements.diff b/src/qcocoa-qpa/patches/27-patch-freetype-improvements.diff index f936b61..6f77642 100644 --- a/src/qcocoa-qpa/patches/27-patch-freetype-improvements.diff +++ b/src/qcocoa-qpa/patches/27-patch-freetype-improvements.diff @@ -1,104 +1,104 @@ diff --git a/cocoa/qcocoaintegration.h b/cocoa/qcocoaintegration.h index f41f023..11a1038 100644 --- a/cocoa/qcocoaintegration.h +++ b/cocoa/qcocoaintegration.h @@ -169,6 +169,8 @@ public: void beep() const Q_DECL_OVERRIDE; + bool freeTypeFontEngine(bool enabled); + bool mCanReplaceFontDatabase; private: static QCocoaIntegration *mInstance; Options mOptions; diff --git a/cocoa/qcocoaintegration.mm b/cocoa/qcocoaintegration.mm index 80d1722..ecf54b4 100644 --- a/cocoa/qcocoaintegration.mm +++ b/cocoa/qcocoaintegration.mm @@ -322,11 +322,17 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) , 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")) { ++ if (qgetenv("QT_MAC_FONTENGINE").toLower() == "freetype") { + mOptions |= QCocoaIntegration::UseFreeTypeFontEngine; + } +#endif #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) #ifndef QT_NO_FREETYPE if (mOptions.testFlag(UseFreeTypeFontEngine)) @@ -572,6 +578,7 @@ QAbstractEventDispatcher *QCocoaIntegration::createEventDispatcher() const QCoreTextFontDatabase *QCocoaIntegration::fontDatabase() const { + QCocoaIntegration::instance()->mCanReplaceFontDatabase = false; return mFontDb.data(); } @@ -715,4 +722,32 @@ void QCocoaIntegration::beep() const NSBeep(); } +bool QCocoaIntegration::freeTypeFontEngine(bool enabled) +{ + if (!mCanReplaceFontDatabase) { + return false; + } +#ifndef QT_NO_FREETYPE + auto options = mOptions; + if (enabled) { + options |= QCocoaIntegration::UseFreeTypeFontEngine; + } else { + options &= ~QCocoaIntegration::UseFreeTypeFontEngine; + } + 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 + return false; +} + QT_END_NAMESPACE diff --git a/cocoa/qcocoanativeinterface.mm b/cocoa/qcocoanativeinterface.mm index bbe91bf..612b9e4 100644 --- a/cocoa/qcocoanativeinterface.mm +++ b/cocoa/qcocoanativeinterface.mm @@ -73,6 +73,12 @@ QT_BEGIN_NAMESPACE +static bool qt_mac_use_freetype(bool enabled) +{ + return QCocoaIntegration::instance()->freeTypeFontEngine(enabled); +} + + QCocoaNativeInterface::QCocoaNativeInterface() { } @@ -143,6 +149,10 @@ QPlatformNativeInterface::NativeResourceForIntegrationFunction QCocoaNativeInter if (resource.toLower() == "testcontentborderposition") return NativeResourceForIntegrationFunction(QCocoaNativeInterface::testContentBorderPosition); + if (resource.toLower() == "qt_mac_use_freetype") { + return NativeResourceForIntegrationFunction(qt_mac_use_freetype); + } + return 0; } diff --git a/src/qcocoa-qpa/patches/28-patch-use-fontconfig.diff b/src/qcocoa-qpa/patches/28-patch-use-fontconfig.diff index 0efc4d7..d064d75 100644 --- a/src/qcocoa-qpa/patches/28-patch-use-fontconfig.diff +++ b/src/qcocoa-qpa/patches/28-patch-use-fontconfig.diff @@ -1,278 +1,278 @@ diff --git a/cocoa/qcocoaintegration.h b/cocoa/qcocoaintegration.h index 11a1038..87d240c 100644 --- a/cocoa/qcocoaintegration.h +++ b/cocoa/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/cocoa/qcocoaintegration.mm b/cocoa/qcocoaintegration.mm index ecf54b4..65dc3df 100644 --- a/cocoa/qcocoaintegration.mm +++ b/cocoa/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,51 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) - if (qt_mac_resolveOption(false, "QT_MAC_USE_FREETYPE")) { + if (qgetenv("QT_MAC_FONTENGINE").toLower() == "freetype") { mOptions |= QCocoaIntegration::UseFreeTypeFontEngine; } +# if QT_CONFIG(fontconfig) -+ if (qt_mac_resolveOption(false, "QT_MAC_USE_FONTCONFIG")) { ++ if (qgetenv("QT_MAC_FONTENGINE").toLower() == "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 +#ifdef HAVE_INFINALITY + m_fontSmoothingGamma = mOptions.testFlag(UseFontConfigDatabase) ? 0.9 : 1.5; +#else + m_fontSmoothingGamma = 1.5; #endif - mFontDb.reset(new QCoreTextFontDatabaseEngineFactory); #else - mFontDb.reset(new QCoreTextFontDatabase(mOptions.testFlag(UseFreeTypeFontEngine))); + m_fontSmoothingGamma = 0.975 #endif + 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))); +#endif + } else { +#if QT_CONFIG(fontconfig) + mFontDb.reset(new QFontconfigDatabase); +#endif + } QString icStr = QPlatformInputContextFactory::requested(); icStr.isNull() ? mInputContext.reset(new QCocoaInputContext) @@ -576,7 +617,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 +677,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 +764,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 +777,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 +792,49 @@ 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 QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) + // unfortunately we may need to reset m_fontSmoothingGamma on 5.9 and up + // depending on whether we're configured for use with the Infinality patch set. + if (!qEnvironmentVariableIsSet("QT_MAC_FREETYPE_FONT_GAMMA")) { +#ifdef HAVE_INFINALITY + m_fontSmoothingGamma = enabled ? 0.9 : 1.5; +#else + m_fontSmoothingGamma = 1.5; +#endif + } #endif + 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/cocoa/qcocoanativeinterface.mm b/cocoa/qcocoanativeinterface.mm index 612b9e4..3191b38 100644 --- a/cocoa/qcocoanativeinterface.mm +++ b/cocoa/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/cocoa/qcocoatheme.mm b/cocoa/qcocoatheme.mm index 4212801..ec48be2 100644 --- a/cocoa/qcocoatheme.mm +++ b/cocoa/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.mm b/src/qcocoa-qpa/qcocoaintegration.mm index 65dc3df..0a77cdb 100644 --- a/src/qcocoa-qpa/qcocoaintegration.mm +++ b/src/qcocoa-qpa/qcocoaintegration.mm @@ -1,840 +1,840 @@ /**************************************************************************** ** ** 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")) { + if (qgetenv("QT_MAC_FONTENGINE").toLower() == "freetype") { mOptions |= QCocoaIntegration::UseFreeTypeFontEngine; } # if QT_CONFIG(fontconfig) - if (qt_mac_resolveOption(false, "QT_MAC_USE_FONTCONFIG")) { + if (qgetenv("QT_MAC_FONTENGINE").toLower() == "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) #ifdef HAVE_INFINALITY m_fontSmoothingGamma = mOptions.testFlag(UseFontConfigDatabase) ? 0.9 : 1.5; #else m_fontSmoothingGamma = 1.5; #endif #else m_fontSmoothingGamma = 0.975 #endif 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))); #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 (hint == QPlatformIntegration::FontSmoothingGamma) #ifdef QT_MAC_USE_FONTCONFIG return m_fontSmoothingGamma; #else 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) { 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; } return false; #endif } bool QCocoaIntegration::fontConfigFontEngine(bool enabled) { #if QT_CONFIG(fontconfig) if (!mCanReplaceFontDatabase) { return false; } auto options = mOptions; bool ret = false; #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) // unfortunately we may need to reset m_fontSmoothingGamma on 5.9 and up // depending on whether we're configured for use with the Infinality patch set. if (!qEnvironmentVariableIsSet("QT_MAC_FREETYPE_FONT_GAMMA")) { #ifdef HAVE_INFINALITY m_fontSmoothingGamma = enabled ? 0.9 : 1.5; #else m_fontSmoothingGamma = 1.5; #endif } #endif 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