From a3118a07f45c7fde59359d659208901bd7586f37 Mon Sep 17 00:00:00 2001 From: nathan Date: Fri, 23 Dec 2016 01:17:25 +0100 Subject: [PATCH] Fixed issues with calling gtk_widget_destroy too much. Fixed threading issue with isDispatch. --- src/dorkbox/systemTray/jna/linux/Gtk.java | 26 ++- .../systemTray/nativeUI/GtkBaseMenuItem.java | 28 +-- src/dorkbox/systemTray/nativeUI/GtkMenu.java | 186 +++++++++--------- .../systemTray/nativeUI/GtkMenuItem.java | 22 +-- .../nativeUI/GtkMenuItemCheckbox.java | 38 ++-- .../nativeUI/GtkMenuItemSeparator.java | 22 +-- .../nativeUI/GtkMenuItemStatus.java | 20 +- .../nativeUI/_AppIndicatorNativeTray.java | 2 +- .../nativeUI/_GtkStatusIconNativeTray.java | 2 +- .../systemTray/swingUI/_AppIndicatorTray.java | 2 +- 10 files changed, 150 insertions(+), 198 deletions(-) diff --git a/src/dorkbox/systemTray/jna/linux/Gtk.java b/src/dorkbox/systemTray/jna/linux/Gtk.java index 21182c5..6a2e18f 100644 --- a/src/dorkbox/systemTray/jna/linux/Gtk.java +++ b/src/dorkbox/systemTray/jna/linux/Gtk.java @@ -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 isDispatch = new ThreadLocal() { + @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); diff --git a/src/dorkbox/systemTray/nativeUI/GtkBaseMenuItem.java b/src/dorkbox/systemTray/nativeUI/GtkBaseMenuItem.java index 4295d93..248a1ec 100644 --- a/src/dorkbox/systemTray/nativeUI/GtkBaseMenuItem.java +++ b/src/dorkbox/systemTray/nativeUI/GtkBaseMenuItem.java @@ -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; } } diff --git a/src/dorkbox/systemTray/nativeUI/GtkMenu.java b/src/dorkbox/systemTray/nativeUI/GtkMenu.java index 15862f1..2a63fc0 100644 --- a/src/dorkbox/systemTray/nativeUI/GtkMenu.java +++ b/src/dorkbox/systemTray/nativeUI/GtkMenu.java @@ -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 menuEntriesCopy = new ArrayList(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 menuEntriesCopy = new ArrayList(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 } } }); diff --git a/src/dorkbox/systemTray/nativeUI/GtkMenuItem.java b/src/dorkbox/systemTray/nativeUI/GtkMenuItem.java index e5418a0..5ed9b75 100644 --- a/src/dorkbox/systemTray/nativeUI/GtkMenuItem.java +++ b/src/dorkbox/systemTray/nativeUI/GtkMenuItem.java @@ -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); } }); diff --git a/src/dorkbox/systemTray/nativeUI/GtkMenuItemCheckbox.java b/src/dorkbox/systemTray/nativeUI/GtkMenuItemCheckbox.java index cf860e9..8848922 100644 --- a/src/dorkbox/systemTray/nativeUI/GtkMenuItemCheckbox.java +++ b/src/dorkbox/systemTray/nativeUI/GtkMenuItemCheckbox.java @@ -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); } diff --git a/src/dorkbox/systemTray/nativeUI/GtkMenuItemSeparator.java b/src/dorkbox/systemTray/nativeUI/GtkMenuItemSeparator.java index e325598..feee363 100644 --- a/src/dorkbox/systemTray/nativeUI/GtkMenuItemSeparator.java +++ b/src/dorkbox/systemTray/nativeUI/GtkMenuItemSeparator.java @@ -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); - } } diff --git a/src/dorkbox/systemTray/nativeUI/GtkMenuItemStatus.java b/src/dorkbox/systemTray/nativeUI/GtkMenuItemStatus.java index ac46e0b..a20171f 100644 --- a/src/dorkbox/systemTray/nativeUI/GtkMenuItemStatus.java +++ b/src/dorkbox/systemTray/nativeUI/GtkMenuItemStatus.java @@ -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); - } } diff --git a/src/dorkbox/systemTray/nativeUI/_AppIndicatorNativeTray.java b/src/dorkbox/systemTray/nativeUI/_AppIndicatorNativeTray.java index 1d33bcf..65c40ae 100644 --- a/src/dorkbox/systemTray/nativeUI/_AppIndicatorNativeTray.java +++ b/src/dorkbox/systemTray/nativeUI/_AppIndicatorNativeTray.java @@ -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 * diff --git a/src/dorkbox/systemTray/nativeUI/_GtkStatusIconNativeTray.java b/src/dorkbox/systemTray/nativeUI/_GtkStatusIconNativeTray.java index 2fb38ba..ae665d1 100644 --- a/src/dorkbox/systemTray/nativeUI/_GtkStatusIconNativeTray.java +++ b/src/dorkbox/systemTray/nativeUI/_GtkStatusIconNativeTray.java @@ -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) { diff --git a/src/dorkbox/systemTray/swingUI/_AppIndicatorTray.java b/src/dorkbox/systemTray/swingUI/_AppIndicatorTray.java index 5986d2f..31e1408 100644 --- a/src/dorkbox/systemTray/swingUI/_AppIndicatorTray.java +++ b/src/dorkbox/systemTray/swingUI/_AppIndicatorTray.java @@ -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); } };