In our Qt-based C++ application, I'm trying to automatically switch application styles based on whether the user has configured dark or bright theme.
I have figured out the notification of when a change happens (see below, for other's reference).
My main problem is the reliable detection of whether currently a dark or bright theme is used on linux (for windows see below); on XFCE, the check for QPalette color roles as mentioned in this answer works, but this does not work on Gnome and KDE Plasma for me (tested under both Ubuntu 22.04 and Fedora 36, my app built against Qt versions 6.5beta2 and 6.4.2, respectively); there the colors still seem to be taken from what I've set as XFCE theme on the same machine (and when starting xfce4-appearance-settings and changing the theme there, my app picks up the change). I would however like to adapt to the current desktop's dark mode setting.
So, my question is: How do I reliably detect application dark mode of the currently used desktop on Qt? I'm not averse to implementing a little custom platform-specific code if nothing is available directly in Qt, but it would be great if it would work without using additional libraries.
A note I saw for QApplication::setPalette I thought might be relevant here, namely "Some styles do not use the palette for all drawing, for instance, if they make use of native theme engines.", what are these all about? I did not see a link to a documentation for this feature, and a quick search for the term "qt native theme engine" also didn't seem to yield any useful results.
Since on Linux, some events are reliably triggered whenever a system theme change happens (see below), I suppose Qt can detect the theme change, it just doesn't expose data about it publicly?
On Linux: via listening for QEvent::StyleChange
events of the application's QMainWindow; two caveats and one side note:
QWidget::event
ThemeChange
event that is also triggered (at the same time as the StyleChange
; not sure what the difference is between these two though, and in what case one would be triggered but not the other... I suppose StyleChange
is used for any change to the style of a widget, so that it's also called when applying some style sheet settings, while ThemeChange
really indicates a change of the system theme? Though ThemeChange
seems to be considered a non-public Event type, at least it doesn't appear in the documentation (marked \omitvalue
)On Windows, via checking for changes to the registry key HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize
(the StyleChange
unfortunately isn't triggered there at all - a Qt bug?). .
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize\AppsUseLightTheme
(1 for bright, 0 for dark). This check is also done in Qt's plugins/platforms/windows/qwindowstheme (
queryDarkMode`), but I think this is not exposed publicly as generic interface anywhere?For those looking for a simple isDarkMode
function that works in Qt 6.4 and 6.5:
#include <QGuiApplication>
#include <QPalette>
#include <QStyleHints>
inline bool isDarkMode() {
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
const auto scheme = QGuiApplication::styleHints()->colorScheme();
return scheme == Qt::ColorScheme::Dark;
#else
const QPalette defaultPalette;
const auto text = defaultPalette.color(QPalette::WindowText);
const auto window = defaultPalette.color(QPalette::Window);
return text.lightness() > window.lightness();
#endif // QT_VERSION
}