Windows Event Dispatch modified to permit multiple instances (required for multiple, simultaneous system tray instances on windows)

This commit is contained in:
Robinson 2021-01-31 23:39:58 +01:00
parent 41fe221e3c
commit 2a69b70803

View File

@ -26,6 +26,7 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -33,12 +34,13 @@ import org.slf4j.LoggerFactory;
import com.sun.jna.WString; import com.sun.jna.WString;
import com.sun.jna.platform.win32.WinUser; import com.sun.jna.platform.win32.WinUser;
@SuppressWarnings({"Convert2Lambda", "UnusedAssignment", "Convert2Diamond", "FieldCanBeLocal"}) @SuppressWarnings({"Convert2Lambda", "UnusedAssignment", "Convert2Diamond", "FieldCanBeLocal", "unused"})
public public
class WindowsEventDispatch implements Runnable { class WindowsEventDispatch implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(WindowsEventDispatch.class); private static final Logger logger = LoggerFactory.getLogger(WindowsEventDispatch.class);
private static final String NAME = "WindowsEventDispatch"; private static final String NAME = "WindowsEventDispatch_";
private static final AtomicInteger COUNT = new AtomicInteger(0);
public static final int WM_TASKBARCREATED = User32.RegisterWindowMessage(new WString("TaskbarCreated")); public static final int WM_TASKBARCREATED = User32.RegisterWindowMessage(new WString("TaskbarCreated"));
public static final int WM_COMMAND = 0x0111; public static final int WM_COMMAND = 0x0111;
@ -49,12 +51,10 @@ class WindowsEventDispatch implements Runnable {
public static final int MF_POPUP = 0x00000010; public static final int MF_POPUP = 0x00000010;
private static final WindowsEventDispatch edt = new WindowsEventDispatch(); private final String name = NAME + COUNT.getAndIncrement();
private final static Map<Integer, List<Listener>> messageIDs = new HashMap<Integer, List<Listener>>(); private final Map<Integer, List<Listener>> messageIDs = new HashMap<Integer, List<Listener>>();
private static final Object lock = new Object();
private static int referenceCount = 0;
private final Object lock = new Object();
private Thread dispatchThread; private Thread dispatchThread;
@ -70,61 +70,55 @@ class WindowsEventDispatch implements Runnable {
} }
public static public static
void start() { WindowsEventDispatch start() {
synchronized (lock) { WindowsEventDispatch edt = new WindowsEventDispatch();
int ref = referenceCount++;
if (ref == 0) { synchronized (edt.lock) {
edt.start_(); edt.start_();
}
try { try {
// wait for the dispatch thread to start // wait for the dispatch thread to start if we aren't started yet, but requested it
lock.wait(); edt.lock.wait();
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} }
} }
return edt;
} }
public static public
void stop() {
synchronized (lock) {
if (--referenceCount == 0) {
edt.stop_();
}
}
}
public static
HWND get() { HWND get() {
return edt.hWnd; return hWnd;
} }
// always from inside lock! // always from inside lock!
private private
void start_() { void start_() {
dispatchThread = new Thread(this, NAME); dispatchThread = new Thread(this, name);
dispatchThread.start(); dispatchThread.start();
} }
// always from inside lock! public void
private void stop() {
stop_() { synchronized (lock) {
User32.SendMessage(hWnd, WM_QUIT, new WPARAM(0), new LPARAM(0)); if (hWnd != null) {
User32.PostMessage(hWnd, WM_QUIT, new WPARAM(0), new LPARAM(0));
try { try {
// wait for the dispatch thread to quit (but only if we are not on the dispatch thread) // wait for the dispatch thread to quit (but only if we are not on the dispatch thread)
if (!Thread.currentThread().equals(dispatchThread)) { if (!Thread.currentThread().equals(dispatchThread)) {
dispatchThread.join(); dispatchThread.join();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
} }
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} }
} }
@SuppressWarnings("Java8MapApi") @SuppressWarnings("Java8MapApi")
public static public
void addListener(final int messageId, final Listener listener) { void addListener(final int messageId, final Listener listener) {
synchronized (messageIDs) { synchronized (messageIDs) {
List<Listener> listeners = messageIDs.get(messageId); List<Listener> listeners = messageIDs.get(messageId);
@ -136,7 +130,8 @@ class WindowsEventDispatch implements Runnable {
listeners.add(listener); listeners.add(listener);
} }
} }
public static
public
void removeListener(final Listener listener) { void removeListener(final Listener listener) {
synchronized (messageIDs) { synchronized (messageIDs) {
for (Map.Entry<Integer, List<Listener>> entry : messageIDs.entrySet()) { for (Map.Entry<Integer, List<Listener>> entry : messageIDs.entrySet()) {
@ -180,7 +175,7 @@ class WindowsEventDispatch implements Runnable {
} }
}; };
hWnd = User32.CreateWindowEx(0, "STATIC", NAME, 0, 0, 0, 0, 0, null, null, null, hWnd = User32.CreateWindowEx(0, "STATIC", name, 0, 0, 0, 0, 0, null, null, null,
null); null);
if (hWnd == null) { if (hWnd == null) {
throw new GetLastErrorException(); throw new GetLastErrorException();