How to react to dark mode change?

Hi folks,

I’m wondering if anyone has a good way to detect when the system changes from light to dark mode and back again while a program is running. The issue is that I have an application where I have some custom colors defined for text, backgrounds, etc. If the program is running and the system toggles from light to dark, everything that is default (presumably system colors) changes. However, all of my custom colors stay the same.

I know that I can use SystemAppearance to detect dark, and I can use that on startup to set my custom colors appropriately. However, if a user changes it while they’ve got the program open there’s no callback or anything like that, so at the moment the best I can come up with is do something like set a timer that checks to see if dark mode has changed every x seconds, then update my custom colors as appropriate. This is a hack, and I"m hoping there’s a better way to do it.

Does anyone has any thoughts on a better way to do this?


  • Jesse

The following code seems to work on Linux when I switch from a light theme to a dark theme and vice-versa:

import wx

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.SetSize((300, 200))
        self.SetTitle("Dark Mode Change")
        self.main_panel = wx.Panel(self, wx.ID_ANY)
        self.Bind(wx.EVT_SYS_COLOUR_CHANGED, self.OnColourChanged)

    def OnColourChanged(self, event):
        sys_appearance = wx.SystemSettings.GetAppearance()
        dark = sys_appearance.IsDark()
        print("dark = %s" % dark)

class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, wx.ID_ANY, "")
        return True

if __name__ == "__main__":
    app = MyApp(0)

Tested on Python 3.8.10 + wxPython 4.1.1 gtk3 (phoenix) wxWidgets 3.1.5 + Linux Mint 20.3

Thanks! I wasn’t aware of the GET_SYS_COLOUR_CHANGED event, and that’s exactly what I was looking for.