4#include <QtCore/qt_windows.h>
12#if QT_CONFIG(systemtrayicon)
13# include "qwindowssystemtrayicon.h"
19#include <commoncontrols.h>
22#include <QtCore/qapplicationstatic.h>
23#include <QtCore/qvariant.h>
24#include <QtCore/qcoreapplication.h>
25#include <QtCore/qdebug.h>
26#include <QtCore/qsysinfo.h>
27#include <QtCore/qcache.h>
28#include <QtCore/qthread.h>
29#include <QtCore/qqueue.h>
30#include <QtCore/qmutex.h>
31#include <QtCore/qwaitcondition.h>
32#include <QtCore/qoperatingsystemversion.h>
33#include <QtGui/qcolor.h>
34#include <QtGui/qpalette.h>
35#include <QtGui/qguiapplication.h>
36#include <QtGui/qpainter.h>
37#include <QtGui/qpixmapcache.h>
38#include <qpa/qwindowsysteminterface.h>
39#include <QtGui/private/qabstractfileiconengine_p.h>
40#include <QtGui/private/qwindowsfontdatabase_p.h>
41#include <private/qhighdpiscaling_p.h>
42#include <private/qwinregistry_p.h>
43#include <QtCore/private/qfunctions_win_p.h>
44#include <QtGui/private/qwindowsthemecache_p.h>
48#if QT_CONFIG(cpp_winrt)
49# include <QtCore/private/qt_winrtbase_p.h>
51# include <winrt/Windows.UI.ViewManagement.h>
56using namespace Qt::StringLiterals;
61 if (SystemParametersInfo(what, 0, &result, 0))
62 return result != FALSE;
69 if (SystemParametersInfo(what, 0, &result, 0))
76 return {(c1.red() + c2.red()) / 2,
77 (c1.green() + c2.green()) / 2,
78 (c1.blue() + c2.blue()) / 2};
91#if QT_CONFIG(cpp_winrt)
92static constexpr QColor getSysColor(winrt::Windows::UI::Color &&color)
94 return QColor(color.R, color.G, color.B, color.A);
100 COLORREF cr = GetSysColor(index);
101 return QColor(GetRValue(cr), GetGValue(cr), GetBValue(cr));
108 QColor accentLighter;
109 QColor accentLightest;
112 QColor accentDarkest;
114#if QT_CONFIG(cpp_winrt)
116 using namespace winrt::Windows::UI::ViewManagement;
117 const auto settings = UISettings();
118 accent = getSysColor(settings.GetColorValue(UIColorType::Accent));
119 accentLight = getSysColor(settings.GetColorValue(UIColorType::AccentLight1));
120 accentLighter = getSysColor(settings.GetColorValue(UIColorType::AccentLight2));
121 accentLightest = getSysColor(settings.GetColorValue(UIColorType::AccentLight3));
122 accentDark = getSysColor(settings.GetColorValue(UIColorType::AccentDark1));
123 accentDarker = getSysColor(settings.GetColorValue(UIColorType::AccentDark2));
124 accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3));
130 if (!accent.isValid()) {
131 accent = []()->QColor {
134 if (QWindowsTheme::queryHighContrast())
135 return getSysColor(COLOR_HIGHLIGHT);
136 const QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)");
137 if (!registry.isValid())
139 const QVariant value = registry.value(L"AccentColor");
140 if (!value.isValid())
144 const QColor abgr = QColor::fromRgba(qvariant_cast<DWORD>(value));
147 return QColor::fromRgb(abgr.blue(), abgr.green(), abgr.red(), abgr.alpha());
149 if (!accent.isValid())
151 accentLight = accent.lighter(120);
152 accentLighter = accentLight.lighter(120);
153 accentLightest = accentLighter.lighter(120);
154 accentDark = accent.darker(120);
155 accentDarker = accentDark.darker(120);
156 accentDarkest = accentDarker.darker(120);
161 return accentDarkest;
169 return accentLighter;
171 return accentLightest;
185 Task(
const QString &fn, DWORD a, UINT f)
202 bool resultValid()
const {
return hIcon != 0 && iIcon >= 0 && finished; }
219 QMutexLocker l(&m_waitForTaskMutex);
220 while (!isInterruptionRequested()) {
221 if (!m_taskQueue.isEmpty())
222 return m_taskQueue.dequeue();
223 m_waitForTaskCondition.wait(&m_waitForTaskMutex);
230 QComHelper comHelper(COINIT_MULTITHREADED);
232 while (!isInterruptionRequested()) {
233 auto task = getNextTask();
236 const bool result = SHGetFileInfo(
reinterpret_cast<
const wchar_t *>(task->fileName.utf16()),
237 task->attributes, &info,
sizeof(SHFILEINFO),
240 task->hIcon = info.hIcon;
241 task->iIcon = info.iIcon;
243 task->finished =
true;
244 m_doneCondition.wakeAll();
253 QMutexLocker l(&m_waitForTaskMutex);
254 m_taskQueue.enqueue(task);
255 m_waitForTaskCondition.wakeAll();
258 QMutexLocker doneLocker(&m_doneMutex);
259 while (!task->finished && !isInterruptionRequested()) {
260 if (!m_doneCondition.wait(&m_doneMutex, QDeadlineTimer(timeout)))
267 requestInterruption();
268 m_doneCondition.wakeAll();
269 m_waitForTaskCondition.wakeAll();
273 QQueue<QSharedPointer<Task>> m_taskQueue;
274 QWaitCondition m_doneCondition;
275 QWaitCondition m_waitForTaskCondition;
277 QMutex m_waitForTaskMutex;
282static inline QPalette standardPalette()
284 QColor backgroundColor(0xd4, 0xd0, 0xc8);
285 QColor lightColor(backgroundColor.lighter());
286 QColor darkColor(backgroundColor.darker());
287 const QBrush darkBrush(darkColor);
288 QColor midColor(Qt::gray);
289 QPalette palette(Qt::black, backgroundColor, lightColor, darkColor,
290 midColor, Qt::black, Qt::white);
291 palette.setBrush(QPalette::Disabled, QPalette::WindowText, darkBrush);
292 palette.setBrush(QPalette::Disabled, QPalette::Text, darkBrush);
293 palette.setBrush(QPalette::Disabled, QPalette::ButtonText, darkBrush);
294 palette.setBrush(QPalette::Disabled, QPalette::Base, QBrush(backgroundColor));
300 textColor.setAlpha(128);
305
306
307
308void QWindowsTheme::populateLightSystemBasePalette(QPalette &result)
312 const QColor background = getSysColor(COLOR_BTNFACE);
313 const QColor textColor = getSysColor(COLOR_WINDOWTEXT);
315 const QColor accent = qt_accentColor(AccentColorNormal);
316 const QColor accentDark = qt_accentColor(AccentColorDark);
317 const QColor accentDarker = qt_accentColor(AccentColorDarker);
318 const QColor accentDarkest = qt_accentColor(AccentColorDarkest);
320 const QColor linkColor = highContrastEnabled ? getSysColor(COLOR_HOTLIGHT) : accentDarker;
321 const QColor linkColorVisited = highContrastEnabled ? linkColor.darker(120) : accentDarkest;
322 const QColor btnFace = background;
323 const QColor btnHighlight = getSysColor(COLOR_BTNHIGHLIGHT);
325 result.setColor(QPalette::Highlight, accent);
326 result.setColor(QPalette::WindowText, getSysColor(COLOR_WINDOWTEXT));
327 result.setColor(QPalette::Button, btnFace);
328 result.setColor(QPalette::Light, btnHighlight);
329 result.setColor(QPalette::Dark, getSysColor(COLOR_BTNSHADOW));
330 result.setColor(QPalette::Mid, result.button().color().darker(150));
331 result.setColor(QPalette::Text, textColor);
332 result.setColor(QPalette::PlaceholderText, placeHolderColor(textColor));
333 result.setColor(QPalette::BrightText, btnHighlight);
334 result.setColor(QPalette::Base, getSysColor(COLOR_WINDOW));
335 result.setColor(QPalette::Window, highContrastEnabled ? getSysColor(COLOR_WINDOW) : btnFace);
336 result.setColor(QPalette::ButtonText, getSysColor(COLOR_BTNTEXT));
337 result.setColor(QPalette::Midlight, getSysColor(COLOR_3DLIGHT));
338 result.setColor(QPalette::Shadow, getSysColor(COLOR_3DDKSHADOW));
339 result.setColor(QPalette::HighlightedText, getSysColor(COLOR_HIGHLIGHTTEXT));
340 result.setColor(QPalette::Accent, accentDark);
342 result.setColor(QPalette::Link, linkColor);
343 result.setColor(QPalette::LinkVisited, linkColorVisited);
344 result.setColor(QPalette::Inactive, QPalette::Button, result.button().color());
345 result.setColor(QPalette::Inactive, QPalette::Window, result.window().color());
346 result.setColor(QPalette::Inactive, QPalette::Light, result.light().color());
347 result.setColor(QPalette::Inactive, QPalette::Dark, result.dark().color());
349 if (highContrastEnabled)
350 result.setColor(QPalette::Inactive, QPalette::WindowText, getSysColor(COLOR_GRAYTEXT));
352 if (result.midlight() == result.button())
353 result.setColor(QPalette::Midlight, result.button().color().lighter(110));
356void QWindowsTheme::populateDarkSystemBasePalette(QPalette &result)
360#if QT_CONFIG(cpp_winrt)
364 if (QWindowsTheme::queryColorScheme() == Qt::ColorScheme::Dark) {
366 using namespace winrt::Windows::UI::ViewManagement;
367 const auto settings = UISettings();
369 foreground = getSysColor(settings.GetColorValue(UIColorType::Foreground));
370 background = [&settings]() -> QColor {
371 auto systemBackground = getSysColor(settings.GetColorValue(UIColorType::Background));
372 if (systemBackground == Qt::black)
373 systemBackground = QColor(0x1E, 0x1E, 0x1E);
374 return systemBackground;
381 if (!background.isValid()) {
383 foreground = Qt::white;
384 background = QColor(0x1E, 0x1E, 0x1E);
387 const QColor accent = qt_accentColor(AccentColorNormal);
388 const QColor accentDarkest = qt_accentColor(AccentColorDarkest);
389 const QColor accentLighter = qt_accentColor(AccentColorLighter);
390 const QColor accentLightest = qt_accentColor(AccentColorLightest);
391 const QColor linkColor = accentLightest;
392 const QColor buttonColor = background.lighter(200);
394 result.setColor(QPalette::All, QPalette::WindowText, foreground);
395 result.setColor(QPalette::All, QPalette::Text, foreground);
396 result.setColor(QPalette::All, QPalette::BrightText, accentLightest);
398 result.setColor(QPalette::All, QPalette::Button, buttonColor);
399 result.setColor(QPalette::All, QPalette::ButtonText, foreground);
400 result.setColor(QPalette::All, QPalette::Light, buttonColor.lighter(200));
401 result.setColor(QPalette::All, QPalette::Midlight, buttonColor.lighter(150));
402 result.setColor(QPalette::All, QPalette::Dark, buttonColor.darker(200));
403 result.setColor(QPalette::All, QPalette::Mid, buttonColor.darker(150));
404 result.setColor(QPalette::All, QPalette::Shadow, Qt::black);
406 result.setColor(QPalette::All, QPalette::Base, background.lighter(150));
407 result.setColor(QPalette::All, QPalette::Window, background);
409 result.setColor(QPalette::All, QPalette::Highlight, accent);
410 result.setColor(QPalette::All, QPalette::HighlightedText, accent.lightness() > 128 ? Qt::black : Qt::white);
411 result.setColor(QPalette::All, QPalette::Link, linkColor);
412 result.setColor(QPalette::All, QPalette::LinkVisited, accentLighter);
413 result.setColor(QPalette::All, QPalette::AlternateBase, accentDarkest);
414 result.setColor(QPalette::All, QPalette::ToolTipBase, buttonColor);
415 result.setColor(QPalette::All, QPalette::ToolTipText, foreground.darker(120));
416 result.setColor(QPalette::All, QPalette::PlaceholderText, placeHolderColor(foreground));
417 result.setColor(QPalette::All, QPalette::Accent, accentLighter);
422 QPalette result(systemPalette);
423 static const bool isWindows11 = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11;
424 const QColor tipBgColor = highContrastEnabled ? (isWindows11 ? getSysColor(COLOR_WINDOW) : getSysColor(COLOR_BTNFACE)) :
425 (light ? getSysColor(COLOR_INFOBK) : systemPalette.button().color());
426 const QColor tipTextColor = highContrastEnabled ? (isWindows11 ? getSysColor(COLOR_WINDOWTEXT) : getSysColor(COLOR_BTNTEXT)) :
427 (light ? getSysColor(COLOR_INFOTEXT) : systemPalette.buttonText().color().darker(120));
429 result.setColor(QPalette::All, QPalette::Button, tipBgColor);
430 result.setColor(QPalette::All, QPalette::Window, tipBgColor);
431 result.setColor(QPalette::All, QPalette::Text, tipTextColor);
432 result.setColor(QPalette::All, QPalette::WindowText, tipTextColor);
433 result.setColor(QPalette::All, QPalette::ButtonText, tipTextColor);
434 result.setColor(QPalette::All, QPalette::Button, tipBgColor);
435 result.setColor(QPalette::All, QPalette::Window, tipBgColor);
436 result.setColor(QPalette::All, QPalette::Text, tipTextColor);
437 result.setColor(QPalette::All, QPalette::WindowText, tipTextColor);
438 result.setColor(QPalette::All, QPalette::ButtonText, tipTextColor);
439 result.setColor(QPalette::All, QPalette::ToolTipBase, tipBgColor);
440 result.setColor(QPalette::All, QPalette::ToolTipText, tipTextColor);
441 const QColor disabled = mixColors(result.windowText().color(), result.button().color());
442 result.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
443 result.setColor(QPalette::Disabled, QPalette::Text, disabled);
444 result.setColor(QPalette::Disabled, QPalette::ToolTipText, disabled);
445 result.setColor(QPalette::Disabled, QPalette::Base, Qt::white);
446 result.setColor(QPalette::Disabled, QPalette::BrightText, Qt::white);
447 result.setColor(QPalette::Disabled, QPalette::ToolTipBase, Qt::white);
454 return systemPalette;
456 QPalette result(systemPalette);
457 const QColor menuColor = getSysColor(COLOR_MENU);
458 const QColor menuTextColor = getSysColor(COLOR_MENUTEXT);
459 const QColor disabled = getSysColor(COLOR_GRAYTEXT);
461 result.setColor(QPalette::Active, QPalette::Button, menuColor);
462 result.setColor(QPalette::Active, QPalette::Text, menuTextColor);
463 result.setColor(QPalette::Active, QPalette::WindowText, menuTextColor);
464 result.setColor(QPalette::Active, QPalette::ButtonText, menuTextColor);
465 result.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
466 result.setColor(QPalette::Disabled, QPalette::Text, disabled);
467 const bool isFlat = booleanSystemParametersInfo(SPI_GETFLATMENU,
false);
468 const QColor highlightColor = getSysColor(isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT);
469 result.setColor(QPalette::Disabled, QPalette::Highlight, highlightColor);
470 result.setColor(QPalette::Disabled, QPalette::HighlightedText, disabled);
471 result.setColor(QPalette::Disabled, QPalette::Button,
472 result.color(QPalette::Active, QPalette::Button));
473 result.setColor(QPalette::Inactive, QPalette::Button,
474 result.color(QPalette::Active, QPalette::Button));
475 result.setColor(QPalette::Inactive, QPalette::Text,
476 result.color(QPalette::Active, QPalette::Text));
477 result.setColor(QPalette::Inactive, QPalette::WindowText,
478 result.color(QPalette::Active, QPalette::WindowText));
479 result.setColor(QPalette::Inactive, QPalette::ButtonText,
480 result.color(QPalette::Active, QPalette::ButtonText));
481 result.setColor(QPalette::Inactive, QPalette::Highlight,
482 result.color(QPalette::Active, QPalette::Highlight));
483 result.setColor(QPalette::Inactive, QPalette::HighlightedText,
484 result.color(QPalette::Active, QPalette::HighlightedText));
485 result.setColor(QPalette::Inactive, QPalette::ButtonText,
486 systemPalette.color(QPalette::Inactive, QPalette::Dark));
492 QPalette *result =
nullptr;
493 if (!light || !booleanSystemParametersInfo(SPI_GETFLATMENU,
false))
496 result =
new QPalette(menuPalette);
497 const QColor menubar(getSysColor(COLOR_MENUBAR));
498 result->setColor(QPalette::Active, QPalette::Button, menubar);
499 result->setColor(QPalette::Disabled, QPalette::Button, menubar);
500 result->setColor(QPalette::Inactive, QPalette::Button, menubar);
507LRESULT QT_WIN_CALLBACK qThemeChangeObserverWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
510 case WM_SETTINGCHANGE:
512 if (!((wParam == 0) && (lParam != 0)
513 && (wcscmp(
reinterpret_cast<LPCWSTR>(lParam), L"ImmersiveColorSet") == 0)))
516 case WM_THEMECHANGED:
519 qCDebug(lcQpaTheme) <<
"Handling theme change due to"
520 << qUtf8Printable(decodeMSG(MSG{hwnd, message, wParam, lParam, 0, {0, 0}}).trimmed());
521 QWindowsTheme::handleThemeChange();
524 while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE));
537 return DefWindowProc(hwnd, message, wParam, lParam);
543 s_colorScheme = Qt::ColorScheme::Unknown;
544 s_colorScheme = QWindowsTheme::effectiveColorScheme();
545 std::fill(m_fonts, m_fonts + NFonts,
nullptr);
546 std::fill(m_palettes, m_palettes + NPalettes,
nullptr);
548 refreshIconPixmapSizes();
550 auto className = QWindowsContext::instance()->registerWindowClass(
551 QWindowsContext::classNamePrefix() + QLatin1String(
"ThemeChangeObserverWindow"),
552 qThemeChangeObserverWndProc);
555 m_themeChangeObserver = CreateWindowEx(0,
reinterpret_cast<LPCWSTR>(className.utf16()),
556 nullptr, WS_TILED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
557 nullptr,
nullptr, GetModuleHandle(
nullptr),
nullptr);
558 Q_ASSERT(m_themeChangeObserver);
565 m_instance =
nullptr;
570 qCDebug(lcQpaTheme) <<
"Destroying theme change window";
571 DestroyWindow(m_themeChangeObserver);
572 m_themeChangeObserver =
nullptr;
577 const QFileInfo appDir(QCoreApplication::applicationDirPath() +
"/icons"_L1);
578 return appDir.isDir() ? QStringList(appDir.absoluteFilePath()) : QStringList();
583 QStringList styles = { QStringLiteral(
"WindowsVista"), QStringLiteral(
"Windows") };
584 if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11)
585 styles.prepend(QStringLiteral(
"Windows11"));
591 int result = QPlatformTheme::HoverEffect;
592 if (booleanSystemParametersInfo(SPI_GETUIEFFECTS,
false))
593 result |= QPlatformTheme::GeneralUiEffect;
594 if (booleanSystemParametersInfo(SPI_GETMENUANIMATION,
false))
595 result |= QPlatformTheme::AnimateMenuUiEffect;
596 if (booleanSystemParametersInfo(SPI_GETMENUFADE,
false))
597 result |= QPlatformTheme::FadeMenuUiEffect;
598 if (booleanSystemParametersInfo(SPI_GETCOMBOBOXANIMATION,
false))
599 result |= QPlatformTheme::AnimateComboUiEffect;
600 if (booleanSystemParametersInfo(SPI_GETTOOLTIPANIMATION,
false))
601 result |= QPlatformTheme::AnimateTooltipUiEffect;
608 case UseFullScreenForPopupMenu:
609 return QVariant(
true);
610 case DialogButtonBoxLayout:
611 return QVariant(QPlatformDialogHelper::WinLayout);
612 case IconThemeSearchPaths:
613 return QVariant(iconThemeSearchPaths());
615 return QVariant(styleNames());
616 case TextCursorWidth:
617 return QVariant(
int(dWordSystemParametersInfo(SPI_GETCARETWIDTH, 1u)));
619 return QVariant(booleanSystemParametersInfo(SPI_GETDROPSHADOW,
false));
620 case MaximumScrollBarDragDistance:
623 return QVariant(
int(WindowsKeyboardScheme));
626 case IconPixmapSizes:
627 return QVariant::fromValue(m_fileIconSizes);
628 case DialogSnapToDefaultButton:
629 return QVariant(booleanSystemParametersInfo(SPI_GETSNAPTODEFBUTTON,
false));
630 case ContextMenuOnMouseRelease:
631 return QVariant(
true);
632 case WheelScrollLines: {
634 const DWORD scrollLines = dWordSystemParametersInfo(SPI_GETWHEELSCROLLLINES, DWORD(result));
635 if (scrollLines != DWORD(-1))
636 result =
int(scrollLines);
637 return QVariant(result);
639 case MouseDoubleClickDistance:
640 return GetSystemMetrics(SM_CXDOUBLECLK);
641 case MenuBarFocusOnAltPressRelease:
646 return QPlatformTheme::themeHint(hint);
651 return QWindowsTheme::effectiveColorScheme();
657 if (queryHighContrast())
658 return Qt::ColorScheme::Unknown;
659 if (s_colorSchemeOverride != Qt::ColorScheme::Unknown)
660 return s_colorSchemeOverride;
661 if (s_colorScheme != Qt::ColorScheme::Unknown)
662 return s_colorScheme;
663 if (!integration->darkModeHandling().testFlag(QWindowsApplication::DarkModeStyle))
664 return Qt::ColorScheme::Light;
665 return queryColorScheme();
670 s_colorSchemeOverride = scheme;
676 return queryHighContrast() ? Qt::ContrastPreference::HighContrast
677 : Qt::ContrastPreference::NoPreference;
682 QWindowsThemeCache::clearAllThemeCaches();
684 const auto oldColorScheme = s_colorScheme;
685 s_colorScheme = Qt::ColorScheme::Unknown;
686 s_colorScheme = effectiveColorScheme();
687 if (s_colorScheme != oldColorScheme) {
692 for (QWindowsWindow *w : std::as_const(QWindowsContext::instance()->windows()))
693 w->setDarkBorder(s_colorScheme == Qt::ColorScheme::Dark);
700 QWindowSystemInterface::handleThemeChange<QWindowSystemInterface::SynchronousDelivery>();
705 qDeleteAll(m_palettes, m_palettes + NPalettes);
706 std::fill(m_palettes, m_palettes + NPalettes,
nullptr);
711 if (!QGuiApplication::desktopSettingsAware())
714 effectiveColorScheme() != Qt::ColorScheme::Dark
715 || !QWindowsIntegration::instance()->darkModeHandling().testFlag(QWindowsApplication::DarkModeStyle);
717 m_palettes[SystemPalette] =
new QPalette(QWindowsTheme::systemPalette(s_colorScheme));
718 m_palettes[ToolTipPalette] =
new QPalette(toolTipPalette(*m_palettes[SystemPalette], light, queryHighContrast()));
719 m_palettes[MenuPalette] =
new QPalette(menuPalette(*m_palettes[SystemPalette], light));
720 m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette], light);
722 m_palettes[CheckBoxPalette] =
new QPalette(*m_palettes[SystemPalette]);
723 m_palettes[CheckBoxPalette]->setColor(QPalette::Active, QPalette::Base, qt_accentColor(AccentColorNormal));
724 m_palettes[CheckBoxPalette]->setColor(QPalette::Active, QPalette::Button, qt_accentColor(AccentColorLighter));
725 m_palettes[CheckBoxPalette]->setColor(QPalette::Inactive, QPalette::Base, qt_accentColor(AccentColorDarkest));
726 m_palettes[RadioButtonPalette] =
new QPalette(*m_palettes[CheckBoxPalette]);
732 QPalette result = standardPalette();
734 switch (colorScheme) {
735 case Qt::ColorScheme::Unknown:
738 case Qt::ColorScheme::Light:
739 populateLightSystemBasePalette(result);
741 case Qt::ColorScheme::Dark:
742 populateDarkSystemBasePalette(result);
746 if (result.window() != result.base()) {
747 result.setColor(QPalette::Inactive, QPalette::Highlight,
748 result.color(QPalette::Inactive, QPalette::Window));
749 result.setColor(QPalette::Inactive, QPalette::HighlightedText,
750 result.color(QPalette::Inactive, QPalette::Text));
751 result.setColor(QPalette::Inactive, QPalette::Accent,
752 result.color(QPalette::Inactive, QPalette::Window));
755 const QColor disabled = mixColors(result.windowText().color(), result.button().color());
757 result.setColorGroup(QPalette::Disabled, result.windowText(), result.button(),
758 result.light(), result.dark(), result.mid(),
759 result.text(), result.brightText(), result.base(),
762 const bool highContrastEnabled = queryHighContrast();
763 const QColor disabledTextColor = highContrastEnabled ? getSysColor(COLOR_GRAYTEXT) : disabled;
764 result.setColor(QPalette::Disabled, QPalette::WindowText, disabledTextColor);
765 result.setColor(QPalette::Disabled, QPalette::Text, disabledTextColor);
766 result.setColor(QPalette::Disabled, QPalette::ButtonText, disabledTextColor);
767 if (highContrastEnabled)
768 result.setColor(QPalette::Disabled, QPalette::Button, result.button().color().darker(150));
770 result.setColor(QPalette::Disabled, QPalette::Highlight, result.color(QPalette::Highlight));
771 result.setColor(QPalette::Disabled, QPalette::HighlightedText, result.color(QPalette::HighlightedText));
772 result.setColor(QPalette::Disabled, QPalette::Accent, disabled);
773 result.setColor(QPalette::Disabled, QPalette::Base, result.window().color());
779 qDeleteAll(m_fonts, m_fonts + NFonts);
780 std::fill(m_fonts, m_fonts + NFonts,
nullptr);
789#ifndef QT_NO_DEBUG_STREAM
790QDebug operator<<(QDebug d,
const NONCLIENTMETRICS &m)
792 QDebugStateSaver saver(d);
795 d <<
"NONCLIENTMETRICS(iMenu=" << m.iMenuWidth <<
'x' << m.iMenuHeight
796 <<
", lfCaptionFont=";
797 QWindowsFontDatabase::debugFormat(d, m.lfCaptionFont);
798 d <<
", lfSmCaptionFont=";
799 QWindowsFontDatabase::debugFormat(d, m.lfSmCaptionFont);
800 d <<
", lfMenuFont=";
801 QWindowsFontDatabase::debugFormat(d, m.lfMenuFont);
802 d <<
", lfMessageFont=";
803 QWindowsFontDatabase::debugFormat(d, m.lfMessageFont);
804 d <<
", lfStatusFont=";
805 QWindowsFontDatabase::debugFormat(d, m.lfStatusFont);
814 if (!QGuiApplication::desktopSettingsAware())
818 NONCLIENTMETRICS ncm;
819 QWindowsContext::nonClientMetrics(&ncm, dpi);
820 qCDebug(lcQpaWindow) <<
__FUNCTION__ << ncm;
822 const QFont menuFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMenuFont, dpi);
823 const QFont messageBoxFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont, dpi);
824 const QFont statusFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfStatusFont, dpi);
825 const QFont titleFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfCaptionFont, dpi);
826 QFont fixedFont(QStringLiteral(
"Courier New"), messageBoxFont.pointSize());
827 fixedFont.setStyleHint(QFont::TypeWriter);
829 LOGFONT lfIconTitleFont;
830 SystemParametersInfoForDpi(SPI_GETICONTITLELOGFONT,
sizeof(lfIconTitleFont), &lfIconTitleFont, 0, dpi);
831 const QFont iconTitleFont = QWindowsFontDatabase::LOGFONT_to_QFont(lfIconTitleFont, dpi);
833 m_fonts[SystemFont] =
new QFont(QWindowsFontDatabase::systemDefaultFont());
834 m_fonts[MenuFont] =
new QFont(menuFont);
835 m_fonts[MenuBarFont] =
new QFont(menuFont);
836 m_fonts[MessageBoxFont] =
new QFont(messageBoxFont);
837 m_fonts[TipLabelFont] =
new QFont(statusFont);
838 m_fonts[StatusBarFont] =
new QFont(statusFont);
839 m_fonts[MdiSubWindowTitleFont] =
new QFont(titleFont);
840 m_fonts[DockWidgetTitleFont] =
new QFont(titleFont);
841 m_fonts[ItemViewFont] =
new QFont(iconTitleFont);
842 m_fonts[FixedFont] =
new QFont(fixedFont);
856 return QWindowsDialogs::useHelper(type);
861 return QWindowsDialogs::createHelper(type);
864#if QT_CONFIG(systemtrayicon)
865QPlatformSystemTrayIcon *QWindowsTheme::createPlatformSystemTrayIcon()
const
867 return new QWindowsSystemTrayIcon;
876 fileIconSizes[SmallFileIcon] = GetSystemMetrics(SM_CXSMICON);
877 fileIconSizes[LargeFileIcon] = GetSystemMetrics(SM_CXICON);
883 m_fileIconSizes = QAbstractFileIconEngine::toSizeList(fileIconSizes, availEnd);
884 qCDebug(lcQpaWindow) <<
__FUNCTION__ << m_fileIconSizes;
892 HMODULE shell32 = ::GetModuleHandleW(L"shell32.dll");
895 static_cast<HICON>(LoadImage(shell32, MAKEINTRESOURCE(resourceId),
896 IMAGE_ICON,
int(size.width()),
int(size.height()), 0));
898 QPixmap iconpixmap = qt_pixmapFromWinHICON(iconHandle);
899 DestroyIcon(iconHandle);
908 SHSTOCKICONID stockId = SIID_INVALID;
909 LPCTSTR iconName =
nullptr;
912 stockId = SIID_DRIVECD;
916 stockId = SIID_DRIVEDVD;
920 stockId = SIID_DRIVENET;
924 stockId = SIID_DRIVEFIXED;
928 stockId = SIID_DRIVE35;
934 stockId = SIID_DOCNOASSOC;
941 stockId = SIID_FOLDER;
950 case DirLinkOpenIcon:
953 stockId = SIID_FOLDEROPEN;
956 case FileDialogNewFolder:
957 stockId = SIID_FOLDER;
964 stockId = SIID_RECYCLER;
967 case MessageBoxInformation:
969 iconName = IDI_INFORMATION;
971 case MessageBoxWarning:
972 stockId = SIID_WARNING;
973 iconName = IDI_WARNING;
975 case MessageBoxCritical:
976 stockId = SIID_ERROR;
977 iconName = IDI_ERROR;
979 case MessageBoxQuestion:
981 iconName = IDI_QUESTION;
984 stockId = SIID_SHIELD;
992 const auto drawLinkOverlayIconIfNeeded = [](StandardPixmap sp, QPixmap &pixmap, QSizeF pixmapSize) {
993 if (sp == FileLinkIcon || sp == DirLinkIcon || sp == DirLinkOpenIcon) {
994 QPainter painter(&pixmap);
995 const QSizeF linkSize = pixmapSize / (pixmapSize.height() >= 48 ? 3 : 2);
996 static constexpr auto LinkOverlayIconId = 16769;
997 const QPixmap link = loadIconFromShell32(LinkOverlayIconId, linkSize.toSize());
998 const int yPos = pixmap.height() - link.size().height();
999 painter.drawPixmap(0, yPos,
int(linkSize.width()),
int(linkSize.height()), link);
1003 if (stockId != SIID_INVALID) {
1004 SHSTOCKICONINFO iconInfo;
1005 memset(&iconInfo, 0,
sizeof(iconInfo));
1006 iconInfo.cbSize =
sizeof(iconInfo);
1007 constexpr UINT stockFlags = SHGSI_ICONLOCATION;
1008 if (SHGetStockIconInfo(stockId, stockFlags, &iconInfo) == S_OK) {
1009 const auto iconSize = pixmapSize.width();
1011 if (SHDefExtractIcon(iconInfo.szPath, iconInfo.iIcon, 0, &icon,
nullptr, iconSize) == S_OK) {
1012 QPixmap pixmap = qt_pixmapFromWinHICON(icon);
1014 if (!pixmap.isNull()) {
1015 drawLinkOverlayIconIfNeeded(sp, pixmap, pixmap.size());
1022 if (resourceId != -1) {
1023 QPixmap pixmap = loadIconFromShell32(resourceId, pixmapSize);
1024 if (!pixmap.isNull()) {
1025 drawLinkOverlayIconIfNeeded(sp, pixmap, pixmapSize);
1031 HICON iconHandle = LoadIcon(
nullptr, iconName);
1032 QPixmap pixmap = qt_pixmapFromWinHICON(iconHandle);
1033 DestroyIcon(iconHandle);
1034 if (!pixmap.isNull())
1038 return QPlatformTheme::standardPixmap(sp, pixmapSize);
1048 QString key =
"qt_dir_"_L1 + QString::number(iIcon);
1049 if (iconSize == SHGFI_LARGEICON)
1051 switch (imageListSize) {
1062template <
typename T>
1067 static_assert(
sizeof(T) <=
sizeof(
void *),
"FakePointers can only go that far.");
1071 return reinterpret_cast<
FakePointer *>(qintptr(thing));
1076 return T(qintptr(
this));
1088 static const IID iID_IImageList = {0x46eb5926, 0x582e, 0x4017, {0x9f, 0xdf, 0xe8, 0x99, 0x8d, 0xaa, 0x9, 0x50}};
1090 IImageList *imageList =
nullptr;
1091 HRESULT hr = SHGetImageList(iImageList, iID_IImageList,
reinterpret_cast<
void **>(&imageList));
1095 hr = imageList->GetIcon(iIcon, ILD_TRANSPARENT, &hIcon);
1097 result = qt_pixmapFromWinHICON(hIcon);
1100 imageList->Release();
1121 if ((options() & QPlatformTheme::DontUseCustomDirectoryIcons) && fileInfo().isDir() && !fileInfo().isRoot())
1122 return QStringLiteral(
"qt_/directory/");
1123 if (!fileInfo().isFile())
1128 QString suffix = fileInfo().suffix();
1129 if (!suffix.compare(u"exe", Qt::CaseInsensitive)
1130 || !suffix.compare(u"lnk", Qt::CaseInsensitive)
1131 || !suffix.compare(u"ico", Qt::CaseInsensitive)) {
1135 + (suffix.isEmpty() ? fileInfo().fileName() : std::move(suffix).toUpper());
1140 QComHelper comHelper;
1142 static QCache<QString, FakePointer<
int> > dirIconEntryCache(1000);
1143 Q_CONSTINIT
static QMutex mx;
1144 static int defaultFolderIIcon = -1;
1145 const bool useDefaultFolderIcon = options() & QPlatformTheme::DontUseCustomDirectoryIcons;
1148 const QString filePath = QDir::toNativeSeparators(fileInfo().filePath());
1149 const int width =
int(size.width());
1150 const int iconSize = width > fileIconSizes[SmallFileIcon] ? SHGFI_LARGEICON : SHGFI_SMALLICON;
1151 const int requestedImageListSize =
1155 bool cacheableDirIcon = fileInfo().isDir() && !fileInfo().isRoot();
1156 if (cacheableDirIcon) {
1157 QMutexLocker locker(&mx);
1158 int iIcon = (useDefaultFolderIcon && defaultFolderIIcon >= 0) ? defaultFolderIIcon
1159 : **dirIconEntryCache.object(filePath);
1161 QPixmapCache::find(dirIconPixmapCacheKey(iIcon, iconSize, requestedImageListSize),
1163 if (pixmap.isNull())
1164 dirIconEntryCache.remove(filePath);
1170 unsigned int flags = SHGFI_ICON | iconSize | SHGFI_SYSICONINDEX | SHGFI_ADDOVERLAYS | SHGFI_OVERLAYINDEX;
1171 DWORD attributes = 0;
1172 QString path = filePath;
1173 if (cacheableDirIcon && useDefaultFolderIcon) {
1174 flags |= SHGFI_USEFILEATTRIBUTES;
1175 attributes |= FILE_ATTRIBUTE_DIRECTORY;
1176 path = QStringLiteral(
"dummy");
1177 }
else if (!fileInfo().exists()) {
1178 flags |= SHGFI_USEFILEATTRIBUTES;
1179 attributes |= FILE_ATTRIBUTE_NORMAL;
1183 s_shGetFileInfoThread()->runWithParams(task);
1185 if (task->resultValid()) {
1187 if (cacheableDirIcon) {
1188 if (useDefaultFolderIcon && defaultFolderIIcon < 0)
1189 defaultFolderIIcon = task->iIcon;
1192 key = dirIconPixmapCacheKey(task->iIcon, iconSize, requestedImageListSize);
1193 QPixmapCache::find(key, &pixmap);
1194 if (!pixmap.isNull()) {
1195 QMutexLocker locker(&mx);
1196 dirIconEntryCache.insert(filePath, FakePointer<
int>::create(task->iIcon));
1200 if (pixmap.isNull()) {
1201 if (requestedImageListSize) {
1202 pixmap = pixmapFromShellImageList(requestedImageListSize, task->iIcon);
1203 if (pixmap.isNull() && requestedImageListSize == sHIL_JUMBO)
1204 pixmap = pixmapFromShellImageList(sHIL_EXTRALARGE, task->iIcon);
1206 if (pixmap.isNull())
1207 pixmap = qt_pixmapFromWinHICON(task->hIcon);
1208 if (!pixmap.isNull()) {
1209 if (cacheableDirIcon) {
1210 QMutexLocker locker(&mx);
1211 QPixmapCache::insert(key, pixmap);
1212 dirIconEntryCache.insert(filePath, FakePointer<
int>::create(task->iIcon));
1215 qWarning(
"QWindowsTheme::fileIconPixmap() no icon found");
1230 return new QWindowsIconEngine(iconName);
1236 if ((options & QWindowsIntegration::NoNativeMenus) != 0)
1238 if ((options & QWindowsIntegration::AlwaysUseNativeMenus) != 0)
1241 if (!QCoreApplication::instance()->inherits(
"QApplication"))
1243 const QWindowList &topLevels = QGuiApplication::topLevelWindows();
1244 for (
const QWindow *t : topLevels) {
1245 if (t->inherits(
"QQuickApplicationWindow"))
1259 if (queryHighContrast())
1260 return Qt::ColorScheme::Unknown;
1262 QWinRegistryKey personalizeKey{
1263 HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)"
1265 const bool useDarkTheme = personalizeKey.value<DWORD>(L"AppsUseLightTheme") == 0;
1266 return useDarkTheme ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light;
1271 HIGHCONTRAST hcf = {};
1272 hcf.cbSize =
static_cast<UINT>(
sizeof(HIGHCONTRAST));
1273 if (SystemParametersInfo(SPI_GETHIGHCONTRAST, hcf.cbSize, &hcf, FALSE))
1274 return hcf.dwFlags & HCF_HIGHCONTRASTON;
1280 qCDebug(lcQpaMenus) <<
__FUNCTION__;
1286 qCDebug(lcQpaMenus) <<
__FUNCTION__;
1296 qCDebug(lcQpaMenus) <<
__FUNCTION__;
1302 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
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
#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 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)
Q_APPLICATION_STATIC(QShGetFileInfoThread, s_shGetFileInfoThread) static inline QPalette standardPalette()
static QPalette * menuBarPalette(const QPalette &menuPalette, bool light)
static bool booleanSystemParametersInfo(UINT what, bool defaultValue)
Task(const QString &fn, DWORD a, UINT f)