Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qcocoatheme.mm
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include <AppKit/AppKit.h>
6
7#include "qcocoatheme.h"
8
9#include <QtCore/QVariant>
10
12#include "qcocoamenuitem.h"
13#include "qcocoamenu.h"
14#include "qcocoamenubar.h"
15#include "qcocoahelpers.h"
17
18#include <QtCore/qfileinfo.h>
19#include <QtCore/qstandardpaths.h>
20#include <QtCore/private/qcore_mac_p.h>
21#include <QtGui/private/qfont_p.h>
22#include <QtGui/private/qguiapplication_p.h>
23#include <QtGui/private/qcoregraphics_p.h>
24#include <QtGui/qpainter.h>
25#include <QtGui/qtextformat.h>
26#include <QtGui/private/qcoretextfontdatabase_p.h>
27#include <QtGui/private/qapplefileiconengine_p.h>
28#include <QtGui/private/qappleiconengine_p.h>
29#include <QtGui/private/qfontengine_coretext_p.h>
30#include <QtGui/private/qabstractfileiconengine_p.h>
31#include <qpa/qplatformdialoghelper.h>
32#include <qpa/qplatformintegration.h>
33#include <qpa/qplatformnativeinterface.h>
34
39
40#include <CoreServices/CoreServices.h>
41#include <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
42
44
46{
47 QColor qc;
48
49 // Standard palette initialization (copied from Qt 4 styles)
50 QBrush backgroundBrush = qt_mac_toQBrush([NSColor windowBackgroundColor]);
51 QColor background = backgroundBrush.color();
52 QColor light(background.lighter(110));
53 QColor dark(background.darker(160));
54 QColor mid(background.darker(140));
55 QPalette *palette = new QPalette(Qt::black, background, light, dark, mid, Qt::black, Qt::white);
56
57 palette->setBrush(QPalette::Window, backgroundBrush);
58
59 palette->setBrush(QPalette::Disabled, QPalette::WindowText, dark);
60 palette->setBrush(QPalette::Disabled, QPalette::Text, dark);
61 palette->setBrush(QPalette::Disabled, QPalette::Base, backgroundBrush);
62 QBrush textBackgroundBrush = qt_mac_toQBrush([NSColor textBackgroundColor]);
63 palette->setBrush(QPalette::Active, QPalette::Base, textBackgroundBrush);
64 palette->setBrush(QPalette::Inactive, QPalette::Base, textBackgroundBrush);
65 palette->setColor(QPalette::Disabled, QPalette::Dark, QColor(191, 191, 191));
66 palette->setColor(QPalette::Active, QPalette::Dark, QColor(191, 191, 191));
67 palette->setColor(QPalette::Inactive, QPalette::Dark, QColor(191, 191, 191));
68
69 // System palette initialization:
70 QBrush br = qt_mac_toQBrush([NSColor selectedControlColor]);
71 palette->setBrush(QPalette::Active, QPalette::Highlight, br);
72 const auto inactiveHighlight = qt_mac_toQBrush([NSColor unemphasizedSelectedContentBackgroundColor]);
73 palette->setBrush(QPalette::Inactive, QPalette::Highlight, inactiveHighlight);
74 palette->setBrush(QPalette::Disabled, QPalette::Highlight, inactiveHighlight);
75
76 palette->setBrush(QPalette::Shadow, qt_mac_toQColor([NSColor shadowColor]));
77
78 qc = qt_mac_toQColor([NSColor controlTextColor]);
79 palette->setColor(QPalette::Active, QPalette::Text, qc);
80 palette->setColor(QPalette::Active, QPalette::ButtonText, qc);
81 palette->setColor(QPalette::Active, QPalette::WindowText, qc);
82 palette->setColor(QPalette::Active, QPalette::HighlightedText, qc);
83 palette->setColor(QPalette::Inactive, QPalette::Text, qc);
84 palette->setColor(QPalette::Inactive, QPalette::WindowText, qc);
85 palette->setColor(QPalette::Inactive, QPalette::HighlightedText, qc);
86
87 qc = qt_mac_toQColor([NSColor disabledControlTextColor]);
88 palette->setColor(QPalette::Disabled, QPalette::Text, qc);
89 palette->setColor(QPalette::Disabled, QPalette::ButtonText, qc);
90 palette->setColor(QPalette::Disabled, QPalette::WindowText, qc);
91 palette->setColor(QPalette::Disabled, QPalette::HighlightedText, qc);
92
93 palette->setBrush(QPalette::ToolTipBase, qt_mac_toQBrush([NSColor controlColor]));
94
95 palette->setColor(QPalette::Normal, QPalette::Link, qt_mac_toQColor([NSColor linkColor]));
96
97 qc = qt_mac_toQColor([NSColor placeholderTextColor]);
98 palette->setColor(QPalette::Active, QPalette::PlaceholderText, qc);
99 palette->setColor(QPalette::Inactive, QPalette::PlaceholderText, qc);
100 palette->setColor(QPalette::Disabled, QPalette::PlaceholderText, qc);
101
102 qc = qt_mac_toQColor([NSColor controlAccentColor]);
103 palette->setColor(QPalette::Accent, qc);
104
105 return palette;
106}
107
109 inline QMacPaletteMap(QPlatformTheme::Palette p, NSColor *a, NSColor *i) :
110 active(a), inactive(i), paletteRole(p) { }
111
115};
116
117#define MAC_PALETTE_ENTRY(pal, active, inactive)
118 QMacPaletteMap(pal, [NSColor active], [NSColor inactive])
120 MAC_PALETTE_ENTRY(QPlatformTheme::ToolButtonPalette, controlTextColor, disabledControlTextColor),
121 MAC_PALETTE_ENTRY(QPlatformTheme::ButtonPalette, controlTextColor, disabledControlTextColor),
122 MAC_PALETTE_ENTRY(QPlatformTheme::HeaderPalette, headerTextColor, disabledControlTextColor),
123 MAC_PALETTE_ENTRY(QPlatformTheme::ComboBoxPalette, controlTextColor, disabledControlTextColor),
124 MAC_PALETTE_ENTRY(QPlatformTheme::ItemViewPalette, textColor, disabledControlTextColor),
125 MAC_PALETTE_ENTRY(QPlatformTheme::MessageBoxLabelPalette, textColor, disabledControlTextColor),
126 MAC_PALETTE_ENTRY(QPlatformTheme::TabBarPalette, controlTextColor, disabledControlTextColor),
127 MAC_PALETTE_ENTRY(QPlatformTheme::LabelPalette, textColor, disabledControlTextColor),
128 MAC_PALETTE_ENTRY(QPlatformTheme::GroupBoxPalette, textColor, disabledControlTextColor),
129 MAC_PALETTE_ENTRY(QPlatformTheme::MenuPalette, controlTextColor, disabledControlTextColor),
130 MAC_PALETTE_ENTRY(QPlatformTheme::MenuBarPalette, controlTextColor, disabledControlTextColor),
131 MAC_PALETTE_ENTRY(QPlatformTheme::TextEditPalette, textColor, disabledControlTextColor),
132 MAC_PALETTE_ENTRY(QPlatformTheme::TextLineEditPalette, textColor, disabledControlTextColor)
133};
134#undef MAC_PALETTE_ENTRY
135
136static const int mac_widget_colors_count = sizeof(mac_widget_colors) / sizeof(mac_widget_colors[0]);
137
138static QHash<QPlatformTheme::Palette, QPalette*> qt_mac_createRolePalettes()
139{
140 QHash<QPlatformTheme::Palette, QPalette*> palettes;
141 QColor qc;
142 for (int i = 0; i < mac_widget_colors_count; i++) {
143 QPalette &pal = *qt_mac_createSystemPalette();
144 if (mac_widget_colors[i].active) {
145 qc = qt_mac_toQColor(mac_widget_colors[i].active);
146 pal.setColor(QPalette::Active, QPalette::Text, qc);
147 pal.setColor(QPalette::Inactive, QPalette::Text, qc);
148 pal.setColor(QPalette::Active, QPalette::WindowText, qc);
149 pal.setColor(QPalette::Inactive, QPalette::WindowText, qc);
150 pal.setColor(QPalette::Active, QPalette::HighlightedText, qc);
151 pal.setColor(QPalette::Inactive, QPalette::HighlightedText, qc);
152 pal.setColor(QPalette::Active, QPalette::ButtonText, qc);
153 pal.setColor(QPalette::Inactive, QPalette::ButtonText, qc);
154 qc = qt_mac_toQColor(mac_widget_colors[i].inactive);
155 pal.setColor(QPalette::Disabled, QPalette::Text, qc);
156 pal.setColor(QPalette::Disabled, QPalette::WindowText, qc);
157 pal.setColor(QPalette::Disabled, QPalette::HighlightedText, qc);
158 pal.setColor(QPalette::Disabled, QPalette::ButtonText, qc);
159 }
160 if (mac_widget_colors[i].paletteRole == QPlatformTheme::MenuPalette
161 || mac_widget_colors[i].paletteRole == QPlatformTheme::MenuBarPalette) {
162 // Cheap approximation for NSVisualEffectView (see deprecation note for selectedMenuItemTextColor)
163 auto selectedMenuItemColor = [[NSColor controlAccentColor] highlightWithLevel:0.3];
164 pal.setBrush(QPalette::Highlight, qt_mac_toQColor(selectedMenuItemColor));
165 qc = qt_mac_toQColor([NSColor labelColor]);
166 pal.setBrush(QPalette::ButtonText, qc);
167 pal.setBrush(QPalette::Text, qc);
168 qc = qt_mac_toQColor([NSColor selectedMenuItemTextColor]);
169 pal.setBrush(QPalette::HighlightedText, qc);
170 qc = qt_mac_toQColor([NSColor disabledControlTextColor]);
171 pal.setBrush(QPalette::Disabled, QPalette::Text, qc);
172 } else if ((mac_widget_colors[i].paletteRole == QPlatformTheme::ButtonPalette)
173 || (mac_widget_colors[i].paletteRole == QPlatformTheme::HeaderPalette)
174 || (mac_widget_colors[i].paletteRole == QPlatformTheme::TabBarPalette)) {
175 pal.setColor(QPalette::Disabled, QPalette::ButtonText,
176 pal.color(QPalette::Disabled, QPalette::Text));
177 pal.setColor(QPalette::Inactive, QPalette::ButtonText,
178 pal.color(QPalette::Inactive, QPalette::Text));
179 pal.setColor(QPalette::Active, QPalette::ButtonText,
180 pal.color(QPalette::Active, QPalette::Text));
181 } else if (mac_widget_colors[i].paletteRole == QPlatformTheme::ItemViewPalette) {
182 NSArray<NSColor *> *baseColors = nil;
183 NSColor *activeHighlightColor = nil;
184 baseColors = [NSColor alternatingContentBackgroundColors];
185 activeHighlightColor = [NSColor selectedContentBackgroundColor];
186 pal.setBrush(QPalette::Inactive, QPalette::HighlightedText,
187 qt_mac_toQBrush([NSColor unemphasizedSelectedTextColor]));
188 pal.setBrush(QPalette::Base, qt_mac_toQBrush(baseColors[0]));
189 pal.setBrush(QPalette::AlternateBase, qt_mac_toQBrush(baseColors[1]));
190 pal.setBrush(QPalette::Active, QPalette::Highlight,
191 qt_mac_toQBrush(activeHighlightColor));
192 pal.setBrush(QPalette::Active, QPalette::HighlightedText,
193 qt_mac_toQBrush([NSColor alternateSelectedControlTextColor]));
194 pal.setBrush(QPalette::Inactive, QPalette::Text,
195 pal.brush(QPalette::Active, QPalette::Text));
196 } else if (mac_widget_colors[i].paletteRole == QPlatformTheme::TextEditPalette) {
197 pal.setBrush(QPalette::Active, QPalette::Base, qt_mac_toQColor([NSColor textBackgroundColor]));
198 pal.setBrush(QPalette::Inactive, QPalette::Text,
199 pal.brush(QPalette::Active, QPalette::Text));
200 pal.setBrush(QPalette::Inactive, QPalette::HighlightedText,
201 pal.brush(QPalette::Active, QPalette::Text));
202 } else if (mac_widget_colors[i].paletteRole == QPlatformTheme::TextLineEditPalette
203 || mac_widget_colors[i].paletteRole == QPlatformTheme::ComboBoxPalette) {
204 pal.setBrush(QPalette::Active, QPalette::Base, qt_mac_toQColor([NSColor textBackgroundColor]));
205 pal.setBrush(QPalette::Disabled, QPalette::Base,
206 pal.brush(QPalette::Active, QPalette::Base));
207 } else if (mac_widget_colors[i].paletteRole == QPlatformTheme::LabelPalette) {
208 qc = qt_mac_toQColor([NSColor labelColor]);
209 pal.setBrush(QPalette::Inactive, QPalette::ToolTipText, qc);
210 }
211 palettes.insert(mac_widget_colors[i].paletteRole, &pal);
212 }
213 return palettes;
214}
215
216const char *QCocoaTheme::name = "cocoa";
217
218QCocoaTheme::QCocoaTheme()
219 : m_systemPalette(nullptr)
220{
221 m_appearanceObserver = QMacKeyValueObserver(NSApp, @"effectiveAppearance", [this] {
222 handleSystemThemeChange();
223 });
224
225 m_systemColorObserver = QMacNotificationObserver(nil,
226 NSSystemColorsDidChangeNotification, [this] {
227 handleSystemThemeChange();
228 });
229
230 updateColorScheme();
231}
232
233QCocoaTheme::~QCocoaTheme()
234{
235 reset();
236}
237
238void QCocoaTheme::reset()
239{
240 delete m_systemPalette;
241 m_systemPalette = nullptr;
242 qDeleteAll(m_palettes);
243 m_palettes.clear();
244}
245
246void QCocoaTheme::handleSystemThemeChange()
247{
248 QMacAutoReleasePool pool;
249
250 reset();
251
252 updateColorScheme();
253
254 if (QCoreTextFontEngine::fontSmoothing() == QCoreTextFontEngine::FontSmoothing::Grayscale) {
255 // Re-populate glyph caches based on the new appearance's assumed text fill color
256 QFontCache::instance()->clear();
257 }
258
259 QWindowSystemInterface::handleThemeChange<QWindowSystemInterface::SynchronousDelivery>();
260}
261
262bool QCocoaTheme::usePlatformNativeDialog(DialogType dialogType) const
263{
264 switch (dialogType) {
265 case QPlatformTheme::FileDialog:
266 case QPlatformTheme::ColorDialog:
267 case QPlatformTheme::FontDialog:
268 case QPlatformTheme::MessageDialog:
269 return true;
270 default:
271 return false;
272 }
273}
274
275QPlatformDialogHelper *QCocoaTheme::createPlatformDialogHelper(DialogType dialogType) const
276{
277 switch (dialogType) {
278 case QPlatformTheme::FileDialog:
279 return new QCocoaFileDialogHelper();
280 case QPlatformTheme::ColorDialog:
281 return new QCocoaColorDialogHelper();
282 case QPlatformTheme::FontDialog:
283 return new QCocoaFontDialogHelper();
284 case QPlatformTheme::MessageDialog:
285 return new QCocoaMessageDialog;
286 default:
287 return nullptr;
288 }
289}
290
291#ifndef QT_NO_SYSTEMTRAYICON
292QPlatformSystemTrayIcon *QCocoaTheme::createPlatformSystemTrayIcon() const
293{
294 return new QCocoaSystemTrayIcon;
295}
296#endif
297
298const QPalette *QCocoaTheme::palette(Palette type) const
299{
300 QMacAutoReleasePool pool;
301
302 // Note: NSColor resolves its RGB values based on the current
303 // drawing appearance, so we need to propagate the effective
304 // appearance when (re)creating the palettes.
305
306 if (type == SystemPalette) {
307 if (!m_systemPalette) {
308 [NSApp.effectiveAppearance performAsCurrentDrawingAppearance:^{
309 m_systemPalette = qt_mac_createSystemPalette();
310 }];
311 }
312 return m_systemPalette;
313 } else {
314 if (m_palettes.isEmpty()) {
315 [NSApp.effectiveAppearance performAsCurrentDrawingAppearance:^{
316 m_palettes = qt_mac_createRolePalettes();
317 }];
318 }
319 return m_palettes.value(type, nullptr);
320 }
321 return nullptr;
322}
323
324const QFont *QCocoaTheme::font(Font type) const
325{
326 const auto *platformIntegration = QGuiApplicationPrivate::platformIntegration();
327 const auto *coreTextFontDatabase = static_cast<QCoreTextFontDatabase *>(platformIntegration->fontDatabase());
328 return coreTextFontDatabase->themeFont(type);
329}
330
331//! \internal
332QPixmap qt_mac_convert_iconref(const IconRef icon, int width, int height)
333{
334 QPixmap ret(width, height);
335 ret.fill(QColor(0, 0, 0, 0));
336
337 CGRect rect = CGRectMake(0, 0, width, height);
338
339 QMacCGContext ctx(&ret);
340 CGAffineTransform old_xform = CGContextGetCTM(ctx);
341 CGContextConcatCTM(ctx, CGAffineTransformInvert(old_xform));
342 CGContextConcatCTM(ctx, CGAffineTransformIdentity);
343
344 ::RGBColor b;
345 b.blue = b.green = b.red = 255*255;
346 PlotIconRefInContext(ctx, &rect, kAlignNone, kTransformNone, &b, kPlotIconRefNormalFlags, icon);
347 return ret;
348}
349
350QPixmap QCocoaTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const
351{
352 OSType iconType = 0;
353 switch (sp) {
354 case MessageBoxQuestion:
355 iconType = kQuestionMarkIcon;
356 break;
357 case MessageBoxInformation:
358 iconType = kAlertNoteIcon;
359 break;
360 case MessageBoxWarning:
361 iconType = kAlertCautionIcon;
362 break;
363 case MessageBoxCritical:
364 iconType = kAlertStopIcon;
365 break;
366 case DesktopIcon: {
367 auto desktop = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
368 NSImage *icon = [NSWorkspace.sharedWorkspace iconForFile:desktop.toNSString()];
369 return qt_mac_toQPixmap(icon, size);
370 }
371 case DirHomeIcon: {
372 auto home = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
373 NSImage *icon = [NSWorkspace.sharedWorkspace iconForFile:home.toNSString()];
374 return qt_mac_toQPixmap(icon, size);
375 }
376 case TrashIcon:
377 iconType = kTrashIcon;
378 break;
379 case ComputerIcon:
380 iconType = kComputerIcon;
381 break;
382 case DriveFDIcon:
383 iconType = kGenericFloppyIcon;
384 break;
385 case DriveHDIcon:
386 iconType = kGenericHardDiskIcon;
387 break;
388 case DriveCDIcon:
389 case DriveDVDIcon:
390 iconType = kGenericCDROMIcon;
391 break;
392 case DriveNetIcon:
393 iconType = kGenericNetworkIcon;
394 break;
395 case DirOpenIcon:
396 case DirLinkOpenIcon:
397 case DirIcon:
398 case DirClosedIcon:
399 case DirLinkIcon: {
400 NSImage *icon = [NSWorkspace.sharedWorkspace iconForContentType:UTTypeFolder];
401 return qt_mac_toQPixmap(icon, size);
402 }
403 case FileLinkIcon:
404 case FileIcon:
405 iconType = kGenericDocumentIcon;
406 break;
407 default:
408 break;
409 }
410 if (iconType != 0) {
411 QPixmap pixmap;
412 IconRef icon = nullptr;
413 QT_IGNORE_DEPRECATIONS(GetIconRef(kOnSystemDisk, kSystemIconsCreator, iconType, &icon));
414
415 if (icon) {
416 pixmap = qt_mac_convert_iconref(icon, size.width(), size.height());
417 QT_IGNORE_DEPRECATIONS(ReleaseIconRef(icon));
418 }
419
420 return pixmap;
421 }
422
423 return QPlatformTheme::standardPixmap(sp, size);
424}
425
426QIcon QCocoaTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions) const
427{
428 QMacAutoReleasePool pool;
429 return QIcon(new QAppleFileIconEngine(fileInfo, iconOptions));
430}
431
432QIconEngine *QCocoaTheme::createIconEngine(const QString &iconName) const
433{
434 return new QAppleIconEngine(iconName);
435}
436
437QVariant QCocoaTheme::themeHint(ThemeHint hint) const
438{
439 switch (hint) {
440 case QPlatformTheme::StyleNames:
441 return QStringList(QStringLiteral("macOS"));
442 case QPlatformTheme::DialogButtonBoxLayout:
443 return QVariant(QPlatformDialogHelper::MacLayout);
444 case KeyboardScheme:
445 return QVariant(int(MacKeyboardScheme));
446 case TabFocusBehavior:
447 return QVariant([[NSApplication sharedApplication] isFullKeyboardAccessEnabled] ?
448 int(Qt::TabFocusAllControls) : int(Qt::TabFocusTextControls | Qt::TabFocusListControls));
449 case IconPixmapSizes:
450 return QVariant::fromValue(QAppleIconEngine::availableIconSizes());
451 case QPlatformTheme::PasswordMaskCharacter:
452 return QVariant(QChar(0x2022));
453 case QPlatformTheme::UiEffects:
454 return QVariant(int(HoverEffect));
455 case QPlatformTheme::SpellCheckUnderlineStyle:
456 return QVariant(int(QTextCharFormat::DotLine));
457 case QPlatformTheme::UseFullScreenForPopupMenu:
458 return false;
459 case QPlatformTheme::InteractiveResizeAcrossScreens:
460 return !NSScreen.screensHaveSeparateSpaces;
461 case QPlatformTheme::ShowDirectoriesFirst:
462 return false;
463 case QPlatformTheme::MouseDoubleClickInterval:
464 return NSEvent.doubleClickInterval * 1000;
465 case QPlatformTheme::KeyboardInputInterval:
466 return NSEvent.keyRepeatDelay * 1000;
467 case QPlatformTheme::KeyboardAutoRepeatRate:
468 return 1.0 / NSEvent.keyRepeatInterval;
469 case QPlatformTheme::MousePressAndHoldInterval: {
470 static const int pressAndHoldInterval = [] {
471 auto *recognizer = [[NSPressGestureRecognizer new] autorelease];
472 recognizer.buttonMask = 0;
473 recognizer.allowedTouchTypes = NSTouchTypeMaskDirect;
474 return qRound(recognizer.minimumPressDuration * 1000);
475 }();
476 return pressAndHoldInterval;
477 }
478 case QPlatformTheme::ShowIconsInMenus:
479 return QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSTahoe;
480 case QPlatformTheme::MenuSelectionWraps:
481 return false;
482 case QPlatformTheme::MnemonicsEnabled:
483 return false;
484 case QPlatformTheme::UnderlineShortcut:
485 return false;
486 default:
487 break;
488 }
489 return QPlatformTheme::themeHint(hint);
490}
491
492Qt::ColorScheme QCocoaTheme::colorScheme() const
493{
494 return m_colorScheme;
495}
496
497void QCocoaTheme::requestColorScheme(Qt::ColorScheme scheme)
498{
499 QMacAutoReleasePool pool;
500
501 NSAppearance *appearance = nil;
502 switch (scheme) {
503 case Qt::ColorScheme::Dark:
504 appearance = [NSAppearance appearanceNamed:NSAppearanceNameDarkAqua];
505 break;
506 case Qt::ColorScheme::Light:
507 appearance = [NSAppearance appearanceNamed:NSAppearanceNameAqua];
508 break;
509 case Qt::ColorScheme::Unknown:
510 break;
511 }
512
513 // Always override the appearance, even if it's the same
514 // as the current effective appearance, as otherwise the
515 // requested appearance won't stick on system theme changes.
516 NSApp.appearance = appearance;
517}
518
519/*
520 Update the theme's color scheme based on the current appearance.
521
522 We can only reference the appearance on the main thread, but the
523 CoreText font engine needs to know the color scheme, and might be
524 used from secondary threads, so we cache the color scheme.
525*/
526void QCocoaTheme::updateColorScheme()
527{
528 auto appearance = [NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:
529 @[ NSAppearanceNameAqua, NSAppearanceNameDarkAqua ]];
530 m_colorScheme = [appearance isEqualToString:NSAppearanceNameDarkAqua] ?
531 Qt::ColorScheme::Dark : Qt::ColorScheme::Light;
532}
533
534Qt::ContrastPreference QCocoaTheme::contrastPreference() const
535{
536 return NSWorkspace.sharedWorkspace.accessibilityDisplayShouldIncreaseContrast ? Qt::ContrastPreference::HighContrast
537 : Qt::ContrastPreference::NoPreference;
538}
539
540Qt::MotionPreference QCocoaTheme::motionPreference() const
541{
542 return NSWorkspace.sharedWorkspace.accessibilityDisplayShouldReduceMotion ? Qt::MotionPreference::ReducedMotion
543 : Qt::MotionPreference::NoPreference;
544}
545
546QString QCocoaTheme::standardButtonText(int button) const
547{
548 return button == QPlatformDialogHelper::Discard ?
549 QCoreApplication::translate("QCocoaTheme", "Don't Save")
550 : QPlatformTheme::standardButtonText(button);
551}
552
553QKeySequence QCocoaTheme::standardButtonShortcut(int button) const
554{
555 return button == QPlatformDialogHelper::Discard ? QKeySequence(Qt::CTRL | Qt::Key_Delete)
556 : QPlatformTheme::standardButtonShortcut(button);
557}
558
559QPlatformMenuItem *QCocoaTheme::createPlatformMenuItem() const
560{
561 auto *menuItem = new QCocoaMenuItem();
562 qCDebug(lcQpaMenus) << "Created" << menuItem;
563 return menuItem;
564}
565
566QPlatformMenu *QCocoaTheme::createPlatformMenu() const
567{
568 auto *menu = new QCocoaMenu();
569 qCDebug(lcQpaMenus) << "Created" << menu;
570 return menu;
571}
572
573QPlatformMenuBar *QCocoaTheme::createPlatformMenuBar() const
574{
575 static bool haveMenubar = false;
576 if (!haveMenubar) {
577 haveMenubar = true;
578 QObject::connect(qGuiApp, &QGuiApplication::focusWindowChanged,
579 QCocoaIntegration::instance(), []{
580 QCocoaMenuBar::updateMenuBarImmediately();
581 });
582 }
583
584 auto *menuBar = new QCocoaMenuBar();
585 qCDebug(lcQpaMenus) << "Created" << menuBar;
586 return menuBar;
587}
588
589#ifndef QT_NO_SHORTCUT
590QList<QKeySequence> QCocoaTheme::keyBindings(QKeySequence::StandardKey key) const
591{
592 // The default key bindings in QPlatformTheme all hard-coded to use the Ctrl
593 // modifier, to match other platforms. In the normal case, when translating
594 // those to key sequences, we'll end up with Qt::ControlModifier+X, which is
595 // then matched against incoming key events that have been mapped from the
596 // command key to Qt::ControlModifier, and we'll get a match. If, however,
597 // the AA_MacDontSwapCtrlAndMeta application attribute is set, we need to
598 // fix the resulting key sequence so that it will match against unmapped
599 // key events that contain Qt::MetaModifier.
600 auto bindings = QPlatformTheme::keyBindings(key);
601
602 if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
603 static auto swapCtrlMeta = [](QKeyCombination keyCombination) {
604 const auto originalKeyModifiers = keyCombination.keyboardModifiers();
605 auto newKeyboardModifiers = originalKeyModifiers & ~(Qt::ControlModifier | Qt::MetaModifier);
606 if (originalKeyModifiers & Qt::ControlModifier)
607 newKeyboardModifiers |= Qt::MetaModifier;
608 if (originalKeyModifiers & Qt::MetaModifier)
609 newKeyboardModifiers |= Qt::ControlModifier;
610 return QKeyCombination(newKeyboardModifiers, keyCombination.key());
611 };
612
613 QList<QKeySequence> swappedBindings;
614 for (auto binding : bindings) {
615 Q_ASSERT(binding.count() == 1);
616 swappedBindings.append(QKeySequence(swapCtrlMeta(binding[0])));
617 }
618
619 bindings = swappedBindings;
620 }
621
622 return bindings;
623}
624#endif
625
626QT_END_NAMESPACE
Combined button and popup list for selecting options.
#define MAC_PALETTE_ENTRY(pal, active, inactive)
static QMacPaletteMap mac_widget_colors[]
static QT_BEGIN_NAMESPACE QPalette * qt_mac_createSystemPalette()
QPlatformTheme::Palette paletteRole
QMacPaletteMap(QPlatformTheme::Palette p, NSColor *a, NSColor *i)
NSColor * inactive
NSColor * active