4#include <QtCore/qt_windows.h>
12#if QT_CONFIG(systemtrayicon)
13# include "qwindowssystemtrayicon.h"
20#include <commoncontrols.h>
23#include <QtCore/qapplicationstatic.h>
24#include <QtCore/qvariant.h>
25#include <QtCore/qcoreapplication.h>
26#include <QtCore/qdebug.h>
27#include <QtCore/qsysinfo.h>
28#include <QtCore/qcache.h>
29#include <QtCore/qthread.h>
30#include <QtCore/qqueue.h>
31#include <QtCore/qmutex.h>
32#include <QtCore/qwaitcondition.h>
33#include <QtCore/qoperatingsystemversion.h>
34#include <QtGui/qcolor.h>
35#include <QtGui/qpalette.h>
36#include <QtGui/qguiapplication.h>
37#include <QtGui/qpainter.h>
38#include <QtGui/qpixmapcache.h>
39#include <qpa/qwindowsysteminterface.h>
40#include <QtGui/private/qabstractfileiconengine_p.h>
41#include <QtGui/private/qwindowsfontdatabase_p.h>
42#include <private/qhighdpiscaling_p.h>
43#include <private/qwinregistry_p.h>
44#include <QtCore/private/qfunctions_win_p.h>
45#include <QtGui/private/qwindowsthemecache_p.h>
49#if QT_CONFIG(cpp_winrt)
50# include <QtCore/private/qt_winrtbase_p.h>
52# include <winrt/Windows.UI.ViewManagement.h>
57using namespace Qt::StringLiterals;
62 if (SystemParametersInfo(what, 0, &result, 0))
63 return result != FALSE;
70 if (SystemParametersInfo(what, 0, &result, 0))
77 return {(c1.red() + c2.red()) / 2,
78 (c1.green() + c2.green()) / 2,
79 (c1.blue() + c2.blue()) / 2};
92#if QT_CONFIG(cpp_winrt)
93static constexpr QColor getSysColor(winrt::Windows::UI::Color &&color)
95 return QColor(color.R, color.G, color.B, color.A);
101 COLORREF cr = GetSysColor(index);
102 return QColor(GetRValue(cr), GetGValue(cr), GetBValue(cr));
109 QColor accentLighter;
110 QColor accentLightest;
113 QColor accentDarkest;
115#if QT_CONFIG(cpp_winrt)
117 using namespace winrt::Windows::UI::ViewManagement;
118 const auto settings = UISettings();
119 accent = getSysColor(settings.GetColorValue(UIColorType::Accent));
120 accentLight = getSysColor(settings.GetColorValue(UIColorType::AccentLight1));
121 accentLighter = getSysColor(settings.GetColorValue(UIColorType::AccentLight2));
122 accentLightest = getSysColor(settings.GetColorValue(UIColorType::AccentLight3));
123 accentDark = getSysColor(settings.GetColorValue(UIColorType::AccentDark1));
124 accentDarker = getSysColor(settings.GetColorValue(UIColorType::AccentDark2));
125 accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3));
131 if (!accent.isValid()) {
132 accent = []()->QColor {
135 if (QWindowsTheme::queryHighContrast())
136 return getSysColor(COLOR_HIGHLIGHT);
137 const QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)");
138 if (!registry.isValid())
140 const QVariant value = registry.value(L"AccentColor");
141 if (!value.isValid())
145 const QColor abgr = QColor::fromRgba(qvariant_cast<DWORD>(value));
148 return QColor::fromRgb(abgr.blue(), abgr.green(), abgr.red(), abgr.alpha());
150 if (!accent.isValid())
152 accentLight = accent.lighter(120);
153 accentLighter = accentLight.lighter(120);
154 accentLightest = accentLighter.lighter(120);
155 accentDark = accent.darker(120);
156 accentDarker = accentDark.darker(120);
157 accentDarkest = accentDarker.darker(120);
162 return accentDarkest;
170 return accentLighter;
172 return accentLightest;
186 Task(
const QString &fn, DWORD a, UINT f)
203 bool resultValid()
const {
return hIcon != 0 && iIcon >= 0 && finished; }
220 QMutexLocker l(&m_waitForTaskMutex);
221 while (!isInterruptionRequested()) {
222 if (!m_taskQueue.isEmpty())
223 return m_taskQueue.dequeue();
224 m_waitForTaskCondition.wait(&m_waitForTaskMutex);
231 QComHelper comHelper(COINIT_MULTITHREADED);
233 while (!isInterruptionRequested()) {
234 auto task = getNextTask();
237 const bool result = SHGetFileInfo(
reinterpret_cast<
const wchar_t *>(task->fileName.utf16()),
238 task->attributes, &info,
sizeof(SHFILEINFO),
241 task->hIcon = info.hIcon;
242 task->iIcon = info.iIcon;
244 task->finished =
true;
245 m_doneCondition.wakeAll();
254 QMutexLocker l(&m_waitForTaskMutex);
255 m_taskQueue.enqueue(task);
256 m_waitForTaskCondition.wakeAll();
259 QMutexLocker doneLocker(&m_doneMutex);
260 while (!task->finished && !isInterruptionRequested()) {
261 if (!m_doneCondition.wait(&m_doneMutex, QDeadlineTimer(timeout)))
268 requestInterruption();
269 m_doneCondition.wakeAll();
270 m_waitForTaskCondition.wakeAll();
274 QQueue<QSharedPointer<Task>> m_taskQueue;
275 QWaitCondition m_doneCondition;
276 QWaitCondition m_waitForTaskCondition;
278 QMutex m_waitForTaskMutex;
285 QColor backgroundColor(0xd4, 0xd0, 0xc8);
286 QColor lightColor(backgroundColor.lighter());
287 QColor darkColor(backgroundColor.darker());
288 const QBrush darkBrush(darkColor);
289 QColor midColor(Qt::gray);
290 QPalette palette(Qt::black, backgroundColor, lightColor, darkColor,
291 midColor, Qt::black, Qt::white);
292 palette.setBrush(QPalette::Disabled, QPalette::WindowText, darkBrush);
293 palette.setBrush(QPalette::Disabled, QPalette::Text, darkBrush);
294 palette.setBrush(QPalette::Disabled, QPalette::ButtonText, darkBrush);
295 palette.setBrush(QPalette::Disabled, QPalette::Base, QBrush(backgroundColor));
301 textColor.setAlpha(128);
306
307
308
309void QWindowsTheme::populateLightSystemBasePalette(QPalette &result)
313 const QColor background = getSysColor(COLOR_BTNFACE);
314 const QColor textColor = getSysColor(COLOR_WINDOWTEXT);
316 const QColor accent = qt_accentColor(AccentColorNormal);
317 const QColor accentDark = qt_accentColor(AccentColorDark);
318 const QColor accentDarker = qt_accentColor(AccentColorDarker);
319 const QColor accentDarkest = qt_accentColor(AccentColorDarkest);
321 const QColor linkColor = highContrastEnabled ? getSysColor(COLOR_HOTLIGHT) : accentDarker;
322 const QColor linkColorVisited = highContrastEnabled ? linkColor.darker(120) : accentDarkest;
323 const QColor btnFace = background;
324 const QColor btnHighlight = getSysColor(COLOR_BTNHIGHLIGHT);
326 result.setColor(QPalette::Highlight, accent);
327 result.setColor(QPalette::WindowText, getSysColor(COLOR_WINDOWTEXT));
328 result.setColor(QPalette::Button, btnFace);
329 result.setColor(QPalette::Light, btnHighlight);
330 result.setColor(QPalette::Dark, getSysColor(COLOR_BTNSHADOW));
331 result.setColor(QPalette::Mid, result.button().color().darker(150));
332 result.setColor(QPalette::Text, textColor);
333 result.setColor(QPalette::PlaceholderText, placeHolderColor(textColor));
334 result.setColor(QPalette::BrightText, btnHighlight);
335 result.setColor(QPalette::Base, getSysColor(COLOR_WINDOW));
336 result.setColor(QPalette::Window, highContrastEnabled ? getSysColor(COLOR_WINDOW) : btnFace);
337 result.setColor(QPalette::ButtonText, getSysColor(COLOR_BTNTEXT));
338 result.setColor(QPalette::Midlight, getSysColor(COLOR_3DLIGHT));
339 result.setColor(QPalette::Shadow, getSysColor(COLOR_3DDKSHADOW));
340 result.setColor(QPalette::HighlightedText, getSysColor(COLOR_HIGHLIGHTTEXT));
341 result.setColor(QPalette::Accent, accentDark);
343 result.setColor(QPalette::Link, linkColor);
344 result.setColor(QPalette::LinkVisited, linkColorVisited);
345 result.setColor(QPalette::Inactive, QPalette::Button, result.button().color());
346 result.setColor(QPalette::Inactive, QPalette::Window, result.window().color());
347 result.setColor(QPalette::Inactive, QPalette::Light, result.light().color());
348 result.setColor(QPalette::Inactive, QPalette::Dark, result.dark().color());
350 if (highContrastEnabled)
351 result.setColor(QPalette::Inactive, QPalette::WindowText, getSysColor(COLOR_GRAYTEXT));
353 if (result.midlight() == result.button())
354 result.setColor(QPalette::Midlight, result.button().color().lighter(110));
357void QWindowsTheme::populateDarkSystemBasePalette(QPalette &result)
361#if QT_CONFIG(cpp_winrt)
365 if (QWindowsTheme::queryColorScheme() == Qt::ColorScheme::Dark) {
367 using namespace winrt::Windows::UI::ViewManagement;
368 const auto settings = UISettings();
370 foreground = getSysColor(settings.GetColorValue(UIColorType::Foreground));
371 background = [&settings]() -> QColor {
372 auto systemBackground = getSysColor(settings.GetColorValue(UIColorType::Background));
373 if (systemBackground == Qt::black)
374 systemBackground = QColor(0x1E, 0x1E, 0x1E);
375 return systemBackground;
382 if (!background.isValid()) {
384 foreground = Qt::white;
385 background = QColor(0x1E, 0x1E, 0x1E);
388 const QColor accent = qt_accentColor(AccentColorNormal);
389 const QColor accentDarkest = qt_accentColor(AccentColorDarkest);
390 const QColor accentLighter = qt_accentColor(AccentColorLighter);
391 const QColor accentLightest = qt_accentColor(AccentColorLightest);
392 const QColor linkColor = accentLightest;
393 const QColor buttonColor = background.lighter(200);
395 result.setColor(QPalette::All, QPalette::WindowText, foreground);
396 result.setColor(QPalette::All, QPalette::Text, foreground);
397 result.setColor(QPalette::All, QPalette::BrightText, accentLightest);
399 result.setColor(QPalette::All, QPalette::Button, buttonColor);
400 result.setColor(QPalette::All, QPalette::ButtonText, foreground);
401 result.setColor(QPalette::All, QPalette::Light, buttonColor.lighter(200));
402 result.setColor(QPalette::All, QPalette::Midlight, buttonColor.lighter(150));
403 result.setColor(QPalette::All, QPalette::Dark, buttonColor.darker(200));
404 result.setColor(QPalette::All, QPalette::Mid, buttonColor.darker(150));
405 result.setColor(QPalette::All, QPalette::Shadow, Qt::black);
407 result.setColor(QPalette::All, QPalette::Base, background.lighter(150));
408 result.setColor(QPalette::All, QPalette::Window, background);
410 result.setColor(QPalette::All, QPalette::Highlight, accent);
411 result.setColor(QPalette::All, QPalette::HighlightedText, accent.lightness() > 128 ? Qt::black : Qt::white);
412 result.setColor(QPalette::All, QPalette::Link, linkColor);
413 result.setColor(QPalette::All, QPalette::LinkVisited, accentLighter);
414 result.setColor(QPalette::All, QPalette::AlternateBase, accentDarkest);
415 result.setColor(QPalette::All, QPalette::ToolTipBase, buttonColor);
416 result.setColor(QPalette::All, QPalette::ToolTipText, foreground.darker(120));
417 result.setColor(QPalette::All, QPalette::PlaceholderText, placeHolderColor(foreground));
418 result.setColor(QPalette::All, QPalette::Accent, accentLighter);
423 QPalette result(systemPalette);
424 static const bool isWindows11 = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11;
425 const QColor tipBgColor = highContrastEnabled ? (isWindows11 ? getSysColor(COLOR_WINDOW) : getSysColor(COLOR_BTNFACE)) :
426 (light ? getSysColor(COLOR_INFOBK) : systemPalette.button().color());
427 const QColor tipTextColor = highContrastEnabled ? (isWindows11 ? getSysColor(COLOR_WINDOWTEXT) : getSysColor(COLOR_BTNTEXT)) :
428 (light ? getSysColor(COLOR_INFOTEXT) : systemPalette.buttonText().color().darker(120));
430 result.setColor(QPalette::All, QPalette::Button, tipBgColor);
431 result.setColor(QPalette::All, QPalette::Window, tipBgColor);
432 result.setColor(QPalette::All, QPalette::Text, tipTextColor);
433 result.setColor(QPalette::All, QPalette::WindowText, tipTextColor);
434 result.setColor(QPalette::All, QPalette::ButtonText, tipTextColor);
435 result.setColor(QPalette::All, QPalette::Button, tipBgColor);
436 result.setColor(QPalette::All, QPalette::Window, tipBgColor);
437 result.setColor(QPalette::All, QPalette::Text, tipTextColor);
438 result.setColor(QPalette::All, QPalette::WindowText, tipTextColor);
439 result.setColor(QPalette::All, QPalette::ButtonText, tipTextColor);
440 result.setColor(QPalette::All, QPalette::ToolTipBase, tipBgColor);
441 result.setColor(QPalette::All, QPalette::ToolTipText, tipTextColor);
442 const QColor disabled = mixColors(result.windowText().color(), result.button().color());
443 result.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
444 result.setColor(QPalette::Disabled, QPalette::Text, disabled);
445 result.setColor(QPalette::Disabled, QPalette::ToolTipText, disabled);
446 result.setColor(QPalette::Disabled, QPalette::Base, Qt::white);
447 result.setColor(QPalette::Disabled, QPalette::BrightText, Qt::white);
448 result.setColor(QPalette::Disabled, QPalette::ToolTipBase, Qt::white);
455 return systemPalette;
457 QPalette result(systemPalette);
458 const QColor menuColor = getSysColor(COLOR_MENU);
459 const QColor menuTextColor = getSysColor(COLOR_MENUTEXT);
460 const QColor disabled = getSysColor(COLOR_GRAYTEXT);
462 result.setColor(QPalette::Active, QPalette::Button, menuColor);
463 result.setColor(QPalette::Active, QPalette::Text, menuTextColor);
464 result.setColor(QPalette::Active, QPalette::WindowText, menuTextColor);
465 result.setColor(QPalette::Active, QPalette::ButtonText, menuTextColor);
466 result.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
467 result.setColor(QPalette::Disabled, QPalette::Text, disabled);
468 const bool isFlat = booleanSystemParametersInfo(SPI_GETFLATMENU,
false);
469 const QColor highlightColor = getSysColor(isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT);
470 result.setColor(QPalette::Disabled, QPalette::Highlight, highlightColor);
471 result.setColor(QPalette::Disabled, QPalette::HighlightedText, disabled);
472 result.setColor(QPalette::Disabled, QPalette::Button,
473 result.color(QPalette::Active, QPalette::Button));
474 result.setColor(QPalette::Inactive, QPalette::Button,
475 result.color(QPalette::Active, QPalette::Button));
476 result.setColor(QPalette::Inactive, QPalette::Text,
477 result.color(QPalette::Active, QPalette::Text));
478 result.setColor(QPalette::Inactive, QPalette::WindowText,
479 result.color(QPalette::Active, QPalette::WindowText));
480 result.setColor(QPalette::Inactive, QPalette::ButtonText,
481 result.color(QPalette::Active, QPalette::ButtonText));
482 result.setColor(QPalette::Inactive, QPalette::Highlight,
483 result.color(QPalette::Active, QPalette::Highlight));
484 result.setColor(QPalette::Inactive, QPalette::HighlightedText,
485 result.color(QPalette::Active, QPalette::HighlightedText));
486 result.setColor(QPalette::Inactive, QPalette::ButtonText,
487 systemPalette.color(QPalette::Inactive, QPalette::Dark));
493 QPalette *result =
nullptr;
494 if (!light || !booleanSystemParametersInfo(SPI_GETFLATMENU,
false))
497 result =
new QPalette(menuPalette);
498 const QColor menubar(getSysColor(COLOR_MENUBAR));
499 result->setColor(QPalette::Active, QPalette::Button, menubar);
500 result->setColor(QPalette::Disabled, QPalette::Button, menubar);
501 result->setColor(QPalette::Inactive, QPalette::Button, menubar);
508LRESULT QT_WIN_CALLBACK qThemeChangeObserverWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
511 case WM_SETTINGCHANGE:
513 if (!((wParam == 0) && (lParam != 0)
514 && (wcscmp(
reinterpret_cast<LPCWSTR>(lParam), L"ImmersiveColorSet") == 0)))
517 case WM_THEMECHANGED:
520 qCDebug(lcQpaTheme) <<
"Handling theme change due to"
521 << qUtf8Printable(decodeMSG(MSG{hwnd, message, wParam, lParam, 0, {0, 0}}).trimmed());
522 QWindowsTheme::handleThemeChange();
525 while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE));
538 return DefWindowProc(hwnd, message, wParam, lParam);
544 s_colorScheme = Qt::ColorScheme::Unknown;
545 s_colorScheme = QWindowsTheme::effectiveColorScheme();
546 std::fill(m_fonts, m_fonts + NFonts,
nullptr);
547 std::fill(m_palettes, m_palettes + NPalettes,
nullptr);
549 refreshIconPixmapSizes();
552 "ThemeChangeObserverWindow"_L1,
553 qThemeChangeObserverWndProc);
556 m_themeChangeObserver = CreateWindowEx(0,
reinterpret_cast<LPCWSTR>(className.utf16()),
557 nullptr, WS_TILED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
558 nullptr,
nullptr, GetModuleHandle(
nullptr),
nullptr);
559 Q_ASSERT(m_themeChangeObserver);
566 m_instance =
nullptr;
571 qCDebug(lcQpaTheme) <<
"Destroying theme change window";
572 DestroyWindow(m_themeChangeObserver);
573 m_themeChangeObserver =
nullptr;
578 const QFileInfo appDir(QCoreApplication::applicationDirPath() +
"/icons"_L1);
579 return appDir.isDir() ? QStringList(appDir.absoluteFilePath()) : QStringList();
584 QStringList styles = { QStringLiteral(
"WindowsVista"), QStringLiteral(
"Windows") };
585 if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11)
586 styles.prepend(QStringLiteral(
"Windows11"));
592 int result = QPlatformTheme::HoverEffect;
593 if (booleanSystemParametersInfo(SPI_GETUIEFFECTS,
false))
594 result |= QPlatformTheme::GeneralUiEffect;
595 if (booleanSystemParametersInfo(SPI_GETMENUANIMATION,
false))
596 result |= QPlatformTheme::AnimateMenuUiEffect;
597 if (booleanSystemParametersInfo(SPI_GETMENUFADE,
false))
598 result |= QPlatformTheme::FadeMenuUiEffect;
599 if (booleanSystemParametersInfo(SPI_GETCOMBOBOXANIMATION,
false))
600 result |= QPlatformTheme::AnimateComboUiEffect;
601 if (booleanSystemParametersInfo(SPI_GETTOOLTIPANIMATION,
false))
602 result |= QPlatformTheme::AnimateTooltipUiEffect;
609 case UseFullScreenForPopupMenu:
610 return QVariant(
true);
611 case DialogButtonBoxLayout:
612 return QVariant(QPlatformDialogHelper::WinLayout);
613 case IconThemeSearchPaths:
614 return QVariant(iconThemeSearchPaths());
616 return QVariant(styleNames());
617 case TextCursorWidth:
618 return QVariant(
int(dWordSystemParametersInfo(SPI_GETCARETWIDTH, 1u)));
620 return QVariant(booleanSystemParametersInfo(SPI_GETDROPSHADOW,
false));
621 case MaximumScrollBarDragDistance:
624 return QVariant(
int(WindowsKeyboardScheme));
627 case IconPixmapSizes:
628 return QVariant::fromValue(m_fileIconSizes);
629 case DialogSnapToDefaultButton:
630 return QVariant(booleanSystemParametersInfo(SPI_GETSNAPTODEFBUTTON,
false));
631 case ContextMenuOnMouseRelease:
632 return QVariant(
true);
633 case WheelScrollLines: {
635 const DWORD scrollLines = dWordSystemParametersInfo(SPI_GETWHEELSCROLLLINES, DWORD(result));
636 if (scrollLines != DWORD(-1))
637 result =
int(scrollLines);
638 return QVariant(result);
640 case MouseDoubleClickDistance:
641 return GetSystemMetrics(SM_CXDOUBLECLK);
642 case MenuBarFocusOnAltPressRelease:
647 return QPlatformTheme::themeHint(hint);
652 return QWindowsTheme::effectiveColorScheme();
658 if (queryHighContrast())
659 return Qt::ColorScheme::Unknown;
660 if (s_colorSchemeOverride != Qt::ColorScheme::Unknown)
661 return s_colorSchemeOverride;
662 if (s_colorScheme != Qt::ColorScheme::Unknown)
663 return s_colorScheme;
664 if (!integration->darkModeHandling().testFlag(QWindowsApplication::DarkModeStyle))
665 return Qt::ColorScheme::Light;
666 return queryColorScheme();
671 s_colorSchemeOverride = scheme;
677 return queryHighContrast() ? Qt::ContrastPreference::HighContrast
678 : Qt::ContrastPreference::NoPreference;
687 QWindowsThemeCache::clearAllThemeCaches();
689 const auto oldColorScheme = s_colorScheme;
690 s_colorScheme = Qt::ColorScheme::Unknown;
691 s_colorScheme = effectiveColorScheme();
692 if (s_colorScheme != oldColorScheme) {
696 for (QWindowsWindow *w : std::as_const(QWindowsContext::instance()->windows()))
697 w->setDarkBorder(s_colorScheme == Qt::ColorScheme::Dark);
704 QWindowSystemInterface::handleThemeChange<QWindowSystemInterface::SynchronousDelivery>();
709 qDeleteAll(m_palettes, m_palettes + NPalettes);
710 std::fill(m_palettes, m_palettes + NPalettes,
nullptr);
715 if (!QGuiApplication::desktopSettingsAware())
718 effectiveColorScheme() != Qt::ColorScheme::Dark
719 || !QWindowsIntegration::instance()->darkModeHandling().testFlag(QWindowsApplication::DarkModeStyle);
721 m_palettes[SystemPalette] =
new QPalette(QWindowsTheme::systemPalette(s_colorScheme));
722 m_palettes[ToolTipPalette] =
new QPalette(toolTipPalette(*m_palettes[SystemPalette], light, queryHighContrast()));
723 m_palettes[MenuPalette] =
new QPalette(menuPalette(*m_palettes[SystemPalette], light));
724 m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette], light);
726 m_palettes[CheckBoxPalette] =
new QPalette(*m_palettes[SystemPalette]);
727 m_palettes[CheckBoxPalette]->setColor(QPalette::Active, QPalette::Base, qt_accentColor(AccentColorNormal));
728 m_palettes[CheckBoxPalette]->setColor(QPalette::Active, QPalette::Button, qt_accentColor(AccentColorLighter));
729 m_palettes[CheckBoxPalette]->setColor(QPalette::Inactive, QPalette::Base, qt_accentColor(AccentColorDarkest));
730 m_palettes[RadioButtonPalette] =
new QPalette(*m_palettes[CheckBoxPalette]);
736 QPalette result = standardPalette();
738 switch (colorScheme) {
739 case Qt::ColorScheme::Unknown:
742 case Qt::ColorScheme::Light:
743 populateLightSystemBasePalette(result);
745 case Qt::ColorScheme::Dark:
746 populateDarkSystemBasePalette(result);
750 if (result.window() != result.base()) {
751 result.setColor(QPalette::Inactive, QPalette::Highlight,
752 result.color(QPalette::Inactive, QPalette::Window));
753 result.setColor(QPalette::Inactive, QPalette::HighlightedText,
754 result.color(QPalette::Inactive, QPalette::Text));
755 result.setColor(QPalette::Inactive, QPalette::Accent,
756 result.color(QPalette::Inactive, QPalette::Window));
759 const QColor disabled = mixColors(result.windowText().color(), result.button().color());
761 result.setColorGroup(QPalette::Disabled, result.windowText(), result.button(),
762 result.light(), result.dark(), result.mid(),
763 result.text(), result.brightText(), result.base(),
766 const bool highContrastEnabled = queryHighContrast();
767 const QColor disabledTextColor = highContrastEnabled ? getSysColor(COLOR_GRAYTEXT) : disabled;
768 result.setColor(QPalette::Disabled, QPalette::WindowText, disabledTextColor);
769 result.setColor(QPalette::Disabled, QPalette::Text, disabledTextColor);
770 result.setColor(QPalette::Disabled, QPalette::ButtonText, disabledTextColor);
771 if (highContrastEnabled)
772 result.setColor(QPalette::Disabled, QPalette::Button, result.button().color().darker(150));
774 result.setColor(QPalette::Disabled, QPalette::Highlight, result.color(QPalette::Highlight));
775 result.setColor(QPalette::Disabled, QPalette::HighlightedText, result.color(QPalette::HighlightedText));
776 result.setColor(QPalette::Disabled, QPalette::Accent, disabled);
777 result.setColor(QPalette::Disabled, QPalette::Base, result.window().color());
783 qDeleteAll(m_fonts, m_fonts + NFonts);
784 std::fill(m_fonts, m_fonts + NFonts,
nullptr);
793#ifndef QT_NO_DEBUG_STREAM
794QDebug operator<<(QDebug d,
const NONCLIENTMETRICS &m)
796 QDebugStateSaver saver(d);
799 d <<
"NONCLIENTMETRICS(iMenu=" << m.iMenuWidth <<
'x' << m.iMenuHeight
800 <<
", lfCaptionFont=";
801 QWindowsFontDatabase::debugFormat(d, m.lfCaptionFont);
802 d <<
", lfSmCaptionFont=";
803 QWindowsFontDatabase::debugFormat(d, m.lfSmCaptionFont);
804 d <<
", lfMenuFont=";
805 QWindowsFontDatabase::debugFormat(d, m.lfMenuFont);
806 d <<
", lfMessageFont=";
807 QWindowsFontDatabase::debugFormat(d, m.lfMessageFont);
808 d <<
", lfStatusFont=";
809 QWindowsFontDatabase::debugFormat(d, m.lfStatusFont);
818 if (!QGuiApplication::desktopSettingsAware())
822 NONCLIENTMETRICS ncm;
823 QWindowsContext::nonClientMetrics(&ncm, dpi);
824 qCDebug(lcQpaWindow) <<
__FUNCTION__ << ncm;
826 const QFont menuFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMenuFont, dpi);
827 const QFont messageBoxFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont, dpi);
828 const QFont statusFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfStatusFont, dpi);
829 const QFont titleFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfCaptionFont, dpi);
830 QFont fixedFont(QStringLiteral(
"Courier New"), messageBoxFont.pointSize());
831 fixedFont.setStyleHint(QFont::TypeWriter);
833 LOGFONT lfIconTitleFont;
834 SystemParametersInfoForDpi(SPI_GETICONTITLELOGFONT,
sizeof(lfIconTitleFont), &lfIconTitleFont, 0, dpi);
835 const QFont iconTitleFont = QWindowsFontDatabase::LOGFONT_to_QFont(lfIconTitleFont, dpi);
837 m_fonts[SystemFont] =
new QFont(QWindowsFontDatabase::systemDefaultFont());
838 m_fonts[MenuFont] =
new QFont(menuFont);
839 m_fonts[MenuBarFont] =
new QFont(menuFont);
840 m_fonts[MessageBoxFont] =
new QFont(messageBoxFont);
841 m_fonts[TipLabelFont] =
new QFont(statusFont);
842 m_fonts[StatusBarFont] =
new QFont(statusFont);
843 m_fonts[MdiSubWindowTitleFont] =
new QFont(titleFont);
844 m_fonts[DockWidgetTitleFont] =
new QFont(titleFont);
845 m_fonts[ItemViewFont] =
new QFont(iconTitleFont);
846 m_fonts[FixedFont] =
new QFont(fixedFont);
860 return QWindowsDialogs::useHelper(type);
865 return QWindowsDialogs::createHelper(type);
868#if QT_CONFIG(systemtrayicon)
869QPlatformSystemTrayIcon *QWindowsTheme::createPlatformSystemTrayIcon()
const
871 return new QWindowsSystemTrayIcon;
887 m_fileIconSizes = QAbstractFileIconEngine::toSizeList(fileIconSizes, availEnd);
888 qCDebug(lcQpaWindow) <<
__FUNCTION__ << m_fileIconSizes;
896 HMODULE shell32 = ::GetModuleHandleW(L"shell32.dll");
899 static_cast<HICON>(LoadImage(shell32, MAKEINTRESOURCE(resourceId),
900 IMAGE_ICON,
int(size.width()),
int(size.height()), 0));
902 QPixmap iconpixmap = qt_pixmapFromWinHICON(iconHandle);
903 DestroyIcon(iconHandle);
912 SHSTOCKICONID stockId = SIID_INVALID;
913 LPCTSTR iconName =
nullptr;
916 stockId = SIID_DRIVECD;
920 stockId = SIID_DRIVEDVD;
924 stockId = SIID_DRIVENET;
928 stockId = SIID_DRIVEFIXED;
932 stockId = SIID_DRIVE35;
938 stockId = SIID_DOCNOASSOC;
945 stockId = SIID_FOLDER;
954 case DirLinkOpenIcon:
957 stockId = SIID_FOLDEROPEN;
960 case FileDialogNewFolder:
961 stockId = SIID_FOLDER;
968 stockId = SIID_RECYCLER;
971 case MessageBoxInformation:
973 iconName = IDI_INFORMATION;
975 case MessageBoxWarning:
976 stockId = SIID_WARNING;
977 iconName = IDI_WARNING;
979 case MessageBoxCritical:
980 stockId = SIID_ERROR;
981 iconName = IDI_ERROR;
983 case MessageBoxQuestion:
985 iconName = IDI_QUESTION;
988 stockId = SIID_SHIELD;
996 const auto drawLinkOverlayIconIfNeeded = [](StandardPixmap sp, QPixmap &pixmap, QSizeF pixmapSize) {
997 if (sp == FileLinkIcon || sp == DirLinkIcon || sp == DirLinkOpenIcon) {
998 QPainter painter(&pixmap);
999 const QSizeF linkSize = pixmapSize / (pixmapSize.height() >= 48 ? 3 : 2);
1000 static constexpr auto LinkOverlayIconId = 16769;
1001 const QPixmap link = loadIconFromShell32(LinkOverlayIconId, linkSize.toSize());
1002 const int yPos = pixmap.height() - link.size().height();
1003 painter.drawPixmap(0, yPos,
int(linkSize.width()),
int(linkSize.height()), link);
1007 if (stockId != SIID_INVALID) {
1008 SHSTOCKICONINFO iconInfo;
1009 memset(&iconInfo, 0,
sizeof(iconInfo));
1010 iconInfo.cbSize =
sizeof(iconInfo);
1011 constexpr UINT stockFlags = SHGSI_ICONLOCATION;
1012 if (SHGetStockIconInfo(stockId, stockFlags, &iconInfo) == S_OK) {
1013 const auto iconSize = pixmapSize.width();
1015 if (SHDefExtractIcon(iconInfo.szPath, iconInfo.iIcon, 0, &icon,
nullptr, iconSize) == S_OK) {
1016 QPixmap pixmap = qt_pixmapFromWinHICON(icon);
1018 if (!pixmap.isNull()) {
1019 drawLinkOverlayIconIfNeeded(sp, pixmap, pixmap.size());
1026 if (resourceId != -1) {
1027 QPixmap pixmap = loadIconFromShell32(resourceId, pixmapSize);
1028 if (!pixmap.isNull()) {
1029 drawLinkOverlayIconIfNeeded(sp, pixmap, pixmapSize);
1035 HICON iconHandle = LoadIcon(
nullptr, iconName);
1036 QPixmap pixmap = qt_pixmapFromWinHICON(iconHandle);
1037 DestroyIcon(iconHandle);
1038 if (!pixmap.isNull())
1042 return QPlatformTheme::standardPixmap(sp, pixmapSize);
1052 QString key =
"qt_dir_"_L1 + QString::number(iIcon);
1053 if (iconSize == SHGFI_LARGEICON)
1055 switch (imageListSize) {
1066template <
typename T>
1071 static_assert(
sizeof(T) <=
sizeof(
void *),
"FakePointers can only go that far.");
1075 return reinterpret_cast<
FakePointer *>(qintptr(thing));
1080 return T(qintptr(
this));
1092 static const IID iID_IImageList = {0x46eb5926, 0x582e, 0x4017, {0x9f, 0xdf, 0xe8, 0x99, 0x8d, 0xaa, 0x9, 0x50}};
1094 IImageList *imageList =
nullptr;
1095 HRESULT hr = SHGetImageList(iImageList, iID_IImageList,
reinterpret_cast<
void **>(&imageList));
1099 hr = imageList->GetIcon(iIcon, ILD_TRANSPARENT, &hIcon);
1101 result = qt_pixmapFromWinHICON(hIcon);
1104 imageList->Release();
1125 if ((options() & QPlatformTheme::DontUseCustomDirectoryIcons) && fileInfo().isDir() && !fileInfo().isRoot())
1126 return QStringLiteral(
"qt_/directory/");
1127 if (!fileInfo().isFile())
1132 QString suffix = fileInfo().suffix();
1133 if (!suffix.compare(u"exe", Qt::CaseInsensitive)
1134 || !suffix.compare(u"lnk", Qt::CaseInsensitive)
1135 || !suffix.compare(u"ico", Qt::CaseInsensitive)) {
1139 + (suffix.isEmpty() ? fileInfo().fileName() : std::move(suffix).toUpper());
1144 QComHelper comHelper;
1146 static QCache<QString, FakePointer<
int> > dirIconEntryCache(1000);
1147 Q_CONSTINIT
static QMutex mx;
1148 static int defaultFolderIIcon = -1;
1149 const bool useDefaultFolderIcon = options() & QPlatformTheme::DontUseCustomDirectoryIcons;
1152 const QString filePath = QDir::toNativeSeparators(fileInfo().filePath());
1153 const int width =
int(size.width());
1154 const int iconSize = width > fileIconSizes[SmallFileIcon] ? SHGFI_LARGEICON : SHGFI_SMALLICON;
1155 const int requestedImageListSize =
1159 bool cacheableDirIcon = fileInfo().isDir() && !fileInfo().isRoot();
1160 if (cacheableDirIcon) {
1161 QMutexLocker locker(&mx);
1162 int iIcon = (useDefaultFolderIcon && defaultFolderIIcon >= 0) ? defaultFolderIIcon
1163 : **dirIconEntryCache.object(filePath);
1165 QPixmapCache::find(dirIconPixmapCacheKey(iIcon, iconSize, requestedImageListSize),
1167 if (pixmap.isNull())
1168 dirIconEntryCache.remove(filePath);
1174 unsigned int flags = SHGFI_ICON | iconSize | SHGFI_SYSICONINDEX | SHGFI_ADDOVERLAYS | SHGFI_OVERLAYINDEX;
1175 DWORD attributes = 0;
1176 QString path = filePath;
1177 if (cacheableDirIcon && useDefaultFolderIcon) {
1178 flags |= SHGFI_USEFILEATTRIBUTES;
1179 attributes |= FILE_ATTRIBUTE_DIRECTORY;
1180 path = QStringLiteral(
"dummy");
1181 }
else if (!fileInfo().exists()) {
1182 flags |= SHGFI_USEFILEATTRIBUTES;
1183 attributes |= FILE_ATTRIBUTE_NORMAL;
1187 s_shGetFileInfoThread()->runWithParams(task);
1189 if (task->resultValid()) {
1191 if (cacheableDirIcon) {
1192 if (useDefaultFolderIcon && defaultFolderIIcon < 0)
1193 defaultFolderIIcon = task->iIcon;
1196 key = dirIconPixmapCacheKey(task->iIcon, iconSize, requestedImageListSize);
1197 QPixmapCache::find(key, &pixmap);
1198 if (!pixmap.isNull()) {
1199 QMutexLocker locker(&mx);
1200 dirIconEntryCache.insert(filePath, FakePointer<
int>::create(task->iIcon));
1204 if (pixmap.isNull()) {
1205 if (requestedImageListSize) {
1206 pixmap = pixmapFromShellImageList(requestedImageListSize, task->iIcon);
1207 if (pixmap.isNull() && requestedImageListSize == sHIL_JUMBO)
1208 pixmap = pixmapFromShellImageList(sHIL_EXTRALARGE, task->iIcon);
1210 if (pixmap.isNull())
1211 pixmap = qt_pixmapFromWinHICON(task->hIcon);
1212 if (!pixmap.isNull()) {
1213 if (cacheableDirIcon) {
1214 QMutexLocker locker(&mx);
1215 QPixmapCache::insert(key, pixmap);
1216 dirIconEntryCache.insert(filePath, FakePointer<
int>::create(task->iIcon));
1219 qWarning(
"QWindowsTheme::fileIconPixmap() no icon found");
1234 return new QWindowsIconEngine(iconName);
1240 if ((options & QWindowsIntegration::NoNativeMenus) != 0)
1242 if ((options & QWindowsIntegration::AlwaysUseNativeMenus) != 0)
1245 if (!QCoreApplication::instance()->inherits(
"QApplication"))
1247 const QWindowList &topLevels = QGuiApplication::topLevelWindows();
1248 for (
const QWindow *t : topLevels) {
1249 if (t->inherits(
"QQuickApplicationWindow"))
1263 if (queryHighContrast())
1264 return Qt::ColorScheme::Unknown;
1266 QWinRegistryKey personalizeKey{
1267 HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)"
1269 const bool useDarkTheme = personalizeKey.value<DWORD>(L"AppsUseLightTheme") == 0;
1270 return useDarkTheme ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light;
1275 HIGHCONTRAST hcf = {};
1276 hcf.cbSize =
static_cast<UINT>(
sizeof(HIGHCONTRAST));
1277 if (SystemParametersInfo(SPI_GETHIGHCONTRAST, hcf.cbSize, &hcf, FALSE))
1278 return hcf.dwFlags & HCF_HIGHCONTRASTON;
1284 qCDebug(lcQpaMenus) <<
__FUNCTION__;
1290 qCDebug(lcQpaMenus) <<
__FUNCTION__;
1300 qCDebug(lcQpaMenus) <<
__FUNCTION__;
1306 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
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)