forked from dorkbox/SystemTray
Fixed issues with calling gtk_widget_destroy too much. Fixed
threading issue with isDispatch.
This commit is contained in:
parent
7c6f3ca77b
commit
a3118a07f4
@ -22,7 +22,6 @@ import java.awt.event.ActionListener;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import com.sun.jna.Function;
|
||||
import com.sun.jna.Pointer;
|
||||
@ -57,9 +56,16 @@ class Gtk {
|
||||
private static boolean alreadyRunningGTK = false;
|
||||
private static boolean isLoaded = false;
|
||||
|
||||
private static AtomicBoolean isDispatch = new AtomicBoolean(false);
|
||||
// This is required because the EDT needs to have it's own value for this boolean, that is a different value than the main thread
|
||||
private static ThreadLocal<Boolean> isDispatch = new ThreadLocal<Boolean>() {
|
||||
@Override
|
||||
protected
|
||||
Boolean initialValue() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
private static final int TIMEOUT = 2;
|
||||
private static final int TIMEOUT = 2000000;
|
||||
|
||||
// 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
|
||||
@ -399,11 +405,11 @@ class Gtk {
|
||||
if (!countDownLatch.await(TIMEOUT, TimeUnit.SECONDS)) {
|
||||
if (SystemTray.DEBUG) {
|
||||
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.",
|
||||
new Exception(""));
|
||||
} else {
|
||||
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.");
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
@ -507,14 +513,18 @@ class Gtk {
|
||||
|
||||
public static native void gtk_menu_shell_append(Pointer menu_shell, Pointer child);
|
||||
|
||||
public static native void gtk_menu_shell_deactivate(Pointer menu_shell, Pointer child);
|
||||
// Typically this results in the menu shell being erased from the screen
|
||||
public static native void gtk_menu_shell_deactivate(Pointer menuShell);
|
||||
|
||||
public static native void gtk_widget_set_sensitive(Pointer widget, boolean sensitive);
|
||||
|
||||
public static native void gtk_container_remove(Pointer menu, Pointer subItem);
|
||||
|
||||
public static native void gtk_widget_show_all(Pointer widget);
|
||||
|
||||
// will automatically get destroyed if no other references to it
|
||||
public static native void gtk_container_remove(Pointer parentWidget, Pointer widget);
|
||||
|
||||
// from: https://developer.gnome.org/gtk3/stable/GtkWidget.html#gtk-widget-destroy
|
||||
// You should typically call this function on top level widgets, and rarely on child widgets.
|
||||
public static native void gtk_widget_destroy(Pointer widget);
|
||||
|
||||
|
||||
|
@ -33,7 +33,12 @@ class GtkBaseMenuItem implements EntryPeer {
|
||||
// these have to be volatile, because they can be changed from any thread
|
||||
private volatile Pointer spacerImage;
|
||||
|
||||
GtkBaseMenuItem() {
|
||||
// the native GTK component
|
||||
protected final Pointer _native;
|
||||
|
||||
GtkBaseMenuItem(final Pointer _native) {
|
||||
this._native = _native;
|
||||
|
||||
// cannot be done in a static initializer, because the tray icon size might not yet have been determined
|
||||
if (transparentIcon == null) {
|
||||
transparentIcon = ImageUtils.getTransparentImage(ImageUtils.ENTRY_SIZE);
|
||||
@ -56,14 +61,14 @@ class GtkBaseMenuItem implements EntryPeer {
|
||||
* called on the DISPATCH thread
|
||||
*/
|
||||
public
|
||||
void setSpacerImage(final Pointer _native, final boolean everyoneElseHasImages) {
|
||||
void setSpacerImage(final boolean everyoneElseHasImages) {
|
||||
if (hasLegitImage) {
|
||||
// we have a legit icon, so there is nothing else we can do.
|
||||
return;
|
||||
}
|
||||
|
||||
if (spacerImage != null) {
|
||||
Gtk.gtk_widget_destroy(spacerImage);
|
||||
Gtk.gtk_container_remove(_native, spacerImage); // will automatically get destroyed if no other references to it
|
||||
spacerImage = null;
|
||||
Gtk.gtk_widget_show_all(_native);
|
||||
}
|
||||
@ -81,18 +86,17 @@ class GtkBaseMenuItem implements EntryPeer {
|
||||
|
||||
// some GTK libraries DO NOT let us add items AFTER the menu has been attached to the indicator.
|
||||
// To work around this issue, we destroy then recreate the menu every time something is changed.
|
||||
abstract void onDeleteMenu(final Pointer parentNative);
|
||||
abstract void onCreateMenu(final Pointer parentNative, final boolean hasImagesInMenu);
|
||||
|
||||
// always on dispatch
|
||||
void onDeleteMenu(final Pointer parentNative, final Pointer _native) {
|
||||
// always on EDT
|
||||
void onDeleteMenu(final Pointer parentNative) {
|
||||
Gobject.g_object_force_floating(_native); // makes it a floating reference
|
||||
Gtk.gtk_container_remove(parentNative, _native);
|
||||
}
|
||||
|
||||
// always on dispatch
|
||||
void onCreateMenu(final Pointer parentNative, final Pointer _native, final boolean hasImagesInMenu) {
|
||||
setSpacerImage(_native, hasImagesInMenu);
|
||||
// some GTK libraries DO NOT let us add items AFTER the menu has been attached to the indicator.
|
||||
// To work around this issue, we destroy then recreate the menu every time something is changed.
|
||||
// always on EDT
|
||||
void onCreateMenu(final Pointer parentNative, final boolean hasImagesInMenu) {
|
||||
setSpacerImage(hasImagesInMenu);
|
||||
|
||||
// will also get: gsignal.c:2516: signal 'child-added' is invalid for instance '0x7f1df8244080' of type 'GtkMenu'
|
||||
Gtk.gtk_menu_shell_append(parentNative, _native);
|
||||
@ -108,7 +112,7 @@ class GtkBaseMenuItem implements EntryPeer {
|
||||
public
|
||||
void run() {
|
||||
if (spacerImage != null) {
|
||||
Gtk.gtk_widget_destroy(spacerImage);
|
||||
Gtk.gtk_container_remove(_native, spacerImage); // will automatically get destroyed if no other references to it
|
||||
spacerImage = null;
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ package dorkbox.systemTray.nativeUI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
@ -37,7 +38,6 @@ class GtkMenu extends GtkBaseMenuItem implements MenuPeer {
|
||||
private final GtkMenu parent;
|
||||
volatile Pointer _nativeMenu; // must ONLY be created at the end of delete!
|
||||
|
||||
private final Pointer _nativeEntry; // is what is added to the parent menu, if we are NOT on the system tray
|
||||
private volatile Pointer image;
|
||||
|
||||
// The mnemonic will ONLY show-up once a menu entry is selected. IT WILL NOT show up before then!
|
||||
@ -46,24 +46,30 @@ class GtkMenu extends GtkBaseMenuItem implements MenuPeer {
|
||||
private volatile char mnemonicKey = 0;
|
||||
|
||||
// have to make sure no other methods can call obliterate, delete, or create menu once it's already started
|
||||
private volatile boolean obliterateInProgress = false;
|
||||
private AtomicBoolean obliterateInProgress = new AtomicBoolean(false);
|
||||
|
||||
// called by the system tray constructors
|
||||
// This is NOT a copy constructor!
|
||||
@SuppressWarnings("IncompleteCopyConstructor")
|
||||
GtkMenu() {
|
||||
super(null);
|
||||
this.parent = null;
|
||||
}
|
||||
|
||||
// This is NOT a copy constructor!
|
||||
@SuppressWarnings("IncompleteCopyConstructor")
|
||||
GtkMenu(final GtkMenu parent) {
|
||||
super(Gtk.gtk_image_menu_item_new_with_mnemonic("")); // is what is added to the parent menu (so images work)
|
||||
this.parent = parent;
|
||||
|
||||
if (parent != null) {
|
||||
_nativeEntry = Gtk.gtk_image_menu_item_new_with_mnemonic(""); // is what is added to the parent menu (so images work)
|
||||
} else {
|
||||
_nativeEntry = null;
|
||||
}
|
||||
}
|
||||
|
||||
GtkMenu getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* ALWAYS CALLED ON THE EDT
|
||||
*/
|
||||
private
|
||||
void add(final GtkBaseMenuItem item, final int index) {
|
||||
if (index > 0) {
|
||||
@ -75,6 +81,8 @@ class GtkMenu extends GtkBaseMenuItem implements MenuPeer {
|
||||
|
||||
/**
|
||||
* Called inside the gdk_threads block
|
||||
*
|
||||
* ALWAYS CALLED ON THE EDT
|
||||
*/
|
||||
protected
|
||||
void onMenuAdded(final Pointer menu) {
|
||||
@ -82,27 +90,28 @@ class GtkMenu extends GtkBaseMenuItem implements MenuPeer {
|
||||
}
|
||||
|
||||
|
||||
// some GTK libraries DO NOT let us add items AFTER the menu has been attached to the indicator.
|
||||
// To work around this issue, we destroy then recreate the menu every time something is changed.
|
||||
/**
|
||||
* Deletes the menu, and unreferences everything in it. ALSO recreates ONLY the menu object.
|
||||
*
|
||||
* some GTK libraries DO NOT let us add items AFTER the menu has been attached to the indicator.
|
||||
* To work around this issue, we destroy then recreate the menu every time something is changed.
|
||||
*
|
||||
* ALWAYS CALLED ON EDT
|
||||
*/
|
||||
private
|
||||
void deleteMenu() {
|
||||
if (obliterateInProgress) {
|
||||
if (obliterateInProgress.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_nativeMenu != null) {
|
||||
// have to remove all other menu entries
|
||||
synchronized (menuEntries) {
|
||||
for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) {
|
||||
final GtkBaseMenuItem menuEntry__ = menuEntries.get(i);
|
||||
menuEntry__.onDeleteMenu(_nativeMenu);
|
||||
}
|
||||
|
||||
Gtk.gtk_widget_destroy(_nativeMenu);
|
||||
for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) {
|
||||
final GtkBaseMenuItem menuEntry__ = menuEntries.get(i);
|
||||
menuEntry__.onDeleteMenu(_nativeMenu);
|
||||
}
|
||||
|
||||
Gtk.gtk_widget_destroy(_nativeMenu);
|
||||
}
|
||||
|
||||
if (parent != null) {
|
||||
@ -114,15 +123,20 @@ class GtkMenu extends GtkBaseMenuItem implements MenuPeer {
|
||||
|
||||
// binds sub-menu to entry (if it exists! it does not for the root menu)
|
||||
if (parent != null) {
|
||||
Gtk.gtk_menu_item_set_submenu(_nativeEntry, _nativeMenu);
|
||||
Gtk.gtk_menu_item_set_submenu(_native, _nativeMenu);
|
||||
}
|
||||
}
|
||||
|
||||
// some GTK libraries DO NOT let us add items AFTER the menu has been attached to the indicator.
|
||||
// To work around this issue, we destroy then recreate the menu every time something is changed.
|
||||
/**
|
||||
* some GTK libraries DO NOT let us add items AFTER the menu has been attached to the indicator.
|
||||
*
|
||||
* To work around this issue, we destroy then recreate the menu every time something is changed.
|
||||
*
|
||||
* ALWAYS CALLED ON THE EDT
|
||||
*/
|
||||
private
|
||||
void createMenu() {
|
||||
if (obliterateInProgress) {
|
||||
if (obliterateInProgress.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -130,62 +144,59 @@ class GtkMenu extends GtkBaseMenuItem implements MenuPeer {
|
||||
parent.createMenu();
|
||||
}
|
||||
|
||||
// now add back other menu entries
|
||||
boolean hasImages = false;
|
||||
|
||||
// now add back other menu entries
|
||||
synchronized (menuEntries) {
|
||||
for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) {
|
||||
final GtkBaseMenuItem menuEntry__ = menuEntries.get(i);
|
||||
hasImages |= menuEntry__.hasImage();
|
||||
}
|
||||
for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) {
|
||||
final GtkBaseMenuItem menuEntry__ = menuEntries.get(i);
|
||||
hasImages |= menuEntry__.hasImage();
|
||||
}
|
||||
|
||||
for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) {
|
||||
// the menu entry looks FUNKY when there are a mis-match of entries WITH and WITHOUT images
|
||||
final GtkBaseMenuItem menuEntry__ = menuEntries.get(i);
|
||||
menuEntry__.onCreateMenu(_nativeMenu, hasImages);
|
||||
for (int i = 0, menuEntriesSize = menuEntries.size(); i < menuEntriesSize; i++) {
|
||||
// the menu entry looks FUNKY when there are a mis-match of entries WITH and WITHOUT images
|
||||
final GtkBaseMenuItem menuEntry__ = menuEntries.get(i);
|
||||
menuEntry__.onCreateMenu(_nativeMenu, hasImages);
|
||||
|
||||
if (menuEntry__ instanceof GtkMenu) {
|
||||
GtkMenu subMenu = (GtkMenu) menuEntry__;
|
||||
if (subMenu.getParent() != GtkMenu.this) {
|
||||
// we don't want to "createMenu" on our sub-menu that is assigned to us directly, as they are already doing it
|
||||
subMenu.createMenu();
|
||||
}
|
||||
if (menuEntry__ instanceof GtkMenu) {
|
||||
GtkMenu subMenu = (GtkMenu) menuEntry__;
|
||||
if (subMenu.getParent() != GtkMenu.this) {
|
||||
// we don't want to "createMenu" on our sub-menu that is assigned to us directly, as they are already doing it
|
||||
subMenu.createMenu();
|
||||
}
|
||||
}
|
||||
|
||||
onMenuAdded(_nativeMenu);
|
||||
Gtk.gtk_widget_show_all(_nativeMenu); // necessary to guarantee widget is visible (doesn't always show_all for all children)
|
||||
}
|
||||
|
||||
Gtk.gtk_widget_show_all(_nativeMenu); // necessary to guarantee widget is visible (doesn't always show_all for all children)
|
||||
onMenuAdded(_nativeMenu);
|
||||
}
|
||||
|
||||
/**
|
||||
* must be called on the dispatch thread
|
||||
*
|
||||
* Completely obliterates the menu, no possible way to reconstruct it.
|
||||
*
|
||||
* ALWAYS CALLED ON THE EDT
|
||||
*/
|
||||
private
|
||||
void obliterateMenu() {
|
||||
if (_nativeMenu != null && !obliterateInProgress) {
|
||||
obliterateInProgress = true;
|
||||
if (_nativeMenu != null && !obliterateInProgress.get()) {
|
||||
obliterateInProgress.set(true);
|
||||
|
||||
// have to remove all other menu entries
|
||||
synchronized (menuEntries) {
|
||||
// a copy is made because sub-menus remove themselves from parents when .remove() is called. If we don't
|
||||
// do this, errors will be had because indices don't line up anymore.
|
||||
ArrayList<GtkBaseMenuItem> menuEntriesCopy = new ArrayList<GtkBaseMenuItem>(this.menuEntries);
|
||||
|
||||
for (int i = 0, menuEntriesSize = menuEntriesCopy.size(); i < menuEntriesSize; i++) {
|
||||
final GtkBaseMenuItem menuEntry__ = menuEntriesCopy.get(i);
|
||||
menuEntry__.remove();
|
||||
}
|
||||
this.menuEntries.clear();
|
||||
menuEntriesCopy.clear();
|
||||
// a copy is made because sub-menus remove themselves from parents when .remove() is called. If we don't
|
||||
// do this, errors will be had because indices don't line up anymore.
|
||||
ArrayList<GtkBaseMenuItem> menuEntriesCopy = new ArrayList<GtkBaseMenuItem>(menuEntries);
|
||||
menuEntries.clear();
|
||||
|
||||
Gtk.gtk_widget_destroy(_nativeMenu);
|
||||
_nativeMenu = null;
|
||||
for (int i = 0, menuEntriesSize = menuEntriesCopy.size(); i < menuEntriesSize; i++) {
|
||||
final GtkBaseMenuItem menuEntry__ = menuEntriesCopy.get(i);
|
||||
menuEntry__.remove();
|
||||
}
|
||||
menuEntriesCopy.clear();
|
||||
|
||||
obliterateInProgress = false;
|
||||
Gtk.gtk_widget_destroy(_nativeMenu);
|
||||
_nativeMenu = null;
|
||||
|
||||
obliterateInProgress.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,21 +264,21 @@ class GtkMenu extends GtkBaseMenuItem implements MenuPeer {
|
||||
public
|
||||
void run() {
|
||||
if (image != null) {
|
||||
Gtk.gtk_widget_destroy(image);
|
||||
Gtk.gtk_container_remove(_native, image); // will automatically get destroyed if no other references to it
|
||||
image = null;
|
||||
Gtk.gtk_widget_show_all(_nativeEntry);
|
||||
Gtk.gtk_widget_show_all(_native);
|
||||
}
|
||||
|
||||
if (menuItem.getImage() != null) {
|
||||
image = Gtk.gtk_image_new_from_file(menuItem.getImage()
|
||||
.getAbsolutePath());
|
||||
Gtk.gtk_image_menu_item_set_image(_nativeEntry, image);
|
||||
Gtk.gtk_image_menu_item_set_image(_native, image);
|
||||
|
||||
// must always re-set always-show after setting the image
|
||||
Gtk.gtk_image_menu_item_set_always_show_image(_nativeEntry, true);
|
||||
Gtk.gtk_image_menu_item_set_always_show_image(_native, true);
|
||||
}
|
||||
|
||||
Gtk.gtk_widget_show_all(_nativeEntry);
|
||||
Gtk.gtk_widget_show_all(_native);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -281,7 +292,7 @@ class GtkMenu extends GtkBaseMenuItem implements MenuPeer {
|
||||
@Override
|
||||
public
|
||||
void run() {
|
||||
Gtk.gtk_widget_set_sensitive(_nativeEntry, menuItem.getEnabled());
|
||||
Gtk.gtk_widget_set_sensitive(_native, menuItem.getEnabled());
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -320,8 +331,8 @@ class GtkMenu extends GtkBaseMenuItem implements MenuPeer {
|
||||
@Override
|
||||
public
|
||||
void run() {
|
||||
Gtk.gtk_menu_item_set_label(_nativeEntry, textWithMnemonic);
|
||||
Gtk.gtk_widget_show_all(_nativeEntry);
|
||||
Gtk.gtk_menu_item_set_label(_native, textWithMnemonic);
|
||||
Gtk.gtk_widget_show_all(_native);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -342,38 +353,25 @@ class GtkMenu extends GtkBaseMenuItem implements MenuPeer {
|
||||
setText(menuItem);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
void onDeleteMenu(final Pointer parentNative) {
|
||||
if (parent != null) {
|
||||
onDeleteMenu(parentNative, _nativeEntry);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void onCreateMenu(final Pointer parentNative, final boolean hasImagesInMenu) {
|
||||
if (parent != null) {
|
||||
onCreateMenu(parentNative, _nativeEntry, hasImagesInMenu);
|
||||
}
|
||||
}
|
||||
|
||||
// called when a child removes itself from the parent menu. Does not work for sub-menus
|
||||
/**
|
||||
* called when a child removes itself from the parent menu. Does not work for sub-menus
|
||||
*
|
||||
* ALWAYS CALLED ON THE EDT
|
||||
*/
|
||||
public
|
||||
void remove(final GtkBaseMenuItem item) {
|
||||
synchronized (menuEntries) {
|
||||
menuEntries.remove(item);
|
||||
}
|
||||
menuEntries.remove(item);
|
||||
|
||||
// have to rebuild the menu now...
|
||||
deleteMenu();
|
||||
createMenu();
|
||||
deleteMenu(); // must be on EDT
|
||||
createMenu(); // must be on EDT
|
||||
}
|
||||
|
||||
// a child will always remove itself from the parent.
|
||||
@Override
|
||||
public
|
||||
void remove() {
|
||||
Gtk.dispatchAndWait(new Runnable() {
|
||||
Gtk.dispatch(new Runnable() {
|
||||
@Override
|
||||
public
|
||||
void run() {
|
||||
@ -381,21 +379,19 @@ class GtkMenu extends GtkBaseMenuItem implements MenuPeer {
|
||||
|
||||
if (parent != null) {
|
||||
// have to remove from the parent.menuEntries first
|
||||
synchronized (parent.menuEntries) {
|
||||
parent.menuEntries.remove(GtkMenu.this);
|
||||
}
|
||||
parent.menuEntries.remove(GtkMenu.this);
|
||||
}
|
||||
|
||||
// delete all of the children of this submenu (must happen before the menuEntry is removed)
|
||||
obliterateMenu();
|
||||
obliterateMenu(); // must be on EDT
|
||||
|
||||
if (parent != null) {
|
||||
// remove the gtk entry item from our menu NATIVE components
|
||||
Gtk.gtk_menu_item_set_submenu(_nativeEntry, null);
|
||||
Gtk.gtk_menu_item_set_submenu(_native, null);
|
||||
|
||||
// have to rebuild the menu now...
|
||||
parent.deleteMenu();
|
||||
parent.createMenu();
|
||||
parent.deleteMenu(); // must be on EDT
|
||||
parent.createMenu(); // must be on EDT
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -32,7 +32,6 @@ class GtkMenuItem extends GtkBaseMenuItem implements MenuItemPeer, GCallback {
|
||||
private final NativeLong nativeLong;
|
||||
|
||||
private final GtkMenu parent;
|
||||
protected final Pointer _native = Gtk.gtk_image_menu_item_new_with_mnemonic("");
|
||||
|
||||
// these have to be volatile, because they can be changed from any thread
|
||||
private volatile MenuItem menuItemForActionCallback;
|
||||
@ -48,6 +47,8 @@ class GtkMenuItem extends GtkBaseMenuItem implements MenuItemPeer, GCallback {
|
||||
* this is a FLOATING reference. See: https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#floating-ref
|
||||
*/
|
||||
GtkMenuItem(final GtkMenu parent) {
|
||||
super(Gtk.gtk_image_menu_item_new_with_mnemonic(""));
|
||||
|
||||
this.parent = parent;
|
||||
nativeLong = Gobject.g_signal_connect_object(_native, "activate", this, null, 0);
|
||||
}
|
||||
@ -85,7 +86,7 @@ class GtkMenuItem extends GtkBaseMenuItem implements MenuItemPeer, GCallback {
|
||||
public
|
||||
void run() {
|
||||
if (image != null) {
|
||||
Gtk.gtk_widget_destroy(image);
|
||||
Gtk.gtk_container_remove(_native, image); // will automatically get destroyed if no other references to it
|
||||
image = null;
|
||||
Gtk.gtk_widget_show_all(_native);
|
||||
}
|
||||
@ -168,16 +169,6 @@ class GtkMenuItem extends GtkBaseMenuItem implements MenuItemPeer, GCallback {
|
||||
setText(menuItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
void onDeleteMenu(final Pointer parentNative) {
|
||||
onDeleteMenu(parentNative, _native);
|
||||
}
|
||||
|
||||
@Override
|
||||
void onCreateMenu(final Pointer parentNative, final boolean hasImagesInMenu) {
|
||||
onCreateMenu(parentNative, _native, hasImagesInMenu);
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
@Override
|
||||
public
|
||||
@ -186,19 +177,16 @@ class GtkMenuItem extends GtkBaseMenuItem implements MenuItemPeer, GCallback {
|
||||
@Override
|
||||
public
|
||||
void run() {
|
||||
Gtk.gtk_container_remove(parent._nativeMenu, _native);
|
||||
Gtk.gtk_menu_shell_deactivate(parent._nativeMenu, _native);
|
||||
Gtk.gtk_container_remove(parent._nativeMenu, _native); // will automatically get destroyed if no other references to it
|
||||
|
||||
GtkMenuItem.super.remove();
|
||||
|
||||
menuItemForActionCallback = null;
|
||||
if (image != null) {
|
||||
Gtk.gtk_widget_destroy(image);
|
||||
Gtk.gtk_container_remove(_native, image); // will automatically get destroyed if no other references to it
|
||||
image = null;
|
||||
}
|
||||
|
||||
Gtk.gtk_widget_destroy(_native);
|
||||
|
||||
parent.remove(GtkMenuItem.this);
|
||||
}
|
||||
});
|
||||
|
@ -36,11 +36,9 @@ class GtkMenuItemCheckbox extends GtkBaseMenuItem implements CheckboxPeer, GCall
|
||||
private final NativeLong nativeLong;
|
||||
|
||||
private final GtkMenu parent;
|
||||
private final Pointer _native = Gtk.gtk_check_menu_item_new_with_mnemonic("");
|
||||
|
||||
|
||||
// these have to be volatile, because they can be changed from any thread
|
||||
private volatile Checkbox menuItem;
|
||||
private volatile Checkbox checkbox;
|
||||
private volatile Pointer image;
|
||||
|
||||
// The mnemonic will ONLY show-up once a menu entry is selected. IT WILL NOT show up before then!
|
||||
@ -53,6 +51,7 @@ class GtkMenuItemCheckbox extends GtkBaseMenuItem implements CheckboxPeer, GCall
|
||||
* this is a FLOATING reference. See: https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#floating-ref
|
||||
*/
|
||||
GtkMenuItemCheckbox(final GtkMenu parent) {
|
||||
super(Gtk.gtk_check_menu_item_new_with_mnemonic(""));
|
||||
this.parent = parent;
|
||||
|
||||
// cannot be done in a static initializer, because the tray icon size might not yet have been determined
|
||||
@ -67,13 +66,13 @@ class GtkMenuItemCheckbox extends GtkBaseMenuItem implements CheckboxPeer, GCall
|
||||
@Override
|
||||
public
|
||||
int callback(final Pointer instance, final Pointer data) {
|
||||
if (menuItem != null) {
|
||||
final ActionListener cb = menuItem.getCallback();
|
||||
if (checkbox != null) {
|
||||
final ActionListener cb = checkbox.getCallback();
|
||||
if (cb != null) {
|
||||
try {
|
||||
Gtk.proxyClick(menuItem, cb);
|
||||
Gtk.proxyClick(checkbox, cb);
|
||||
} catch (Exception e) {
|
||||
SystemTray.logger.error("Error calling menu entry checkbox {} click event.", menuItem.getText(), e);
|
||||
SystemTray.logger.error("Error calling menu entry checkbox {} click event.", checkbox.getText(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -87,7 +86,7 @@ class GtkMenuItemCheckbox extends GtkBaseMenuItem implements CheckboxPeer, GCall
|
||||
}
|
||||
|
||||
public
|
||||
void setSpacerImage(final Pointer _native, final boolean everyoneElseHasImages) {
|
||||
void setSpacerImage(final boolean everyoneElseHasImages) {
|
||||
// no op
|
||||
}
|
||||
|
||||
@ -138,8 +137,8 @@ class GtkMenuItemCheckbox extends GtkBaseMenuItem implements CheckboxPeer, GCall
|
||||
|
||||
@Override
|
||||
public
|
||||
void setCallback(final Checkbox menuItem) {
|
||||
this.menuItem = menuItem;
|
||||
void setCallback(final Checkbox checkbox) {
|
||||
this.checkbox = checkbox;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -162,16 +161,6 @@ class GtkMenuItemCheckbox extends GtkBaseMenuItem implements CheckboxPeer, GCall
|
||||
setText(menuItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
void onDeleteMenu(final Pointer parentNative) {
|
||||
onDeleteMenu(parentNative, _native);
|
||||
}
|
||||
|
||||
@Override
|
||||
void onCreateMenu(final Pointer parentNative, final boolean hasImagesInMenu) {
|
||||
onCreateMenu(parentNative, _native, hasImagesInMenu);
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
@Override
|
||||
public
|
||||
@ -180,18 +169,15 @@ class GtkMenuItemCheckbox extends GtkBaseMenuItem implements CheckboxPeer, GCall
|
||||
@Override
|
||||
public
|
||||
void run() {
|
||||
Gtk.gtk_container_remove(parent._nativeMenu, _native);
|
||||
Gtk.gtk_menu_shell_deactivate(parent._nativeMenu, _native);
|
||||
Gtk.gtk_container_remove(parent._nativeMenu, _native); // will automatically get destroyed if no other references to it
|
||||
|
||||
GtkMenuItemCheckbox.super.remove();
|
||||
|
||||
menuItem = null;
|
||||
if (image != null) {
|
||||
Gtk.gtk_widget_destroy(image);
|
||||
Gtk.gtk_container_remove(_native, image); // will automatically get destroyed if no other references to it
|
||||
image = null;
|
||||
}
|
||||
|
||||
Gtk.gtk_widget_destroy(_native);
|
||||
checkbox = null;
|
||||
|
||||
parent.remove(GtkMenuItemCheckbox.this);
|
||||
}
|
||||
|
@ -15,22 +15,19 @@
|
||||
*/
|
||||
package dorkbox.systemTray.nativeUI;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import dorkbox.systemTray.jna.linux.Gtk;
|
||||
import dorkbox.systemTray.peer.EntryPeer;
|
||||
|
||||
class GtkMenuItemSeparator extends GtkBaseMenuItem implements EntryPeer {
|
||||
|
||||
private final GtkMenu parent;
|
||||
private final Pointer _native = Gtk.gtk_separator_menu_item_new();
|
||||
|
||||
|
||||
/**
|
||||
* called from inside dispatch thread. ONLY creates the menu item, but DOES NOT attach it!
|
||||
* this is a FLOATING reference. See: https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#floating-ref
|
||||
*/
|
||||
GtkMenuItemSeparator(final GtkMenu parent) {
|
||||
super(Gtk.gtk_separator_menu_item_new());
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@ -42,10 +39,7 @@ class GtkMenuItemSeparator extends GtkBaseMenuItem implements EntryPeer {
|
||||
@Override
|
||||
public
|
||||
void run() {
|
||||
Gtk.gtk_container_remove(parent._nativeMenu, _native);
|
||||
Gtk.gtk_menu_shell_deactivate(parent._nativeMenu, _native);
|
||||
|
||||
Gtk.gtk_widget_destroy(_native);
|
||||
Gtk.gtk_container_remove(parent._nativeMenu, _native); // will automatically get destroyed if no other references to it
|
||||
|
||||
parent.remove(GtkMenuItemSeparator.this);
|
||||
}
|
||||
@ -58,17 +52,7 @@ class GtkMenuItemSeparator extends GtkBaseMenuItem implements EntryPeer {
|
||||
}
|
||||
|
||||
public
|
||||
void setSpacerImage(final Pointer _native, final boolean everyoneElseHasImages) {
|
||||
void setSpacerImage(final boolean everyoneElseHasImages) {
|
||||
// no op
|
||||
}
|
||||
|
||||
@Override
|
||||
void onDeleteMenu(final Pointer parentNative) {
|
||||
onDeleteMenu(parentNative, _native);
|
||||
}
|
||||
|
||||
@Override
|
||||
void onCreateMenu(final Pointer parentNative, final boolean hasImagesInMenu) {
|
||||
onCreateMenu(parentNative, _native, hasImagesInMenu);
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,6 @@
|
||||
*/
|
||||
package dorkbox.systemTray.nativeUI;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
|
||||
import dorkbox.systemTray.Status;
|
||||
import dorkbox.systemTray.jna.linux.Gtk;
|
||||
import dorkbox.systemTray.peer.StatusPeer;
|
||||
@ -26,14 +24,13 @@ import dorkbox.systemTray.peer.StatusPeer;
|
||||
class GtkMenuItemStatus extends GtkBaseMenuItem implements StatusPeer {
|
||||
|
||||
private final GtkMenu parent;
|
||||
private final Pointer _native = Gtk.gtk_image_menu_item_new_with_mnemonic("");
|
||||
|
||||
/**
|
||||
* called from inside dispatch thread. ONLY creates the menu item, but DOES NOT attach it!
|
||||
* this is a FLOATING reference. See: https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#floating-ref
|
||||
*/
|
||||
GtkMenuItemStatus(final GtkMenu parent) {
|
||||
super();
|
||||
super(Gtk.gtk_image_menu_item_new_with_mnemonic(""));
|
||||
this.parent = parent;
|
||||
|
||||
// need that extra space so it matches windows/mac
|
||||
@ -66,25 +63,12 @@ class GtkMenuItemStatus extends GtkBaseMenuItem implements StatusPeer {
|
||||
@Override
|
||||
public
|
||||
void run() {
|
||||
Gtk.gtk_container_remove(parent._nativeMenu, _native);
|
||||
Gtk.gtk_menu_shell_deactivate(parent._nativeMenu, _native);
|
||||
Gtk.gtk_container_remove(parent._nativeMenu, _native); // will automatically get destroyed if no other references to it
|
||||
|
||||
GtkMenuItemStatus.super.remove();
|
||||
|
||||
Gtk.gtk_widget_destroy(_native);
|
||||
|
||||
parent.remove(GtkMenuItemStatus.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
void onDeleteMenu(final Pointer parentNative) {
|
||||
onDeleteMenu(parentNative, _native);
|
||||
}
|
||||
|
||||
@Override
|
||||
void onCreateMenu(final Pointer parentNative, final boolean hasImagesInMenu) {
|
||||
onCreateMenu(parentNative, _native, hasImagesInMenu);
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ class _AppIndicatorNativeTray extends Tray implements NativeUI {
|
||||
Gtk.startGui();
|
||||
|
||||
// we override various methods, because each tray implementation is SLIGHTLY different. This allows us customization.
|
||||
final GtkMenu gtkMenu = new GtkMenu(null) {
|
||||
final GtkMenu gtkMenu = new GtkMenu() {
|
||||
/**
|
||||
* MUST BE AFTER THE ITEM IS ADDED/CHANGED from the menu
|
||||
*
|
||||
|
@ -64,7 +64,7 @@ class _GtkStatusIconNativeTray extends Tray implements NativeUI {
|
||||
Gtk.startGui();
|
||||
|
||||
// we override various methods, because each tray implementation is SLIGHTLY different. This allows us customization.
|
||||
final GtkMenu gtkMenu = new GtkMenu(null) {
|
||||
final GtkMenu gtkMenu = new GtkMenu() {
|
||||
@Override
|
||||
public
|
||||
void setEnabled(final MenuItem menuItem) {
|
||||
|
@ -287,7 +287,7 @@ class _AppIndicatorTray extends Tray implements SwingUI {
|
||||
@Override
|
||||
public
|
||||
void callback(Pointer notUsed, final GdkEventButton event) {
|
||||
Gtk.gtk_widget_destroy(dummyMenu); // destroy the menu, so it will disappear (and we then have focus on our swing menu)
|
||||
Gtk.gtk_menu_shell_deactivate(dummyMenu);
|
||||
SwingUtil.invokeLater(popupRunnable);
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user