5#include <QtCore/qt_windows.h>
13#if QT_CONFIG(systemtrayicon)
14# include "qwindowssystemtrayicon.h"
21#include <commoncontrols.h>
24#include <QtCore/qapplicationstatic.h>
25#include <QtCore/qvariant.h>
26#include <QtCore/qcoreapplication.h>
27#include <QtCore/qdebug.h>
28#include <QtCore/qsysinfo.h>
29#include <QtCore/qcache.h>
30#include <QtCore/qthread.h>
31#include <QtCore/qqueue.h>
32#include <QtCore/qmutex.h>
33#include <QtCore/qwaitcondition.h>
34#include <QtCore/qoperatingsystemversion.h>
35#include <QtGui/qcolor.h>
36#include <QtGui/qpalette.h>
37#include <QtGui/qguiapplication.h>
38#include <QtGui/qpainter.h>
39#include <QtGui/qpixmapcache.h>
40#include <qpa/qwindowsysteminterface.h>
41#include <QtGui/private/qabstractfileiconengine_p.h>
42#include <QtGui/private/qwindowsfontdatabase_p.h>
43#include <private/qhighdpiscaling_p.h>
44#include <private/qwinregistry_p.h>
45#include <QtCore/private/qfunctions_win_p.h>
46#include <QtGui/private/qwindowsthemecache_p.h>
50#if QT_CONFIG(cpp_winrt)
51# include <QtCore/private/qt_winrtbase_p.h>
53# include <winrt/Windows.UI.ViewManagement.h>
58using namespace Qt::StringLiterals;
63 if (SystemParametersInfo(what, 0, &result, 0))
64 return result != FALSE;
71 if (SystemParametersInfo(what, 0, &result, 0))
78 return {(c1.red() + c2.red()) / 2,
79 (c1.green() + c2.green()) / 2,
80 (c1.blue() + c2.blue()) / 2};
93#if QT_CONFIG(cpp_winrt)
94static constexpr QColor getSysColor(winrt::Windows::UI::Color &&color)
96 return QColor(color.R, color.G, color.B, color.A);
102 COLORREF cr = GetSysColor(index);
103 return QColor(GetRValue(cr), GetGValue(cr), GetBValue(cr));
110 QColor accentLighter;
111 QColor accentLightest;
114 QColor accentDarkest;
116#if QT_CONFIG(cpp_winrt)
118 using namespace winrt::Windows::UI::ViewManagement;
119 const auto settings = UISettings();
120 accent = getSysColor(settings.GetColorValue(UIColorType::Accent));
121 accentLight = getSysColor(settings.GetColorValue(UIColorType::AccentLight1));
122 accentLighter = getSysColor(settings.GetColorValue(UIColorType::AccentLight2));
123 accentLightest = getSysColor(settings.GetColorValue(UIColorType::AccentLight3));
124 accentDark = getSysColor(settings.GetColorValue(UIColorType::AccentDark1));
125 accentDarker = getSysColor(settings.GetColorValue(UIColorType::AccentDark2));
126 accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3));
132 if (!accent.isValid()) {
133 accent = []()->QColor {
136 if (QWindowsTheme::queryHighContrast())
137 return getSysColor(COLOR_HIGHLIGHT);
138 const QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)");
139 if (!registry.isValid())
141 const QVariant value = registry.value(L"AccentColor");
142 if (!value.isValid())
146 const QColor abgr = QColor::fromRgba(qvariant_cast<DWORD>(value));
149 return QColor::fromRgb(abgr.blue(), abgr.green(), abgr.red(), abgr.alpha());
151 if (!accent.isValid())
153 accentLight = accent.lighter(120);
154 accentLighter = accentLight.lighter(120);
155 accentLightest = accentLighter.lighter(120);
156 accentDark = accent.darker(120);
157 accentDarker = accentDark.darker(120);
158 accentDarkest = accentDarker.darker(120);
163 return accentDarkest;
171 return accentLighter;
173 return accentLightest;
187 Task(
const QString &fn, DWORD a, UINT f)
204 bool resultValid()
const {
return hIcon != 0 && iIcon >= 0 && finished; }
221 QMutexLocker l(&m_waitForTaskMutex);
222 while (!isInterruptionRequested()) {
223 if (!m_taskQueue.isEmpty())
224 return m_taskQueue.dequeue();
225 m_waitForTaskCondition.wait(&m_waitForTaskMutex);
232 QComHelper comHelper(COINIT_MULTITHREADED);
234 while (!isInterruptionRequested()) {
235 auto task = getNextTask();
238 const bool result = SHGetFileInfo(
reinterpret_cast<
const wchar_t *>(task->fileName.utf16()),
239 task->attributes, &info,
sizeof(SHFILEINFO),
242 task->hIcon = info.hIcon;
243 task->iIcon = info.iIcon;
245 task->finished =
true;
246 m_doneCondition.wakeAll();
255 QMutexLocker l(&m_waitForTaskMutex);
256 m_taskQueue.enqueue(task);
257 m_waitForTaskCondition.wakeAll();
260 QMutexLocker doneLocker(&m_doneMutex);
261 while (!task->finished && !isInterruptionRequested()) {
262 if (!m_doneCondition.wait(&m_doneMutex, QDeadlineTimer(timeout)))
269 requestInterruption();
270 m_doneCondition.wakeAll();
271 m_waitForTaskCondition.wakeAll();
275 QQueue<QSharedPointer<Task>> m_taskQueue;
276 QWaitCondition m_doneCondition;
277 QWaitCondition m_waitForTaskCondition;
279 QMutex m_waitForTaskMutex;
286 QColor backgroundColor(0xd4, 0xd0, 0xc8);
287 QColor lightColor(backgroundColor.lighter());
288 QColor darkColor(backgroundColor.darker());
289 const QBrush darkBrush(darkColor);
290 QColor midColor(Qt::gray);
291 QPalette palette(Qt::black, backgroundColor, lightColor, darkColor,
292 midColor, Qt::black, Qt::white);
293 palette.setBrush(QPalette::Disabled, QPalette::WindowText, darkBrush);
294 palette.setBrush(QPalette::Disabled, QPalette::Text, darkBrush);
295 palette.setBrush(QPalette::Disabled, QPalette::ButtonText, darkBrush);
296 palette.setBrush(QPalette::Disabled, QPalette::Base, QBrush(backgroundColor));
302 textColor.setAlpha(128);
307
308
309
310void QWindowsTheme::populateLightSystemBasePalette(QPalette &result)
314 const QColor background = getSysColor(COLOR_BTNFACE);
315 const QColor textColor = getSysColor(COLOR_WINDOWTEXT);
317 const QColor accent = qt_accentColor(AccentColorNormal);
318 const QColor accentDark = qt_accentColor(AccentColorDark);
319 const QColor accentDarker = qt_accentColor(AccentColorDarker);
320 const QColor accentDarkest = qt_accentColor(AccentColorDarkest);
322 const QColor linkColor = highContrastEnabled ? getSysColor(COLOR_HOTLIGHT) : accentDarker;
323 const QColor linkColorVisited = highContrastEnabled ? linkColor.darker(120) : accentDarkest;
324 const QColor btnFace = background;
325 const QColor btnHighlight = getSysColor(COLOR_BTNHIGHLIGHT);
327 result.setColor(QPalette::Highlight, accent);
328 result.setColor(QPalette::WindowText, getSysColor(COLOR_WINDOWTEXT));
329 result.setColor(QPalette::Button, btnFace);
330 result.setColor(QPalette::Light, btnHighlight);
331 result.setColor(QPalette::Dark, getSysColor(COLOR_BTNSHADOW));
332 result.setColor(QPalette::Mid, result.button().color().darker(150));
333 result.setColor(QPalette::Text, textColor);
334 result.setColor(QPalette::PlaceholderText, placeHolderColor(textColor));
335 result.setColor(QPalette::BrightText, btnHighlight);
336 result.setColor(QPalette::Base, getSysColor(COLOR_WINDOW));
337 result.setColor(QPalette::Window, highContrastEnabled ? getSysColor(COLOR_WINDOW) : btnFace);
338 result.setColor(QPalette::ButtonText, getSysColor(COLOR_BTNTEXT));
339 result.setColor(QPalette::Midlight, getSysColor(COLOR_3DLIGHT));
340 result.setColor(QPalette::Shadow, getSysColor(COLOR_3DDKSHADOW));
341 result.setColor(QPalette::HighlightedText, getSysColor(COLOR_HIGHLIGHTTEXT));
342 result.setColor(QPalette::Accent, accentDark);
344 result.setColor(QPalette::Link, linkColor);
345 result.setColor(QPalette::LinkVisited, linkColorVisited);
346 result.setColor(QPalette::Inactive, QPalette::Button, result.button().color());
347 result.setColor(QPalette::Inactive, QPalette::Window, result.window().color());
348 result.setColor(QPalette::Inactive, QPalette::Light, result.light().color());
349 result.setColor(QPalette::Inactive, QPalette::Dark, result.dark().color());
351 if (highContrastEnabled)
352 result.setColor(QPalette::Inactive, QPalette::WindowText, getSysColor(COLOR_GRAYTEXT));
354 if (result.midlight() == result.button())
355 result.setColor(QPalette::Midlight, result.button().color().lighter(110));
358void QWindowsTheme::populateDarkSystemBasePalette(QPalette &result)
362#if QT_CONFIG(cpp_winrt)
366 if (QWindowsTheme::queryColorScheme() == Qt::ColorScheme::Dark) {
368 using namespace winrt::Windows::UI::ViewManagement;
369 const auto settings = UISettings();
371 foreground = getSysColor(settings.GetColorValue(UIColorType::Foreground));
372 background = [&settings]() -> QColor {
373 auto systemBackground = getSysColor(settings.GetColorValue(UIColorType::Background));
374 if (systemBackground == Qt::black)
375 systemBackground = QColor(0x1E, 0x1E, 0x1E);
376 return systemBackground;
383 if (!background.isValid()) {
385 foreground = Qt::white;
386 background = QColor(0x1E, 0x1E, 0x1E);
389 const QColor accent = qt_accentColor(AccentColorNormal);
390 const QColor accentDarkest = qt_accentColor(AccentColorDarkest);
391 const QColor accentLighter = qt_accentColor(AccentColorLighter);
392 const QColor accentLightest = qt_accentColor(AccentColorLightest);
393 const QColor linkColor = accentLightest;
394 const QColor buttonColor = background.lighter(200);
396 result.setColor(QPalette::All, QPalette::WindowText, foreground);
397 result.setColor(QPalette::All, QPalette::Text, foreground);
398 result.setColor(QPalette::All, QPalette::BrightText, accentLightest);
400 result.setColor(QPalette::All, QPalette::Button, buttonColor);
401 result.setColor(QPalette::All, QPalette::ButtonText, foreground);
402 result.setColor(QPalette::All, QPalette::Light, buttonColor.lighter(200));
403 result.setColor(QPalette::All, QPalette::Midlight, buttonColor.lighter(150));
404 result.setColor(QPalette::All, QPalette::Dark, buttonColor.darker(200));
405 result.setColor(QPalette::All, QPalette::Mid, buttonColor.darker(150));
406 result.setColor(QPalette::All, QPalette::Shadow, Qt::black);
408 result.setColor(QPalette::All, QPalette::Base, background.lighter(150));
409 result.setColor(QPalette::All, QPalette::Window, background);
411 result.setColor(QPalette::All, QPalette::Highlight, accent);
412 result.setColor(QPalette::All, QPalette::HighlightedText, accent.lightness() > 128 ? Qt::black : Qt::white);
413 result.setColor(QPalette::All, QPalette::Link, linkColor);
414 result.setColor(QPalette::All, QPalette::LinkVisited, accentLighter);
415 result.setColor(QPalette::All, QPalette::AlternateBase, accentDarkest);
416 result.setColor(QPalette::All, QPalette::ToolTipBase, buttonColor);
417 result.setColor(QPalette::All, QPalette::ToolTipText, foreground.darker(120));
418 result.setColor(QPalette::All, QPalette::PlaceholderText, placeHolderColor(foreground));
419 result.setColor(QPalette::All, QPalette::Accent, accentLighter);
424 QPalette result(systemPalette);
425 static const bool isWindows11 = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11;
426 const QColor tipBgColor = highContrastEnabled ? (isWindows11 ? getSysColor(COLOR_WINDOW) : getSysColor(COLOR_BTNFACE)) :
427 (light ? getSysColor(COLOR_INFOBK) : systemPalette.button().color());
428 const QColor tipTextColor = highContrastEnabled ? (isWindows11 ? getSysColor(COLOR_WINDOWTEXT) : getSysColor(COLOR_BTNTEXT)) :
429 (light ? getSysColor(COLOR_INFOTEXT) : systemPalette.buttonText().color().darker(120));
431 result.setColor(QPalette::All, QPalette::Button, tipBgColor);
432 result.setColor(QPalette::All, QPalette::Window, tipBgColor);
433 result.setColor(QPalette::All, QPalette::Text, tipTextColor);
434 result.setColor(QPalette::All, QPalette::WindowText, tipTextColor);
435 result.setColor(QPalette::All, QPalette::ButtonText, tipTextColor);
436 result.setColor(QPalette::All, QPalette::Button, tipBgColor);
437 result.setColor(QPalette::All, QPalette::Window, tipBgColor);
438 result.setColor(QPalette::All, QPalette::Text, tipTextColor);
439 result.setColor(QPalette::All, QPalette::WindowText, tipTextColor);
440 result.setColor(QPalette::All, QPalette::ButtonText, tipTextColor);
441 result.setColor(QPalette::All, QPalette::ToolTipBase, tipBgColor);
442 result.setColor(QPalette::All, QPalette::ToolTipText, tipTextColor);
443 const QColor disabled = mixColors(result.windowText().color(), result.button().color());
444 result.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
445 result.setColor(QPalette::Disabled, QPalette::Text, disabled);
446 result.setColor(QPalette::Disabled, QPalette::ToolTipText, disabled);
447 result.setColor(QPalette::Disabled, QPalette::Base, Qt::white);
448 result.setColor(QPalette::Disabled, QPalette::BrightText, Qt::white);
449 result.setColor(QPalette::Disabled, QPalette::ToolTipBase, Qt::white);
456 return systemPalette;
458 QPalette result(systemPalette);
459 const QColor menuColor = getSysColor(COLOR_MENU);
460 const QColor menuTextColor = getSysColor(COLOR_MENUTEXT);
461 const QColor disabled = getSysColor(COLOR_GRAYTEXT);
463 result.setColor(QPalette::Active, QPalette::Button, menuColor);
464 result.setColor(QPalette::Active, QPalette::Text, menuTextColor);
465 result.setColor(QPalette::Active, QPalette::WindowText, menuTextColor);
466 result.setColor(QPalette::Active, QPalette::ButtonText, menuTextColor);
467 result.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
468 result.setColor(QPalette::Disabled, QPalette::Text, disabled);
469 const bool isFlat = booleanSystemParametersInfo(SPI_GETFLATMENU,
false);
470 const QColor highlightColor = getSysColor(isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT);
471 result.setColor(QPalette::Disabled, QPalette::Highlight, highlightColor);
472 result.setColor(QPalette::Disabled, QPalette::HighlightedText, disabled);
473 result.setColor(QPalette::Disabled, QPalette::Button,
474 result.color(QPalette::Active, QPalette::Button));
475 result.setColor(QPalette::Inactive, QPalette::Button,
476 result.color(QPalette::Active, QPalette::Button));
477 result.setColor(QPalette::Inactive, QPalette::Text,
478 result.color(QPalette::Active, QPalette::Text));
479 result.setColor(QPalette::Inactive, QPalette::WindowText,
480 result.color(QPalette::Active, QPalette::WindowText));
481 result.setColor(QPalette::Inactive, QPalette::ButtonText,
482 result.color(QPalette::Active, QPalette::ButtonText));
483 result.setColor(QPalette::Inactive, QPalette::Highlight,
484 result.color(QPalette::Active, QPalette::Highlight));
485 result.setColor(QPalette::Inactive, QPalette::HighlightedText,
486 result.color(QPalette::Active, QPalette::HighlightedText));
487 result.setColor(QPalette::Inactive, QPalette::ButtonText,
488 systemPalette.color(QPalette::Inactive, QPalette::Dark));
494 QPalette *result =
nullptr;
495 if (!light || !booleanSystemParametersInfo(SPI_GETFLATMENU,
false))
498 result =
new QPalette(menuPalette);
499 const QColor menubar(getSysColor(COLOR_MENUBAR));
500 result->setColor(QPalette::Active, QPalette::Button, menubar);
501 result->setColor(QPalette::Disabled, QPalette::Button, menubar);
502 result->setColor(QPalette::Inactive, QPalette::Button, menubar);
509LRESULT QT_WIN_CALLBACK qThemeChangeObserverWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
512 case WM_SETTINGCHANGE:
515 if (!((wParam == 0) && (lParam != 0)
516 && (wcscmp(
reinterpret_cast<LPCWSTR>(lParam), L"ImmersiveColorSet") == 0))
517 && wParam != SPI_SETCLIENTAREAANIMATION)
520 case WM_THEMECHANGED:
523 qCDebug(lcQpaTheme) <<
"Handling theme change due to"
524 << qUtf8Printable(decodeMSG(MSG{hwnd, message, wParam, lParam, 0, {0, 0}}).trimmed());
525 QWindowsTheme::handleThemeChange();
528 while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE));
541 return DefWindowProc(hwnd, message, wParam, lParam);
547 s_colorScheme = Qt::ColorScheme::Unknown;
548 s_colorScheme = QWindowsTheme::effectiveColorScheme();
549 std::fill(m_fonts, m_fonts + NFonts,
nullptr);
550 std::fill(m_palettes, m_palettes + NPalettes,
nullptr);
552 refreshIconPixmapSizes();
555 "ThemeChangeObserverWindow"_L1,
556 qThemeChangeObserverWndProc);
559 m_themeChangeObserver = CreateWindowEx(0,
reinterpret_cast<LPCWSTR>(className.utf16()),
560 nullptr, WS_TILED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
561 nullptr,
nullptr, GetModuleHandle(
nullptr),
nullptr);
562 Q_ASSERT(m_themeChangeObserver);
569 m_instance =
nullptr;
574 qCDebug(lcQpaTheme) <<
"Destroying theme change window";
575 DestroyWindow(m_themeChangeObserver);
576 m_themeChangeObserver =
nullptr;
581 const QFileInfo appDir(QCoreApplication::applicationDirPath() +
"/icons"_L1);
582 return appDir.isDir() ? QStringList(appDir.absoluteFilePath()) : QStringList();
587 QStringList styles = { QStringLiteral(
"WindowsVista"), QStringLiteral(
"Windows") };
588 if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11)
589 styles.prepend(QStringLiteral(
"Windows11"));
595 int result = QPlatformTheme::HoverEffect;
596 if (booleanSystemParametersInfo(SPI_GETUIEFFECTS,
false))
597 result |= QPlatformTheme::GeneralUiEffect;
598 if (booleanSystemParametersInfo(SPI_GETMENUANIMATION,
false))
599 result |= QPlatformTheme::AnimateMenuUiEffect;
600 if (booleanSystemParametersInfo(SPI_GETMENUFADE,
false))
601 result |= QPlatformTheme::FadeMenuUiEffect;
602 if (booleanSystemParametersInfo(SPI_GETCOMBOBOXANIMATION,
false))
603 result |= QPlatformTheme::AnimateComboUiEffect;
604 if (booleanSystemParametersInfo(SPI_GETTOOLTIPANIMATION,
false))
605 result |= QPlatformTheme::AnimateTooltipUiEffect;
612 case UseFullScreenForPopupMenu:
613 return QVariant(
true);
614 case DialogButtonBoxLayout:
615 return QVariant(QPlatformDialogHelper::WinLayout);
616 case IconThemeSearchPaths:
617 return QVariant(iconThemeSearchPaths());
619 return QVariant(styleNames());
620 case TextCursorWidth:
621 return QVariant(
int(dWordSystemParametersInfo(SPI_GETCARETWIDTH, 1u)));
623 return QVariant(booleanSystemParametersInfo(SPI_GETDROPSHADOW,
false));
624 case MaximumScrollBarDragDistance:
627 return QVariant(
int(WindowsKeyboardScheme));
630 case IconPixmapSizes:
631 return QVariant::fromValue(m_fileIconSizes);
632 case DialogSnapToDefaultButton:
633 return QVariant(booleanSystemParametersInfo(SPI_GETSNAPTODEFBUTTON,
false));
634 case ContextMenuOnMouseRelease:
635 return QVariant(
true);
636 case WheelScrollLines: {
638 const DWORD scrollLines = dWordSystemParametersInfo(SPI_GETWHEELSCROLLLINES, DWORD(result));
639 if (scrollLines != DWORD(-1))
640 result =
int(scrollLines);
641 return QVariant(result);
643 case MouseDoubleClickDistance:
644 return GetSystemMetrics(SM_CXDOUBLECLK);
645 case MenuBarFocusOnAltPressRelease:
650 return QPlatformTheme::themeHint(hint);
655 return QWindowsTheme::effectiveColorScheme();
661 if (queryHighContrast())
662 return Qt::ColorScheme::Unknown;
663 if (s_colorSchemeOverride != Qt::ColorScheme::Unknown)
664 return s_colorSchemeOverride;
665 if (s_colorScheme != Qt::ColorScheme::Unknown)
666 return s_colorScheme;
667 if (!integration->darkModeHandling().testFlag(QWindowsApplication::DarkModeStyle))
668 return Qt::ColorScheme::Light;
669 return queryColorScheme();
674 s_colorSchemeOverride = scheme;
680 return queryHighContrast() ? Qt::ContrastPreference::HighContrast
681 : Qt::ContrastPreference::NoPreference;
686 return booleanSystemParametersInfo(SPI_GETCLIENTAREAANIMATION,
false) ? Qt::MotionPreference::NoPreference
687 : Qt::MotionPreference::ReducedMotion;
696 QWindowsThemeCache::clearAllThemeCaches();
698 const auto oldColorScheme = s_colorScheme;
699 s_colorScheme = Qt::ColorScheme::Unknown;
700 s_colorScheme = effectiveColorScheme();
701 if (s_colorScheme != oldColorScheme) {
705 for (QWindowsWindow *w : std::as_const(QWindowsContext::instance()->windows()))
706 w->setDarkBorder(s_colorScheme == Qt::ColorScheme::Dark);
713 QWindowSystemInterface::handleThemeChange<QWindowSystemInterface::SynchronousDelivery>();
718 qDeleteAll(m_palettes, m_palettes + NPalettes);
719 std::fill(m_palettes, m_palettes + NPalettes,
nullptr);
724 if (!QGuiApplication::desktopSettingsAware())
727 effectiveColorScheme() != Qt::ColorScheme::Dark
728 || !QWindowsIntegration::instance()->darkModeHandling().testFlag(QWindowsApplication::DarkModeStyle);
730 m_palettes[SystemPalette] =
new QPalette(QWindowsTheme::systemPalette(s_colorScheme));
731 m_palettes[ToolTipPalette] =
new QPalette(toolTipPalette(*m_palettes[SystemPalette], light, queryHighContrast()));
732 m_palettes[MenuPalette] =
new QPalette(menuPalette(*m_palettes[SystemPalette], light));
733 m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette], light);
735 m_palettes[CheckBoxPalette] =
new QPalette(*m_palettes[SystemPalette]);
736 m_palettes[CheckBoxPalette]->setColor(QPalette::Active, QPalette::Base, qt_accentColor(AccentColorNormal));
737 m_palettes[CheckBoxPalette]->setColor(QPalette::Active, QPalette::Button, qt_accentColor(AccentColorLighter));
738 m_palettes[CheckBoxPalette]->setColor(QPalette::Inactive, QPalette::Base, qt_accentColor(AccentColorDarkest));
739 m_palettes[RadioButtonPalette] =
new QPalette(*m_palettes[CheckBoxPalette]);
745 QPalette result = standardPalette();
747 switch (colorScheme) {
748 case Qt::ColorScheme::Unknown:
751 case Qt::ColorScheme::Light:
752 populateLightSystemBasePalette(result);
754 case Qt::ColorScheme::Dark:
755 populateDarkSystemBasePalette(result);
759 if (result.window() != result.base()) {
760 result.setColor(QPalette::Inactive, QPalette::Highlight,
761 result.color(QPalette::Inactive, QPalette::Window));
762 result.setColor(QPalette::Inactive, QPalette::HighlightedText,
763 result.color(QPalette::Inactive, QPalette::Text));
764 result.setColor(QPalette::Inactive, QPalette::Accent,
765 result.color(QPalette::Inactive, QPalette::Window));
768 const QColor disabled = mixColors(result.windowText().color(), result.button().color());
770 result.setColorGroup(QPalette::Disabled, result.windowText(), result.button(),
771 result.light(), result.dark(), result.mid(),
772 result.text(), result.brightText(), result.base(),
775 const bool highContrastEnabled = queryHighContrast();
776 const QColor disabledTextColor = highContrastEnabled ? getSysColor(COLOR_GRAYTEXT) : disabled;
777 result.setColor(QPalette::Disabled, QPalette::WindowText, disabledTextColor);
778 result.setColor(QPalette::Disabled, QPalette::Text, disabledTextColor);
779 result.setColor(QPalette::Disabled, QPalette::ButtonText, disabledTextColor);
780 if (highContrastEnabled)
781 result.setColor(QPalette::Disabled, QPalette::Button, result.button().color().darker(150));
783 result.setColor(QPalette::Disabled, QPalette::Highlight, result.color(QPalette::Highlight));
784 result.setColor(QPalette::Disabled, QPalette::HighlightedText, result.color(QPalette::HighlightedText));
785 result.setColor(QPalette::Disabled, QPalette::Accent, disabled);
786 result.setColor(QPalette::Disabled, QPalette::Base, result.window().color());
792 qDeleteAll(m_fonts, m_fonts + NFonts);
793 std::fill(m_fonts, m_fonts + NFonts,
nullptr);
802#ifndef QT_NO_DEBUG_STREAM
803QDebug operator<<(QDebug d,
const NONCLIENTMETRICS &m)
805 QDebugStateSaver saver(d);
808 d <<
"NONCLIENTMETRICS(iMenu=" << m.iMenuWidth <<
'x' << m.iMenuHeight
809 <<
", lfCaptionFont=";
810 QWindowsFontDatabase::debugFormat(d, m.lfCaptionFont);
811 d <<
", lfSmCaptionFont=";
812 QWindowsFontDatabase::debugFormat(d, m.lfSmCaptionFont);
813 d <<
", lfMenuFont=";
814 QWindowsFontDatabase::debugFormat(d, m.lfMenuFont);
815 d <<
", lfMessageFont=";
816 QWindowsFontDatabase::debugFormat(d, m.lfMessageFont);
817 d <<
", lfStatusFont=";
818 QWindowsFontDatabase::debugFormat(d, m.lfStatusFont);
827 if (!QGuiApplication::desktopSettingsAware())
831 NONCLIENTMETRICS ncm;
832 QWindowsContext::nonClientMetrics(&ncm, dpi);
833 qCDebug(lcQpaWindow) <<
__FUNCTION__ << ncm;
835 const QFont menuFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMenuFont, dpi);
836 const QFont messageBoxFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont, dpi);
837 const QFont statusFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfStatusFont, dpi);
838 const QFont titleFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfCaptionFont, dpi);
839 QFont fixedFont(QStringLiteral(
"Courier New"), messageBoxFont.pointSize());
840 fixedFont.setStyleHint(QFont::TypeWriter);
842 LOGFONT lfIconTitleFont;
843 SystemParametersInfoForDpi(SPI_GETICONTITLELOGFONT,
sizeof(lfIconTitleFont), &lfIconTitleFont, 0, dpi);
844 const QFont iconTitleFont = QWindowsFontDatabase::LOGFONT_to_QFont(lfIconTitleFont, dpi);
846 m_fonts[SystemFont] =
new QFont(QWindowsFontDatabase::systemDefaultFont());
847 m_fonts[MenuFont] =
new QFont(menuFont);
848 m_fonts[MenuBarFont] =
new QFont(menuFont);
849 m_fonts[MessageBoxFont] =
new QFont(messageBoxFont);
850 m_fonts[TipLabelFont] =
new QFont(statusFont);
851 m_fonts[StatusBarFont] =
new QFont(statusFont);
852 m_fonts[MdiSubWindowTitleFont] =
new QFont(titleFont);
853 m_fonts[DockWidgetTitleFont] =
new QFont(titleFont);
854 m_fonts[ItemViewFont] =
new QFont(iconTitleFont);
855 m_fonts[FixedFont] =
new QFont(fixedFont);
869 return QWindowsDialogs::useHelper(type);
874 return QWindowsDialogs::createHelper(type);
877#if QT_CONFIG(systemtrayicon)
878QPlatformSystemTrayIcon *QWindowsTheme::createPlatformSystemTrayIcon()
const
880 return new QWindowsSystemTrayIcon;
896 m_fileIconSizes = QAbstractFileIconEngine::toSizeList(fileIconSizes, availEnd);
897 qCDebug(lcQpaWindow) <<
__FUNCTION__ << m_fileIconSizes;
905 HMODULE shell32 = ::GetModuleHandleW(L"shell32.dll");
908 static_cast<HICON>(LoadImage(shell32, MAKEINTRESOURCE(resourceId),
909 IMAGE_ICON,
int(size.width()),
int(size.height()), 0));
911 QPixmap iconpixmap = qt_pixmapFromWinHICON(iconHandle);
912 DestroyIcon(iconHandle);
921 SHSTOCKICONID stockId = SIID_INVALID;
922 LPCTSTR iconName =
nullptr;
925 stockId = SIID_DRIVECD;
929 stockId = SIID_DRIVEDVD;
933 stockId = SIID_DRIVENET;
937 stockId = SIID_DRIVEFIXED;
941 stockId = SIID_DRIVE35;
947 stockId = SIID_DOCNOASSOC;
954 stockId = SIID_FOLDER;
963 case DirLinkOpenIcon:
966 stockId = SIID_FOLDEROPEN;
969 case FileDialogNewFolder:
970 stockId = SIID_FOLDER;
977 stockId = SIID_RECYCLER;
980 case MessageBoxInformation:
982 iconName = IDI_INFORMATION;
984 case MessageBoxWarning:
985 stockId = SIID_WARNING;
986 iconName = IDI_WARNING;
988 case MessageBoxCritical:
989 stockId = SIID_ERROR;
990 iconName = IDI_ERROR;
992 case MessageBoxQuestion:
994 iconName = IDI_QUESTION;
997 stockId = SIID_SHIELD;
1005 const auto drawLinkOverlayIconIfNeeded = [](StandardPixmap sp, QPixmap &pixmap, QSizeF pixmapSize) {
1006 if (sp == FileLinkIcon || sp == DirLinkIcon || sp == DirLinkOpenIcon) {
1007 QPainter painter(&pixmap);
1008 const QSizeF linkSize = pixmapSize / (pixmapSize.height() >= 48 ? 3 : 2);
1009 static constexpr auto LinkOverlayIconId = 16769;
1010 const QPixmap link = loadIconFromShell32(LinkOverlayIconId, linkSize.toSize());
1011 const int yPos = pixmap.height() - link.size().height();
1012 painter.drawPixmap(0, yPos,
int(linkSize.width()),
int(linkSize.height()), link);
1016 if (stockId != SIID_INVALID) {
1017 SHSTOCKICONINFO iconInfo;
1018 memset(&iconInfo, 0,
sizeof(iconInfo));
1019 iconInfo.cbSize =
sizeof(iconInfo);
1020 constexpr UINT stockFlags = SHGSI_ICONLOCATION;
1021 if (SHGetStockIconInfo(stockId, stockFlags, &iconInfo) == S_OK) {
1022 const auto iconSize = pixmapSize.width();
1024 if (SHDefExtractIcon(iconInfo.szPath, iconInfo.iIcon, 0, &icon,
nullptr, iconSize) == S_OK) {
1025 QPixmap pixmap = qt_pixmapFromWinHICON(icon);
1027 if (!pixmap.isNull()) {
1028 drawLinkOverlayIconIfNeeded(sp, pixmap, pixmap.size());
1035 if (resourceId != -1) {
1036 QPixmap pixmap = loadIconFromShell32(resourceId, pixmapSize);
1037 if (!pixmap.isNull()) {
1038 drawLinkOverlayIconIfNeeded(sp, pixmap, pixmapSize);
1044 HICON iconHandle = LoadIcon(
nullptr, iconName);
1045 QPixmap pixmap = qt_pixmapFromWinHICON(iconHandle);
1046 DestroyIcon(iconHandle);
1047 if (!pixmap.isNull())
1051 return QPlatformTheme::standardPixmap(sp, pixmapSize);
1061 QString key =
"qt_dir_"_L1 + QString::number(iIcon);
1062 if (iconSize == SHGFI_LARGEICON)
1064 switch (imageListSize) {
1075template <
typename T>
1080 static_assert(
sizeof(T) <=
sizeof(
void *),
"FakePointers can only go that far.");
1084 return reinterpret_cast<
FakePointer *>(qintptr(thing));
1089 return T(qintptr(
this));
1101 static const IID iID_IImageList = {0x46eb5926, 0x582e, 0x4017, {0x9f, 0xdf, 0xe8, 0x99, 0x8d, 0xaa, 0x9, 0x50}};
1103 IImageList *imageList =
nullptr;
1104 HRESULT hr = SHGetImageList(iImageList, iID_IImageList,
reinterpret_cast<
void **>(&imageList));
1108 hr = imageList->GetIcon(iIcon, ILD_TRANSPARENT, &hIcon);
1110 result = qt_pixmapFromWinHICON(hIcon);
1113 imageList->Release();
1134 if ((options() & QPlatformTheme::DontUseCustomDirectoryIcons) && fileInfo().isDir() && !fileInfo().isRoot())
1135 return QStringLiteral(
"qt_/directory/");
1136 if (!fileInfo().isFile())
1141 QString suffix = fileInfo().suffix();
1142 if (!suffix.compare(u"exe", Qt::CaseInsensitive)
1143 || !suffix.compare(u"lnk", Qt::CaseInsensitive)
1144 || !suffix.compare(u"ico", Qt::CaseInsensitive)) {
1148 + (suffix.isEmpty() ? fileInfo().fileName() : std::move(suffix).toUpper());
1153 QComHelper comHelper;
1155 static QCache<QString, FakePointer<
int> > dirIconEntryCache(1000);
1156 Q_CONSTINIT
static QMutex mx;
1157 static int defaultFolderIIcon = -1;
1158 const bool useDefaultFolderIcon = options() & QPlatformTheme::DontUseCustomDirectoryIcons;
1161 const QString filePath = QDir::toNativeSeparators(fileInfo().filePath());
1162 const int width =
int(size.width());
1163 const int iconSize = width > fileIconSizes[SmallFileIcon] ? SHGFI_LARGEICON : SHGFI_SMALLICON;
1164 const int requestedImageListSize =
1168 bool cacheableDirIcon = fileInfo().isDir() && !fileInfo().isRoot();
1169 if (cacheableDirIcon) {
1170 QMutexLocker locker(&mx);
1171 int iIcon = (useDefaultFolderIcon && defaultFolderIIcon >= 0) ? defaultFolderIIcon
1172 : **dirIconEntryCache.object(filePath);
1174 QPixmapCache::find(dirIconPixmapCacheKey(iIcon, iconSize, requestedImageListSize),
1176 if (pixmap.isNull())
1177 dirIconEntryCache.remove(filePath);
1183 unsigned int flags = SHGFI_ICON | iconSize | SHGFI_SYSICONINDEX | SHGFI_ADDOVERLAYS | SHGFI_OVERLAYINDEX;
1184 DWORD attributes = 0;
1185 QString path = filePath;
1186 if (cacheableDirIcon && useDefaultFolderIcon) {
1187 flags |= SHGFI_USEFILEATTRIBUTES;
1188 attributes |= FILE_ATTRIBUTE_DIRECTORY;
1189 path = QStringLiteral(
"dummy");
1190 }
else if (!fileInfo().exists()) {
1191 flags |= SHGFI_USEFILEATTRIBUTES;
1192 attributes |= FILE_ATTRIBUTE_NORMAL;
1196 s_shGetFileInfoThread()->runWithParams(task);
1198 if (task->resultValid()) {
1200 if (cacheableDirIcon) {
1201 if (useDefaultFolderIcon && defaultFolderIIcon < 0)
1202 defaultFolderIIcon = task->iIcon;
1205 key = dirIconPixmapCacheKey(task->iIcon, iconSize, requestedImageListSize);
1206 QPixmapCache::find(key, &pixmap);
1207 if (!pixmap.isNull()) {
1208 QMutexLocker locker(&mx);
1209 dirIconEntryCache.insert(filePath, FakePointer<
int>::create(task->iIcon));
1213 if (pixmap.isNull()) {
1214 if (requestedImageListSize) {
1215 pixmap = pixmapFromShellImageList(requestedImageListSize, task->iIcon);
1216 if (pixmap.isNull() && requestedImageListSize == sHIL_JUMBO)
1217 pixmap = pixmapFromShellImageList(sHIL_EXTRALARGE, task->iIcon);
1219 if (pixmap.isNull())
1220 pixmap = qt_pixmapFromWinHICON(task->hIcon);
1221 if (!pixmap.isNull()) {
1222 if (cacheableDirIcon) {
1223 QMutexLocker locker(&mx);
1224 QPixmapCache::insert(key, pixmap);
1225 dirIconEntryCache.insert(filePath, FakePointer<
int>::create(task->iIcon));
1228 qWarning(
"QWindowsTheme::fileIconPixmap() no icon found");
1243 return new QWindowsIconEngine(iconName);
1249 if ((options & QWindowsIntegration::NoNativeMenus) != 0)
1251 if ((options & QWindowsIntegration::AlwaysUseNativeMenus) != 0)
1254 if (!QCoreApplication::instance()->inherits(
"QApplication"))
1256 const QWindowList &topLevels = QGuiApplication::topLevelWindows();
1257 for (
const QWindow *t : topLevels) {
1258 if (t->inherits(
"QQuickApplicationWindow"))
1272 if (queryHighContrast())
1273 return Qt::ColorScheme::Unknown;
1275 QWinRegistryKey personalizeKey{
1276 HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)"
1278 const bool useDarkTheme = personalizeKey.value<DWORD>(L"AppsUseLightTheme") == 0;
1279 return useDarkTheme ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light;
1284 HIGHCONTRAST hcf = {};
1285 hcf.cbSize =
static_cast<UINT>(
sizeof(HIGHCONTRAST));
1286 if (SystemParametersInfo(SPI_GETHIGHCONTRAST, hcf.cbSize, &hcf, FALSE))
1287 return hcf.dwFlags & HCF_HIGHCONTRASTON;
1293 qCDebug(lcQpaMenus) <<
__FUNCTION__;
1299 qCDebug(lcQpaMenus) <<
__FUNCTION__;
1309 qCDebug(lcQpaMenus) <<
__FUNCTION__;
1315 qCDebug(lcQpaMenus) <<
__FUNCTION__;
void operator delete(void *)
static FakePointer * create(T thing)
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
void runWithParams(const QSharedPointer< Task > &task, std::chrono::milliseconds timeout=std::chrono::milliseconds(5000))
QSharedPointer< Task > getNextTask()
Singleton container for all relevant information.
static QWindowsContext * instance()
QList< QSize > availableSizes(QIcon::Mode=QIcon::Normal, QIcon::State=QIcon::Off) override
Returns sizes of all images that are contained in the engine for the specific mode and state.
QPixmap filePixmap(const QSize &size, QIcon::Mode mode, QIcon::State) override
QWindowsFileIconEngine(const QFileInfo &info, QPlatformTheme::IconOptions opts)
QString cacheKey() const override
void updateApplicationBadge()
static QWindowsIntegration * instance()
static bool useNativeMenus()
void requestColorScheme(Qt::ColorScheme scheme) override
void showPlatformMenuBar() override
QIconEngine * createIconEngine(const QString &iconName) const override
Factory function for the QIconEngine used by QIcon::fromTheme().
QPlatformMenuBar * createPlatformMenuBar() const override
static void handleThemeChange()
bool usePlatformNativeDialog(DialogType type) const override
QPlatformMenuItem * createPlatformMenuItem() const override
Qt::ColorScheme colorScheme() const override
QVariant themeHint(ThemeHint) const override
~QWindowsTheme() override
Qt::MotionPreference motionPreference() const override
static bool queryHighContrast()
QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions={}) const override
Return an icon for fileInfo, observing iconOptions.
QPlatformDialogHelper * createPlatformDialogHelper(DialogType type) const override
static QWindowsTheme * instance()
QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const override
Return a pixmap for standardPixmap, at the given size.
QPlatformMenu * createPlatformMenu() const override
Qt::ContrastPreference contrastPreference() const override
static QWindowsWindowClassRegistry * instance()
#define WM_SYSCOLORCHANGE
#define WM_DWMCOLORIZATIONCOLORCHANGED
static QPixmap pixmapFromShellImageList(int iImageList, int iIcon)
static int fileIconSizes[FileIconSizeCount]
static QStringList styleNames()
static bool doUseNativeMenus()
static QPalette toolTipPalette(const QPalette &systemPalette, bool light, bool highContrastEnabled)
static QStringList iconThemeSearchPaths()
static QColor qt_accentColor(AccentColorLevel level)
static QColor getSysColor(int index)
static QPalette standardPalette()
static QString dirIconPixmapCacheKey(int iIcon, int iconSize, int imageListSize)
static QColor mixColors(const QColor &c1, const QColor &c2)
static QColor placeHolderColor(QColor textColor)
static DWORD dWordSystemParametersInfo(UINT what, DWORD defaultValue)
static QPalette menuPalette(const QPalette &systemPalette, bool light)
static QPixmap loadIconFromShell32(int resourceId, QSizeF size)
static QPalette * menuBarPalette(const QPalette &menuPalette, bool light)
static bool booleanSystemParametersInfo(UINT what, bool defaultValue)
Task(const QString &fn, DWORD a, UINT f)