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::ShowIconsInMenus:
470 return QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSTahoe;
471 case QPlatformTheme::MenuSelectionWraps:
472 return false;
473 case QPlatformTheme::MnemonicsEnabled:
474 return false;
475 case QPlatformTheme::UnderlineShortcut:
476 return false;
477 default:
478 break;
479 }
480 return QPlatformTheme::themeHint(hint);
481}
482
483Qt::ColorScheme QCocoaTheme::colorScheme() const
484{
485 return m_colorScheme;
486}
487
488void QCocoaTheme::requestColorScheme(Qt::ColorScheme scheme)
489{
490 QMacAutoReleasePool pool;
491
492 NSAppearance *appearance = nil;
493 switch (scheme) {
494 case Qt::ColorScheme::Dark:
495 appearance = [NSAppearance appearanceNamed:NSAppearanceNameDarkAqua];
496 break;
497 case Qt::ColorScheme::Light:
498 appearance = [NSAppearance appearanceNamed:NSAppearanceNameAqua];
499 break;
500 case Qt::ColorScheme::Unknown:
501 break;
502 }
503
504 // Always override the appearance, even if it's the same
505 // as the current effective appearance, as otherwise the
506 // requested appearance won't stick on system theme changes.
507 NSApp.appearance = appearance;
508}
509
510/*
511 Update the theme's color scheme based on the current appearance.
512
513 We can only reference the appearance on the main thread, but the
514 CoreText font engine needs to know the color scheme, and might be
515 used from secondary threads, so we cache the color scheme.
516*/
517void QCocoaTheme::updateColorScheme()
518{
519 auto appearance = [NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:
520 @[ NSAppearanceNameAqua, NSAppearanceNameDarkAqua ]];
521 m_colorScheme = [appearance isEqualToString:NSAppearanceNameDarkAqua] ?
522 Qt::ColorScheme::Dark : Qt::ColorScheme::Light;
523}
524
525Qt::ContrastPreference QCocoaTheme::contrastPreference() const
526{
527 return NSWorkspace.sharedWorkspace.accessibilityDisplayShouldIncreaseContrast ? Qt::ContrastPreference::HighContrast
528 : Qt::ContrastPreference::NoPreference;
529}
530
531Qt::MotionPreference QCocoaTheme::motionPreference() const
532{
533 return NSWorkspace.sharedWorkspace.accessibilityDisplayShouldReduceMotion ? Qt::MotionPreference::ReducedMotion
534 : Qt::MotionPreference::NoPreference;
535}
536
537QString QCocoaTheme::standardButtonText(int button) const
538{
539 return button == QPlatformDialogHelper::Discard ?
540 QCoreApplication::translate("QCocoaTheme", "Don't Save")
541 : QPlatformTheme::standardButtonText(button);
542}
543
544QKeySequence QCocoaTheme::standardButtonShortcut(int button) const
545{
546 return button == QPlatformDialogHelper::Discard ? QKeySequence(Qt::CTRL | Qt::Key_Delete)
547 : QPlatformTheme::standardButtonShortcut(button);
548}
549
550QPlatformMenuItem *QCocoaTheme::createPlatformMenuItem() const
551{
552 auto *menuItem = new QCocoaMenuItem();
553 qCDebug(lcQpaMenus) << "Created" << menuItem;
554 return menuItem;
555}
556
557QPlatformMenu *QCocoaTheme::createPlatformMenu() const
558{
559 auto *menu = new QCocoaMenu();
560 qCDebug(lcQpaMenus) << "Created" << menu;
561 return menu;
562}
563
564QPlatformMenuBar *QCocoaTheme::createPlatformMenuBar() const
565{
566 static bool haveMenubar = false;
567 if (!haveMenubar) {
568 haveMenubar = true;
569 QObject::connect(qGuiApp, &QGuiApplication::focusWindowChanged,
570 QCocoaIntegration::instance(), []{
571 QCocoaMenuBar::updateMenuBarImmediately();
572 });
573 }
574
575 auto *menuBar = new QCocoaMenuBar();
576 qCDebug(lcQpaMenus) << "Created" << menuBar;
577 return menuBar;
578}
579
580#ifndef QT_NO_SHORTCUT
581QList<QKeySequence> QCocoaTheme::keyBindings(QKeySequence::StandardKey key) const
582{
583 // The default key bindings in QPlatformTheme all hard-coded to use the Ctrl
584 // modifier, to match other platforms. In the normal case, when translating
585 // those to key sequences, we'll end up with Qt::ControlModifier+X, which is
586 // then matched against incoming key events that have been mapped from the
587 // command key to Qt::ControlModifier, and we'll get a match. If, however,
588 // the AA_MacDontSwapCtrlAndMeta application attribute is set, we need to
589 // fix the resulting key sequence so that it will match against unmapped
590 // key events that contain Qt::MetaModifier.
591 auto bindings = QPlatformTheme::keyBindings(key);
592
593 if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
594 static auto swapCtrlMeta = [](QKeyCombination keyCombination) {
595 const auto originalKeyModifiers = keyCombination.keyboardModifiers();
596 auto newKeyboardModifiers = originalKeyModifiers & ~(Qt::ControlModifier | Qt::MetaModifier);
597 if (originalKeyModifiers & Qt::ControlModifier)
598 newKeyboardModifiers |= Qt::MetaModifier;
599 if (originalKeyModifiers & Qt::MetaModifier)
600 newKeyboardModifiers |= Qt::ControlModifier;
601 return QKeyCombination(newKeyboardModifiers, keyCombination.key());
602 };
603
604 QList<QKeySequence> swappedBindings;
605 for (auto binding : bindings) {
606 Q_ASSERT(binding.count() == 1);
607 swappedBindings.append(QKeySequence(swapCtrlMeta(binding[0])));
608 }
609
610 bindings = swappedBindings;
611 }
612
613 return bindings;
614}
615#endif
616
617QT_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