forked from dorkbox/SystemTray
Added comments for gtk2/3. Code polish, fixed potential issues with
race conditions and finally blocks.
This commit is contained in:
parent
b3b4300179
commit
6cce5cd1cb
@ -22,6 +22,7 @@ import java.awt.event.ActionListener;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import com.sun.jna.Function;
|
import com.sun.jna.Function;
|
||||||
import com.sun.jna.Pointer;
|
import com.sun.jna.Pointer;
|
||||||
@ -36,6 +37,8 @@ import dorkbox.systemTray.util.Swt;
|
|||||||
* bindings for gtk 2 or 3
|
* bindings for gtk 2 or 3
|
||||||
*
|
*
|
||||||
* note: gtk2/3 loading is SENSITIVE, and which AppIndicator symbols are loaded depends on this being loaded first
|
* note: gtk2/3 loading is SENSITIVE, and which AppIndicator symbols are loaded depends on this being loaded first
|
||||||
|
* Additionally, gtk3 has deprecated some methods -- which, fortunately for us, means it will be another 25 years before they are
|
||||||
|
* removed; forcing us to have separate gtk2/3 bindings (we can then only have gtk3 bindings)
|
||||||
*
|
*
|
||||||
* Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md
|
* Direct-mapping, See: https://github.com/java-native-access/jna/blob/master/www/DirectMapping.md
|
||||||
*/
|
*/
|
||||||
@ -54,13 +57,10 @@ class Gtk {
|
|||||||
private static boolean alreadyRunningGTK = false;
|
private static boolean alreadyRunningGTK = false;
|
||||||
private static boolean isLoaded = false;
|
private static boolean isLoaded = false;
|
||||||
|
|
||||||
// there is ONLY a single thread EVER setting this value!!
|
private static AtomicBoolean isDispatch = new AtomicBoolean(false);
|
||||||
private static volatile boolean isDispatch = false;
|
|
||||||
|
|
||||||
private static final int TIMEOUT = 2;
|
private static final int TIMEOUT = 2;
|
||||||
|
|
||||||
private static final Object dispatchLock = new Object[0];
|
|
||||||
|
|
||||||
// objdump -T /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0 | grep gtk
|
// objdump -T /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0 | grep gtk
|
||||||
// objdump -T /usr/lib/x86_64-linux-gnu/libgtk-3.so.0 | grep gtk
|
// objdump -T /usr/lib/x86_64-linux-gnu/libgtk-3.so.0 | grep gtk
|
||||||
|
|
||||||
@ -171,6 +171,7 @@ class Gtk {
|
|||||||
@SuppressWarnings("FieldCanBeLocal")
|
@SuppressWarnings("FieldCanBeLocal")
|
||||||
private static Thread gtkUpdateThread = null;
|
private static Thread gtkUpdateThread = null;
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
public static final int FALSE = 0;
|
public static final int FALSE = 0;
|
||||||
public static final int TRUE = 1;
|
public static final int TRUE = 1;
|
||||||
|
|
||||||
@ -251,7 +252,7 @@ class Gtk {
|
|||||||
if (!blockUntilStarted.await(10, TimeUnit.SECONDS)) {
|
if (!blockUntilStarted.await(10, TimeUnit.SECONDS)) {
|
||||||
if (SystemTray.DEBUG) {
|
if (SystemTray.DEBUG) {
|
||||||
SystemTray.logger.error("Something is very wrong. The waitForStartup took longer than expected.",
|
SystemTray.logger.error("Something is very wrong. The waitForStartup took longer than expected.",
|
||||||
new RuntimeException());
|
new Exception());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
@ -275,7 +276,7 @@ class Gtk {
|
|||||||
if (!blockUntilStarted.await(10, TimeUnit.SECONDS)) {
|
if (!blockUntilStarted.await(10, TimeUnit.SECONDS)) {
|
||||||
if (SystemTray.DEBUG) {
|
if (SystemTray.DEBUG) {
|
||||||
SystemTray.logger.error("Something is very wrong. The waitForStartup took longer than expected.",
|
SystemTray.logger.error("Something is very wrong. The waitForStartup took longer than expected.",
|
||||||
new RuntimeException());
|
new Exception());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
@ -298,7 +299,7 @@ class Gtk {
|
|||||||
if (!blockUntilStarted.await(10, TimeUnit.SECONDS)) {
|
if (!blockUntilStarted.await(10, TimeUnit.SECONDS)) {
|
||||||
if (SystemTray.DEBUG) {
|
if (SystemTray.DEBUG) {
|
||||||
SystemTray.logger.error("Something is very wrong. The waitForStartup took longer than expected.",
|
SystemTray.logger.error("Something is very wrong. The waitForStartup took longer than expected.",
|
||||||
new RuntimeException());
|
new Exception());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
@ -338,7 +339,7 @@ class Gtk {
|
|||||||
|
|
||||||
// not javafx
|
// not javafx
|
||||||
// gtk/swt are **mostly** the same in how events are dispatched, so we can use "raw" gtk methods for SWT
|
// gtk/swt are **mostly** the same in how events are dispatched, so we can use "raw" gtk methods for SWT
|
||||||
if (isDispatch) {
|
if (isDispatch.get()) {
|
||||||
// Run directly on the dispatch thread
|
// Run directly on the dispatch thread
|
||||||
runnable.run();
|
runnable.run();
|
||||||
} else {
|
} else {
|
||||||
@ -348,27 +349,28 @@ class Gtk {
|
|||||||
int callback(final Pointer data) {
|
int callback(final Pointer data) {
|
||||||
synchronized (gtkCallbacks) {
|
synchronized (gtkCallbacks) {
|
||||||
gtkCallbacks.removeFirst(); // now that we've 'handled' it, we can remove it from our callback list
|
gtkCallbacks.removeFirst(); // now that we've 'handled' it, we can remove it from our callback list
|
||||||
|
}
|
||||||
|
|
||||||
isDispatch = true;
|
isDispatch.set(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
runnable.run();
|
runnable.run();
|
||||||
} finally {
|
} finally {
|
||||||
isDispatch = false;
|
isDispatch.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
return Gtk.FALSE; // don't want to call this again
|
return Gtk.FALSE; // don't want to call this again
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
synchronized (gtkCallbacks) {
|
synchronized (gtkCallbacks) {
|
||||||
gtkCallbacks.offer(callback); // prevent GC from collecting this object before it can be called
|
gtkCallbacks.offer(callback); // prevent GC from collecting this object before it can be called
|
||||||
|
}
|
||||||
|
|
||||||
// the correct way to do it. Add with a slightly higher value
|
// the correct way to do it. Add with a slightly higher value
|
||||||
gdk_threads_add_idle_full(100, callback, null, null);
|
gdk_threads_add_idle_full(100, callback, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static
|
public static
|
||||||
void dispatchAndWait(final Runnable runnable) {
|
void dispatchAndWait(final Runnable runnable) {
|
||||||
@ -394,7 +396,7 @@ class Gtk {
|
|||||||
if (SystemTray.DEBUG) {
|
if (SystemTray.DEBUG) {
|
||||||
SystemTray.logger.error("Something is very wrong. The Event Dispatch Queue took longer than " + TIMEOUT + " seconds " +
|
SystemTray.logger.error("Something is very wrong. The Event Dispatch Queue took longer than " + TIMEOUT + " seconds " +
|
||||||
"to complete. Please adjust `SystemTray.TIMEOUT` to a value which better suites your environment.",
|
"to complete. Please adjust `SystemTray.TIMEOUT` to a value which better suites your environment.",
|
||||||
new RuntimeException());
|
new Exception());
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Something is very wrong. The Event Dispatch Queue took longer than " + TIMEOUT + " seconds " +
|
throw new RuntimeException("Something is very wrong. The Event Dispatch Queue took longer than " + TIMEOUT + " seconds " +
|
||||||
"to complete. Please adjust `SystemTray.TIMEOUT` to a value which better suites your environment.");
|
"to complete. Please adjust `SystemTray.TIMEOUT` to a value which better suites your environment.");
|
||||||
@ -403,7 +405,6 @@ class Gtk {
|
|||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
SystemTray.logger.error("Error waiting for dispatch to complete.", new Exception());
|
SystemTray.logger.error("Error waiting for dispatch to complete.", new Exception());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static
|
public static
|
||||||
@ -429,12 +430,12 @@ class Gtk {
|
|||||||
*/
|
*/
|
||||||
public static
|
public static
|
||||||
void proxyClick(final Entry menuEntry, final ActionListener callback) {
|
void proxyClick(final Entry menuEntry, final ActionListener callback) {
|
||||||
Gtk.isDispatch = true;
|
Gtk.isDispatch.set(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
callback.actionPerformed(new ActionEvent(menuEntry, ActionEvent.ACTION_PERFORMED, ""));
|
callback.actionPerformed(new ActionEvent(menuEntry, ActionEvent.ACTION_PERFORMED, ""));
|
||||||
} finally {
|
} finally {
|
||||||
Gtk.isDispatch = false;
|
Gtk.isDispatch.set(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user