/*
 * MIT License
 *
 * Copyright (c) 2020 Jannis Weis
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.github.weisj.darklaf.platform.windows;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;

public class WindowsPreferenceMonitor {

    private static final Logger LOGGER = Logger.getLogger(WindowsThemePreferenceProvider.class.getName());

    private final WindowsThemePreferenceProvider preferenceProvider;
    private Thread worker;

    private boolean darkMode;
    private boolean highContrast;
    private long fontScaleFactor;
    private long eventHandle;
    private AtomicBoolean running = new AtomicBoolean(false);

    public WindowsPreferenceMonitor(final WindowsThemePreferenceProvider preferenceProvider) {
        this.preferenceProvider = preferenceProvider;
    }

    public void run() {
        LOGGER.info("Started preference monitoring.");
        while (running.get() && JNIThemeInfoWindows.waitPreferenceChange(eventHandle)) {
            boolean newDark = JNIThemeInfoWindows.isDarkThemeEnabled();
            boolean newHighContrast = JNIThemeInfoWindows.isHighContrastEnabled();
            long newFotScale = JNIThemeInfoWindows.getFontScaleFactor();
            if (darkMode != newDark || fontScaleFactor != newFotScale || highContrast != newHighContrast) {
                darkMode = newDark;
                fontScaleFactor = newFotScale;
                highContrast = newHighContrast;
                preferenceProvider.reportPreferenceChange(highContrast, darkMode, fontScaleFactor);
            }
        }
        if (running.get()) {
            LOGGER.severe("Monitor encountered an error. Stopping preference monitoring.");
            running.set(false);
        } else {
            LOGGER.info("Stopped preference monitoring.");
        }
    }

    public void setRunning(final boolean running) {
        if (running == this.running.get()) return;
        if (running) {
            darkMode = JNIThemeInfoWindows.isDarkThemeEnabled();
            highContrast = JNIThemeInfoWindows.isHighContrastEnabled();
            fontScaleFactor = JNIThemeInfoWindows.getFontScaleFactor();
            eventHandle = JNIThemeInfoWindows.createEventHandle();
            this.running.set(true);
            worker = new Thread(this::run);
            worker.start();
        } else {
            this.running.set(false);
            JNIThemeInfoWindows.notifyEventHandle(eventHandle);
        }
    }

    public boolean isRunning() {
        return running.get();
    }
}

@@ -2870,133 +2870,30 @@
    p
-ublic
+rivate
  void s
-etRunning(final boolean running) %7B%0A        if (running == this.running.get()) return;%0A        if (running) %7B%0A    
+tart() %7B%0A
     
@@ -2941,36 +2941,32 @@
 ThemeEnabled();%0A
-    
         highCont
@@ -3017,36 +3017,32 @@
 bled();%0A        
-    
 fontScaleFactor 
@@ -3077,36 +3077,32 @@
 tScaleFactor();%0A
-    
         eventHan
@@ -3148,36 +3148,256 @@
 ndle();%0A        
+/*%0A
     
+     * In theory this shouldn't be necessary, but%0A         * it ensures that the registry listeners are actually unregistered.%0A         */%0A        Runtime.getRuntime().addShutdownHook(new Thread(this::stop));%0A        
 this.running.set
@@ -3400,28 +3400,24 @@
 .set(true);%0A
-    
         work
@@ -3448,28 +3448,24 @@
 n);%0A        
-    
 worker.start
@@ -3468,34 +3468,50 @@
 tart();%0A    
+%7D%0A%0A
     
-%7D else
+private void stop()
  %7B%0A         
@@ -3505,28 +3505,24 @@
 ) %7B%0A        
- 
-   
 this.running
@@ -3530,28 +3530,24 @@
 set(false);%0A
-    
         JNIT
@@ -3590,24 +3590,215 @@
 entHandle);%0A
+    %7D%0A%0A    public void setRunning(final boolean running) %7B%0A        if (running == this.running.get()) return;%0A        if (running) %7B%0A            start();%0A        %7D else %7B%0A            stop();%0A
         %7D%0A  

Make sure preference listeners on windows are removed on shutdown.