package com.github.gilday.darkmode; import static com.github.gilday.darkmode.DarkModeDetector.isMacOsDarkMode; import static com.github.gilday.darkmode.DarkModeDetector.isWindowsDarkMode; import com.intellij.concurrency.JobScheduler; import com.intellij.ide.actions.QuickChangeLookAndFeel; import com.intellij.ide.ui.LafManager; import com.intellij.openapi.Disposable; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.SystemInfo; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import javax.swing.UIManager.LookAndFeelInfo; /** * Application component which sets IDEA's theme to Darcula when it detects that macOS is in Dark * Mode, and sets the theme to IntelliJ when it detects that macOS is not in Dark Mode. * * <p>Schedules a background job for polling macOS Dark Mode configuration and updating IDEA * configuration accordingly. */ public final class DarkModeSync implements Disposable { private final ScheduledFuture<?> scheduledFuture; private final LafManager lafManager; private final DarkModeSyncThemes themes; /** @param lafManager IDEA look-and-feel manager for getting and setting the current theme */ public DarkModeSync(final LafManager lafManager) { themes = ServiceManager.getService(DarkModeSyncThemes.class); this.lafManager = lafManager; // Checks if OS is Windows or MacOS if (!(SystemInfo.isMacOSMojave || SystemInfo.isWin10OrNewer)) { logger.error("Plugin only supports macOS Mojave and greater or Windows 10 and greater"); scheduledFuture = null; return; } ScheduledExecutorService executor = JobScheduler.getScheduler(); scheduledFuture = executor.scheduleWithFixedDelay(this::updateLafIfNecessary, 0, 3, TimeUnit.SECONDS); } /** cancels the scheduled task if one exists */ @Override public void dispose() { if (scheduledFuture != null) scheduledFuture.cancel(true); } private void updateLafIfNecessary() { final LookAndFeelInfo current = lafManager.getCurrentLookAndFeel(); final boolean isDarkMode; if (SystemInfo.isMacOSMojave) { isDarkMode = isMacOsDarkMode(); } else if (SystemInfo.isWin10OrNewer) { isDarkMode = isWindowsDarkMode(); } else { throw new IllegalStateException( "Plugin only works on MacOS Mojave and newer or Windows 10 and newer."); } final LookAndFeelInfo dark = themes.getDark(); final LookAndFeelInfo light = themes.getLight(); if (isDarkMode && !dark.equals(current)) { updateLaf(dark); } else if (!isDarkMode && !light.equals(current)) { updateLaf(light); } } private void updateLaf(final LookAndFeelInfo newLaf) { QuickChangeLookAndFeel.switchLafAndUpdateUI(lafManager, newLaf, true); } private static final Logger logger = Logger.getInstance(DarkModeSync.class); }