JFormDesigner / FlatLaf

FlatLaf - Swing Look and Feel (with Darcula/IntelliJ themes support)
https://www.formdev.com/flatlaf/
Apache License 2.0
3.38k stars 268 forks source link

Automatic switching between Dark and Light themes #204

Open bondolo opened 3 years ago

bondolo commented 3 years ago

Operating systems increasingly provide a setting for system-wide dark-light theme preference. This often accompanied by an option to switch based on local day-night cycle.

Adding to FlatLaF the ability to either dynamically or at launch follow the system preference for dark or light theme would be appreciated.

DevCharly commented 3 years ago

Yes, that would be definitely a nice to have feature 👍

PicoMitchell commented 3 years ago

I did something like this myself by checking the system color theme when the main window of my app is activated and updating the FlatLaf theme if the system theme has changed. I've included my example code.

Within this code, I call a custom CommandReader() method which just executes a command and can return the output in a variety of useful ways. There may be other ways to detect system color themes that I'm not aware of.

Also, my Linux system color theme detection is only made to work for Linux Mint's Cinnamon desktop environment since that's all my app supports. I haven't investigated theme detection for any other flavors of Linux.

Obviously, this will not update the app theme the instant the system theme is changed, but it will update it the next time the user goes back to the app. Also, obviously, I do these same checks on launch to set the correct initial FlatLaf theme.

If there is any better idea about how to update the FlatLaf theme dynamically to match the system theme whenever it changes, I would be very interest to hear about it!

mainWindow.addWindowListener(new WindowAdapter() {
    @Override
    public void windowActivated(WindowEvent windowEvent) {
        // This isn't very efficient (since it will get called excessively), but will help keep dark/light theme in sync with OS when changed.

        String currentLookAndFeelName = javax.swing.UIManager.getLookAndFeel().getName();
        if (currentLookAndFeelName.startsWith("FlatLaf")) {
            Boolean osIsDarkMode = false;

            if (isMacOS) {
                osIsDarkMode = new CommandReader("defaults read NSGlobalDomain AppleInterfaceStyle").getFirstOutputLine().toLowerCase().equals("dark");
            } else if (isLinux) {
                String cinnamonGtkThemeName = new CommandReader("gsettings get org.cinnamon.desktop.interface gtk-theme").getFirstOutputLine().toLowerCase();
                osIsDarkMode = (cinnamonGtkThemeName.contains("-dark") && !cinnamonGtkThemeName.contains("-darker"));
            } else if (isWindows) {
                osIsDarkMode = !new CommandReader("reg query HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize /v AppsUseLightTheme").getFirstOutputLineContaining("0x0").isEmpty();
            }

            if (osIsDarkMode != currentLookAndFeelName.endsWith(" Dark")) {
                try {
                    javax.swing.UIManager.setLookAndFeel((osIsDarkMode ? new com.formdev.flatlaf.FlatDarkLaf() : new com.formdev.flatlaf.FlatLightLaf()));
                    com.formdev.flatlaf.FlatLaf.updateUI();
                    // Now do other necessary stuff to make sure the UI get updated properly.
                } catch (UnsupportedLookAndFeelException updateFlatLafThemeException) {

                }
            }
        }
    }
});
TheKodeToad commented 3 years ago

For Gnome (and therefore Ubuntu) do gsettings get org.gnome.desktop.interface gtk-theme.

awecz commented 2 years ago

I guess you can gain some inspiration in https://github.com/Dansoftowner/jSystemThemeDetector.