All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dorkbox.jna.windows.WindowsEventDispatch Maven / Gradle / Ivy

/*
 * Copyright 2017 dorkbox, llc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package dorkbox.jna.windows;

import static com.sun.jna.platform.win32.WinDef.HWND;
import static com.sun.jna.platform.win32.WinDef.LPARAM;
import static com.sun.jna.platform.win32.WinDef.LRESULT;
import static com.sun.jna.platform.win32.WinDef.WPARAM;
import static com.sun.jna.platform.win32.WinUser.WM_QUIT;
import static dorkbox.jna.windows.User32.User32;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sun.jna.WString;
import com.sun.jna.platform.win32.WinUser;

@SuppressWarnings({"Convert2Lambda", "UnusedAssignment", "Convert2Diamond", "FieldCanBeLocal"})
public
class WindowsEventDispatch implements Runnable {
    private static final Logger logger = LoggerFactory.getLogger(WindowsEventDispatch.class);

    private static final String NAME = "WindowsEventDispatch";

    public static final int WM_TASKBARCREATED = User32.RegisterWindowMessage(new WString("TaskbarCreated"));
    public static final int WM_COMMAND = 0x0111;
    public static final int WM_SHELLNOTIFY = WinUser.WM_USER + 1;
    public static final int WM_MEASUREITEM = 44;
    public static final int WM_DRAWITEM = 43;

    public static final int MF_POPUP = 0x00000010;


    private static final WindowsEventDispatch edt = new WindowsEventDispatch();
    private final static Map> messageIDs = new HashMap>();

    private static final Object lock = new Object();
    private static int referenceCount = 0;


    private Thread dispatchThread;

    // keep these around to prevent GC
    private WNDPROC WndProc;

    // used to dispatch messages
    private volatile HWND hWnd;


    private
    WindowsEventDispatch() {
    }

    public static
    void start() {
        synchronized (lock) {
            int ref = referenceCount++;

            if (ref == 0) {
                edt.start_();
            }

            try {
                // wait for the dispatch thread to start
                lock.wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public static
    void stop() {
        synchronized (lock) {
            if (--referenceCount == 0) {
                edt.stop_();
            }
        }
    }

    public static
    HWND get() {
        return edt.hWnd;
    }

    // always from inside lock!
    private
    void start_() {
        dispatchThread = new Thread(this, NAME);
        dispatchThread.start();
    }

    // always from inside lock!
    private void
    stop_() {
        User32.SendMessage(hWnd, WM_QUIT, new WPARAM(0), new LPARAM(0));

        try {
            // wait for the dispatch thread to quit (but only if we are not on the dispatch thread)
            if (!Thread.currentThread().equals(dispatchThread)) {
                dispatchThread.join();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    @SuppressWarnings("Java8MapApi")
    public static
    void addListener(final int messageId, final Listener listener) {
        synchronized (messageIDs) {
            List listeners = messageIDs.get(messageId);
            if (listeners == null) {
                listeners = new ArrayList();
                messageIDs.put(messageId, listeners);
            }

            listeners.add(listener);
        }
    }
    public static
    void removeListener(final Listener listener) {
        synchronized (messageIDs) {
            for (Map.Entry> entry : messageIDs.entrySet()) {
                List value = entry.getValue();
                if (value.remove(listener)) {
                    return;
                }
            }
        }
    }

    @Override
    public
    void run() {
        WndProc = new WNDPROC() {
            @Override
            public
            LRESULT callback(HWND hWnd, int msg, WPARAM wParam, LPARAM lParam) {
                List listeners = null;
                synchronized (messageIDs) {
                    listeners = messageIDs.get(msg);
                    if (listeners != null) {
                        // make a copy, in case a listener action modifies the message listener
                        listeners = new ArrayList(listeners);
                    }
                }

                if (listeners != null) {
                    for (final Listener listener : listeners) {
                        if (listener != null) {
                            try {
                                listener.run(hWnd, wParam, lParam);
                            } catch (Exception e) {
                                logger.error("Error during listener execution.", e);
                            }
                        }
                    }
                }

                return User32.DefWindowProc(hWnd, msg, wParam, lParam);
            }
        };

        hWnd = User32.CreateWindowEx(0, "STATIC", NAME, 0, 0, 0, 0, 0, null, null, null,
                                            null);
        if (hWnd == null) {
            throw new GetLastErrorException();
        }

        User32.SetWindowLong(hWnd, User32.GWL_WNDPROC, WndProc);

        synchronized (lock) {
            lock.notifyAll();
        }

        MSG msg = new MSG();
        while (User32.GetMessage(msg, null, 0, 0)) {
            User32.TranslateMessage(msg);
            User32.DispatchMessage(msg);
        }

        if (hWnd != null) {
            if (!User32.DestroyWindow(hWnd)) {
                throw new GetLastErrorException();
            }
            hWnd = null;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy