Consolidated gtk menu (so the menuentry has the entry+menu)
This commit is contained in:
parent
b1398392c7
commit
ad8cd3709c
|
@ -39,9 +39,6 @@ class GtkEntryItem extends GtkEntry implements GCallback {
|
||||||
// these are necessary BECAUSE GTK menus look funky as hell when there are some menu entries WITH icons and some WITHOUT
|
// these are necessary BECAUSE GTK menus look funky as hell when there are some menu entries WITH icons and some WITHOUT
|
||||||
private volatile boolean hasLegitIcon = true;
|
private volatile boolean hasLegitIcon = true;
|
||||||
|
|
||||||
// only set when this entry has a submenu attached to it. One cannot "unattach" a sub-menu, they must delete+add
|
|
||||||
private GtkMenu subMenu;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* called from inside dispatch thread. ONLY creates the menu item, but DOES NOT attach it!
|
* 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
|
* this is a FLOATING reference. See: https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html#floating-ref
|
||||||
|
@ -65,20 +62,6 @@ class GtkEntryItem extends GtkEntry implements GCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves the sub-menu for an entry, so we can recreate all of the menus when one entry changes (because of how GTK on some systems work
|
|
||||||
*
|
|
||||||
* @param subMenu The submenu that is attached to this menu entry
|
|
||||||
*/
|
|
||||||
void setSubMenu(GtkMenu subMenu) {
|
|
||||||
this.subMenu = subMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
// only needed for recursive create/delete menus
|
|
||||||
GtkMenu getSubMenu() {
|
|
||||||
return subMenu;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setCallback(final SystemTrayMenuAction callback) {
|
void setCallback(final SystemTrayMenuAction callback) {
|
||||||
|
@ -176,9 +159,5 @@ class GtkEntryItem extends GtkEntry implements GCallback {
|
||||||
Gtk.gtk_widget_destroy(image);
|
Gtk.gtk_widget_destroy(image);
|
||||||
image = null;
|
image = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subMenu != null) {
|
|
||||||
subMenu.obliterateMenu();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,19 +34,24 @@ import dorkbox.systemTray.linux.jna.Gobject;
|
||||||
import dorkbox.systemTray.linux.jna.Gtk;
|
import dorkbox.systemTray.linux.jna.Gtk;
|
||||||
|
|
||||||
class GtkMenu extends Menu implements MenuEntry {
|
class GtkMenu extends Menu implements MenuEntry {
|
||||||
// menu entry that this menu is attached to
|
// menu entry that this menu is attached to. Will be NULL when it's the system tray
|
||||||
private final GtkEntryItem menuEntry;
|
private final GtkEntryItem menuEntry;
|
||||||
|
|
||||||
// must ONLY be created at the end of delete!
|
// must ONLY be created at the end of delete!
|
||||||
volatile Pointer _native;
|
volatile Pointer _native;
|
||||||
|
|
||||||
|
|
||||||
// called on dispatch
|
// called on dispatch
|
||||||
GtkMenu(SystemTray systemTray, GtkMenu parent, final GtkEntryItem menuEntry) {
|
GtkMenu(final SystemTray systemTray, final GtkMenu parent, final GtkEntryItem menuEntry) {
|
||||||
super(systemTray, parent);
|
super(systemTray, parent);
|
||||||
|
|
||||||
|
if (menuEntry != null) {
|
||||||
|
// by default, no callback on a menu entry means it's DISABLED. we have to undo that, because we don't have a callback for menus
|
||||||
|
Gtk.gtk_widget_set_sensitive(menuEntry._native, Gtk.TRUE);
|
||||||
|
}
|
||||||
this.menuEntry = menuEntry;
|
this.menuEntry = menuEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Necessary to guarantee all updates occur on the dispatch thread
|
* Necessary to guarantee all updates occur on the dispatch thread
|
||||||
*/
|
*/
|
||||||
|
@ -123,6 +128,75 @@ class GtkMenu extends Menu implements MenuEntry {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
String getText() {
|
||||||
|
return menuEntry.getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void setText(final String newText) {
|
||||||
|
menuEntry.setText(newText);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void setImage(final File imageFile) {
|
||||||
|
menuEntry.setImage(imageFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void setImage(final String imagePath) {
|
||||||
|
menuEntry.setImage(imagePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void setImage(final URL imageUrl) {
|
||||||
|
menuEntry.setImage(imageUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void setImage(final String cacheName, final InputStream imageStream) {
|
||||||
|
menuEntry.setImage(cacheName, imageStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void setImage(final InputStream imageStream) {
|
||||||
|
menuEntry.setImage(imageStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
boolean hasImage() {
|
||||||
|
return menuEntry.hasImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public
|
||||||
|
void setCallback(final SystemTrayMenuAction callback) {
|
||||||
|
// NO OP.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when this sub-menu is removed from it's parent menu
|
||||||
|
*/
|
||||||
|
protected
|
||||||
|
void removePrivate() {
|
||||||
|
// delete all of the children
|
||||||
|
obliterateMenu();
|
||||||
|
|
||||||
|
// remove the gtk entry item from our parent menu
|
||||||
|
if (menuEntry != null) {
|
||||||
|
menuEntry.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// some GTK libraries DO NOT let us add items AFTER the menu has been attached to the indicator.
|
// 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.
|
// To work around this issue, we destroy then recreate the menu every time something is changed.
|
||||||
/**
|
/**
|
||||||
|
@ -133,10 +207,20 @@ class GtkMenu extends Menu implements MenuEntry {
|
||||||
// have to remove all other menu entries
|
// have to remove all other menu entries
|
||||||
synchronized (menuEntries) {
|
synchronized (menuEntries) {
|
||||||
for (int i = 0; i < menuEntries.size(); i++) {
|
for (int i = 0; i < menuEntries.size(); i++) {
|
||||||
GtkEntry menuEntry__ = (GtkEntry) menuEntries.get(i);
|
MenuEntry menuEntry__ = menuEntries.get(i);
|
||||||
|
|
||||||
Gobject.g_object_force_floating(menuEntry__._native);
|
if (menuEntry__ instanceof GtkEntry) {
|
||||||
Gtk.gtk_container_remove(_native, menuEntry__._native);
|
GtkEntry entry = (GtkEntry) menuEntry__;
|
||||||
|
|
||||||
|
Gobject.g_object_force_floating(entry._native);
|
||||||
|
Gtk.gtk_container_remove(_native, entry._native);
|
||||||
|
}
|
||||||
|
else if (menuEntry__ instanceof GtkMenu) {
|
||||||
|
GtkMenu subMenu = (GtkMenu) menuEntry__;
|
||||||
|
|
||||||
|
Gobject.g_object_force_floating(subMenu.menuEntry._native);
|
||||||
|
Gtk.gtk_container_remove(_native, subMenu.menuEntry._native);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Gtk.gtk_widget_destroy(_native);
|
Gtk.gtk_widget_destroy(_native);
|
||||||
|
@ -173,23 +257,27 @@ class GtkMenu extends Menu implements MenuEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < menuEntries.size(); i++) {
|
for (int i = 0; i < menuEntries.size(); i++) {
|
||||||
GtkEntry menuEntry__ = (GtkEntry) menuEntries.get(i);
|
MenuEntry menuEntry__ = menuEntries.get(i);
|
||||||
|
|
||||||
// the menu entry looks FUNKY when there are a mis-match of entries WITH and WITHOUT images
|
// the menu entry looks FUNKY when there are a mis-match of entries WITH and WITHOUT images
|
||||||
menuEntry__.setSpacerImage(hasImages);
|
if (menuEntry__ instanceof GtkEntry) {
|
||||||
|
GtkEntry entry = (GtkEntry) menuEntry__;
|
||||||
|
entry.setSpacerImage(hasImages);
|
||||||
|
|
||||||
// will also get: gsignal.c:2516: signal 'child-added' is invalid for instance '0x7f1df8244080' of type 'GtkMenu'
|
// will also get: gsignal.c:2516: signal 'child-added' is invalid for instance '0x7f1df8244080' of type 'GtkMenu'
|
||||||
Gtk.gtk_menu_shell_append(this._native, menuEntry__._native);
|
Gtk.gtk_menu_shell_append(this._native, entry._native);
|
||||||
Gobject.g_object_ref_sink(menuEntry__._native); // undoes "floating"
|
Gobject.g_object_ref_sink(entry._native); // undoes "floating"
|
||||||
|
}
|
||||||
|
else if (menuEntry__ instanceof GtkMenu) {
|
||||||
|
GtkMenu subMenu = (GtkMenu) menuEntry__;
|
||||||
|
|
||||||
if (menuEntry__ instanceof GtkEntryItem) {
|
// will also get: gsignal.c:2516: signal 'child-added' is invalid for instance '0x7f1df8244080' of type 'GtkMenu'
|
||||||
GtkMenu subMenu = ((GtkEntryItem) menuEntry__).getSubMenu();
|
Gtk.gtk_menu_shell_append(this._native, subMenu.menuEntry._native);
|
||||||
if (subMenu != null) {
|
Gobject.g_object_ref_sink(subMenu.menuEntry._native); // undoes "floating"
|
||||||
|
|
||||||
|
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
|
// we don't want to "createMenu" on our sub-menu that is assigned to us directly, as they are already doing it
|
||||||
if (subMenu.getParent() != GtkMenu.this) {
|
subMenu.createMenu();
|
||||||
subMenu.createMenu();
|
|
||||||
} else {
|
|
||||||
Gtk.gtk_widget_set_sensitive(menuEntry__._native, Gtk.TRUE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,8 +302,14 @@ class GtkMenu extends Menu implements MenuEntry {
|
||||||
// have to remove all other menu entries
|
// have to remove all other menu entries
|
||||||
synchronized (menuEntries) {
|
synchronized (menuEntries) {
|
||||||
for (int i = 0; i < menuEntries.size(); i++) {
|
for (int i = 0; i < menuEntries.size(); i++) {
|
||||||
GtkEntry menuEntry__ = (GtkEntry) menuEntries.get(i);
|
MenuEntry menuEntry__ = menuEntries.get(i);
|
||||||
menuEntry__.removePrivate();
|
|
||||||
|
if (menuEntry__ instanceof GtkEntry) {
|
||||||
|
((GtkEntry) menuEntry__).removePrivate();
|
||||||
|
}
|
||||||
|
else if (menuEntry__ instanceof GtkMenu) {
|
||||||
|
((GtkMenu) menuEntry__).removePrivate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
menuEntries.clear();
|
menuEntries.clear();
|
||||||
|
|
||||||
|
@ -295,29 +389,20 @@ class GtkMenu extends Menu implements MenuEntry {
|
||||||
// To work around this issue, we destroy then recreate the menu every time something is changed.
|
// To work around this issue, we destroy then recreate the menu every time something is changed.
|
||||||
deleteMenu();
|
deleteMenu();
|
||||||
|
|
||||||
|
GtkMenu subMenu = new GtkMenu(getSystemTray(), GtkMenu.this, new GtkEntryItem(GtkMenu.this, null));
|
||||||
|
subMenu.setText(menuText);
|
||||||
|
subMenu.setImage(imagePath);
|
||||||
|
|
||||||
menuEntry = new GtkEntryItem(GtkMenu.this, null);
|
menuEntries.add(subMenu);
|
||||||
Gtk.gtk_widget_set_sensitive(_native, Gtk.TRUE); // submenu needs to be active
|
|
||||||
menuEntry.setText(menuText);
|
|
||||||
menuEntry.setImage(imagePath);
|
|
||||||
menuEntries.add(menuEntry);
|
|
||||||
|
|
||||||
GtkMenu subMenu = new GtkMenu(getSystemTray(), GtkMenu.this, (GtkEntryItem) menuEntry);
|
|
||||||
|
|
||||||
((GtkEntryItem) menuEntry).setSubMenu(subMenu);
|
|
||||||
|
|
||||||
value.set(subMenu);
|
value.set(subMenu);
|
||||||
|
|
||||||
createMenu();
|
createMenu();
|
||||||
} else if (menuEntry instanceof GtkEntryItem) {
|
} else if (menuEntry instanceof GtkMenu) {
|
||||||
GtkMenu subMenu = ((GtkEntryItem) menuEntry).getSubMenu();
|
menuEntry.setText(menuText);
|
||||||
if (subMenu != null) {
|
menuEntry.setImage(imagePath);
|
||||||
|
|
||||||
menuEntry.setText(menuText);
|
value.set(((GtkMenu) menuEntry));
|
||||||
menuEntry.setImage(imagePath);
|
|
||||||
|
|
||||||
value.set(subMenu);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -326,63 +411,20 @@ class GtkMenu extends Menu implements MenuEntry {
|
||||||
return value.get();
|
return value.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
String getText() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void setText(final String newText) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void setImage(final File imageFile) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void setImage(final String imagePath) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void setImage(final URL imageUrl) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void setImage(final String cacheName, final InputStream imageStream) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void setImage(final InputStream imageStream) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
boolean hasImage() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public
|
|
||||||
void setCallback(final SystemTrayMenuAction callback) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void remove() {
|
void remove() {
|
||||||
|
GtkMenu parent = (GtkMenu) getParent();
|
||||||
|
|
||||||
|
Gtk.gtk_container_remove(parent._native, _native);
|
||||||
|
Gtk.gtk_menu_shell_deactivate(parent._native, _native);
|
||||||
|
|
||||||
|
removePrivate();
|
||||||
|
|
||||||
|
Gtk.gtk_widget_destroy(_native);
|
||||||
|
|
||||||
|
// have to rebuild the menu now...
|
||||||
|
parent.deleteMenu();
|
||||||
|
parent.createMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue