Fixed issues with calling gtk_widget_destroy too much. Fixed

threading issue with isDispatch.
This commit is contained in:
nathan 2016-12-23 01:17:25 +01:00
parent 7c6f3ca77b
commit a3118a07f4
10 changed files with 150 additions and 198 deletions

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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
}
}
});

View File

@ -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);
}
});

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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
*

View File

@ -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) {

View File

@ -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);
}
};