forked from dorkbox/SystemTray
Fixed issue #5, fix involves issues surrounding Arch distro's using an old version of libappindicator (which is buggy), and various workarounds necessary to show/edit the system tray
This commit is contained in:
parent
3092e6ad11
commit
1a28dcb406
@ -17,6 +17,7 @@ package dorkbox.util.tray;
|
|||||||
|
|
||||||
import dorkbox.util.OS;
|
import dorkbox.util.OS;
|
||||||
import dorkbox.util.jna.linux.AppIndicator;
|
import dorkbox.util.jna.linux.AppIndicator;
|
||||||
|
import dorkbox.util.jna.linux.AppIndicatorQuery;
|
||||||
import dorkbox.util.jna.linux.GtkSupport;
|
import dorkbox.util.jna.linux.GtkSupport;
|
||||||
import dorkbox.util.process.ShellProcessBuilder;
|
import dorkbox.util.process.ShellProcessBuilder;
|
||||||
import dorkbox.util.tray.linux.AppIndicatorTray;
|
import dorkbox.util.tray.linux.AppIndicatorTray;
|
||||||
@ -96,8 +97,13 @@ class SystemTray {
|
|||||||
}
|
}
|
||||||
else if ("XFCE".equalsIgnoreCase(XDG)) {
|
else if ("XFCE".equalsIgnoreCase(XDG)) {
|
||||||
// XFCE uses a BAD version of libappindicator by default, which DOES NOT support images in the menu.
|
// XFCE uses a BAD version of libappindicator by default, which DOES NOT support images in the menu.
|
||||||
|
// if we have libappindicator1, we are OK. if we don't, fallback to GTKSystemTray
|
||||||
try {
|
try {
|
||||||
|
if (AppIndicatorQuery.get_v1() != null) {
|
||||||
|
trayType = AppIndicatorTray.class;
|
||||||
|
} else {
|
||||||
trayType = GtkSystemTray.class;
|
trayType = GtkSystemTray.class;
|
||||||
|
}
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,19 +30,19 @@ import dorkbox.util.jna.linux.GtkSupport;
|
|||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
class AppIndicatorTray extends GtkTypeSystemTray {
|
class AppIndicatorTray extends GtkTypeSystemTray {
|
||||||
private static final AppIndicator libappindicator = AppIndicator.INSTANCE;
|
private static final AppIndicator appindicator = AppIndicator.INSTANCE;
|
||||||
|
|
||||||
private AppIndicator.AppIndicatorInstanceStruct appIndicator;
|
private AppIndicator.AppIndicatorInstanceStruct appIndicator;
|
||||||
|
|
||||||
public
|
public
|
||||||
AppIndicatorTray(String iconName) {
|
AppIndicatorTray(String iconName) {
|
||||||
libgtk.gdk_threads_enter();
|
gtk.gdk_threads_enter();
|
||||||
String icon_name = iconPath(iconName);
|
String icon_name = iconPath(iconName);
|
||||||
this.appIndicator = libappindicator.app_indicator_new(System.nanoTime() + "DBST", icon_name,
|
this.appIndicator = appindicator.app_indicator_new(System.nanoTime() + "DBST", icon_name,
|
||||||
AppIndicator.CATEGORY_APPLICATION_STATUS);
|
AppIndicator.CATEGORY_APPLICATION_STATUS);
|
||||||
libappindicator.app_indicator_set_status(this.appIndicator, AppIndicator.STATUS_ACTIVE);
|
appindicator.app_indicator_set_status(this.appIndicator, AppIndicator.STATUS_ACTIVE);
|
||||||
|
|
||||||
libgtk.gdk_threads_leave();
|
gtk.gdk_threads_leave();
|
||||||
|
|
||||||
GtkSupport.startGui();
|
GtkSupport.startGui();
|
||||||
}
|
}
|
||||||
@ -50,26 +50,26 @@ class AppIndicatorTray extends GtkTypeSystemTray {
|
|||||||
@Override
|
@Override
|
||||||
public synchronized
|
public synchronized
|
||||||
void shutdown() {
|
void shutdown() {
|
||||||
libgtk.gdk_threads_enter();
|
gtk.gdk_threads_enter();
|
||||||
|
|
||||||
// this hides the indicator
|
// this hides the indicator
|
||||||
libappindicator.app_indicator_set_status(this.appIndicator, AppIndicator.STATUS_PASSIVE);
|
appindicator.app_indicator_set_status(this.appIndicator, AppIndicator.STATUS_PASSIVE);
|
||||||
Pointer p = this.appIndicator.getPointer();
|
Pointer p = this.appIndicator.getPointer();
|
||||||
libgobject.g_object_unref(p);
|
gobject.g_object_unref(p);
|
||||||
|
|
||||||
// GC it
|
// GC it
|
||||||
this.appIndicator = null;
|
this.appIndicator = null;
|
||||||
|
|
||||||
// libgtk.gdk_threads_leave(); called by parent class
|
// libgtk.gdk_threads_leave(); called by super class
|
||||||
super.shutdown();
|
super.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized
|
public synchronized
|
||||||
void setIcon(final String iconName) {
|
void setIcon(final String iconName) {
|
||||||
libgtk.gdk_threads_enter();
|
gtk.gdk_threads_enter();
|
||||||
libappindicator.app_indicator_set_icon(this.appIndicator, iconPath(iconName));
|
appindicator.app_indicator_set_icon(this.appIndicator, iconPath(iconName));
|
||||||
libgtk.gdk_threads_leave();
|
gtk.gdk_threads_leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -78,6 +78,6 @@ class AppIndicatorTray extends GtkTypeSystemTray {
|
|||||||
*/
|
*/
|
||||||
protected
|
protected
|
||||||
void onMenuAdded(final Pointer menu) {
|
void onMenuAdded(final Pointer menu) {
|
||||||
libappindicator.app_indicator_set_menu(this.appIndicator, menu);
|
appindicator.app_indicator_set_menu(this.appIndicator, menu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,8 @@ import dorkbox.util.tray.MenuEntry;
|
|||||||
import dorkbox.util.tray.SystemTrayMenuAction;
|
import dorkbox.util.tray.SystemTrayMenuAction;
|
||||||
|
|
||||||
class GtkMenuEntry implements MenuEntry {
|
class GtkMenuEntry implements MenuEntry {
|
||||||
private static final Gtk libgtk = Gtk.INSTANCE;
|
private static final Gtk gtk = Gtk.INSTANCE;
|
||||||
private static final Gobject libgobject = Gobject.INSTANCE;
|
private static final Gobject gobject = Gobject.INSTANCE;
|
||||||
|
|
||||||
private final GCallback gtkCallback;
|
private final GCallback gtkCallback;
|
||||||
final Pointer menuItem;
|
final Pointer menuItem;
|
||||||
@ -55,20 +55,20 @@ class GtkMenuEntry implements MenuEntry {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
menuItem = libgtk.gtk_image_menu_item_new_with_label(label);
|
menuItem = gtk.gtk_image_menu_item_new_with_label(label);
|
||||||
|
|
||||||
if (imagePath != null && !imagePath.isEmpty()) {
|
if (imagePath != null && !imagePath.isEmpty()) {
|
||||||
// NOTE: XFCE uses appindicator3, which DOES NOT support images in the menu. This change was reverted.
|
// NOTE: XFCE uses appindicator3, which DOES NOT support images in the menu. This change was reverted.
|
||||||
// see: https://ask.fedoraproject.org/en/question/23116/how-to-fix-missing-icons-in-program-menus-and-context-menus/
|
// see: https://ask.fedoraproject.org/en/question/23116/how-to-fix-missing-icons-in-program-menus-and-context-menus/
|
||||||
// see: https://git.gnome.org/browse/gtk+/commit/?id=627a03683f5f41efbfc86cc0f10e1b7c11e9bb25
|
// see: https://git.gnome.org/browse/gtk+/commit/?id=627a03683f5f41efbfc86cc0f10e1b7c11e9bb25
|
||||||
image = libgtk.gtk_image_new_from_file(imagePath);
|
image = gtk.gtk_image_new_from_file(imagePath);
|
||||||
|
|
||||||
libgtk.gtk_image_menu_item_set_image(menuItem, image);
|
gtk.gtk_image_menu_item_set_image(menuItem, image);
|
||||||
// must always re-set always-show after setting the image
|
// must always re-set always-show after setting the image
|
||||||
libgtk.gtk_image_menu_item_set_always_show_image(menuItem, Gtk.TRUE);
|
gtk.gtk_image_menu_item_set_always_show_image(menuItem, Gtk.TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
nativeLong = libgobject.g_signal_connect_data(menuItem, "activate", gtkCallback, null, null, 0);
|
nativeLong = gobject.g_signal_connect_data(menuItem, "activate", gtkCallback, null, null, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private
|
private
|
||||||
@ -95,38 +95,36 @@ class GtkMenuEntry implements MenuEntry {
|
|||||||
public
|
public
|
||||||
void setText(final String newText) {
|
void setText(final String newText) {
|
||||||
this.text = newText;
|
this.text = newText;
|
||||||
libgtk.gdk_threads_enter();
|
gtk.gdk_threads_enter();
|
||||||
|
|
||||||
libgtk.gtk_menu_item_set_label(menuItem, newText);
|
gtk.gtk_menu_item_set_label(menuItem, newText);
|
||||||
|
|
||||||
libgtk.gtk_widget_show_all(parentMenu);
|
gtk.gtk_widget_show_all(parentMenu);
|
||||||
|
|
||||||
libgtk.gdk_threads_leave();
|
gtk.gdk_threads_leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setImage(final String imagePath) {
|
void setImage(final String imagePath) {
|
||||||
libgtk.gdk_threads_enter();
|
gtk.gdk_threads_enter();
|
||||||
|
|
||||||
if (imagePath != null && !imagePath.isEmpty()) {
|
if (imagePath != null && !imagePath.isEmpty()) {
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
libgtk.gtk_widget_destroy(image);
|
gtk.gtk_widget_destroy(image);
|
||||||
}
|
}
|
||||||
libgtk.gtk_widget_show_all(parentMenu);
|
gtk.gtk_widget_show_all(parentMenu);
|
||||||
libgtk.gdk_threads_leave();
|
|
||||||
|
|
||||||
libgtk.gdk_threads_enter();
|
image = gtk.gtk_image_new_from_file(imagePath);
|
||||||
image = libgtk.gtk_image_new_from_file(imagePath);
|
|
||||||
|
|
||||||
libgtk.gtk_image_menu_item_set_image(menuItem, image);
|
gtk.gtk_image_menu_item_set_image(menuItem, image);
|
||||||
|
|
||||||
// must always re-set always-show after setting the image
|
// must always re-set always-show after setting the image
|
||||||
libgtk.gtk_image_menu_item_set_always_show_image(menuItem, Gtk.TRUE);
|
gtk.gtk_image_menu_item_set_always_show_image(menuItem, Gtk.TRUE);
|
||||||
}
|
}
|
||||||
libgtk.gtk_widget_show_all(parentMenu);
|
|
||||||
|
|
||||||
libgtk.gdk_threads_leave();
|
gtk.gdk_threads_leave();
|
||||||
|
gtk.gtk_widget_show_all(parentMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -140,7 +138,7 @@ class GtkMenuEntry implements MenuEntry {
|
|||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
void remove() {
|
void remove() {
|
||||||
libgtk.gdk_threads_enter();
|
gtk.gdk_threads_enter();
|
||||||
|
|
||||||
removePrivate();
|
removePrivate();
|
||||||
|
|
||||||
@ -148,17 +146,17 @@ class GtkMenuEntry implements MenuEntry {
|
|||||||
systemTray.deleteMenu();
|
systemTray.deleteMenu();
|
||||||
systemTray.createMenu();
|
systemTray.createMenu();
|
||||||
|
|
||||||
libgtk.gdk_threads_leave();
|
gtk.gdk_threads_leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
void removePrivate() {
|
void removePrivate() {
|
||||||
libgobject.g_signal_handler_disconnect(menuItem, nativeLong);
|
gobject.g_signal_handler_disconnect(menuItem, nativeLong);
|
||||||
libgtk.gtk_menu_shell_deactivate(parentMenu, menuItem);
|
gtk.gtk_menu_shell_deactivate(parentMenu, menuItem);
|
||||||
|
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
libgtk.gtk_widget_destroy(image);
|
gtk.gtk_widget_destroy(image);
|
||||||
}
|
}
|
||||||
libgtk.gtk_widget_destroy(menuItem);
|
gtk.gtk_widget_destroy(menuItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -40,15 +40,15 @@ class GtkSystemTray extends GtkTypeSystemTray {
|
|||||||
GtkSystemTray(String iconName) {
|
GtkSystemTray(String iconName) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
libgtk.gdk_threads_enter();
|
gtk.gdk_threads_enter();
|
||||||
|
|
||||||
final Pointer trayIcon = libgtk.gtk_status_icon_new();
|
final Pointer trayIcon = gtk.gtk_status_icon_new();
|
||||||
libgtk.gtk_status_icon_set_title(trayIcon, "SystemTray@Dorkbox");
|
gtk.gtk_status_icon_set_title(trayIcon, "SystemTray@Dorkbox");
|
||||||
libgtk.gtk_status_icon_set_name(trayIcon, "SystemTray");
|
gtk.gtk_status_icon_set_name(trayIcon, "SystemTray");
|
||||||
|
|
||||||
this.trayIcon = trayIcon;
|
this.trayIcon = trayIcon;
|
||||||
|
|
||||||
libgtk.gtk_status_icon_set_from_file(trayIcon, iconPath(iconName));
|
gtk.gtk_status_icon_set_from_file(trayIcon, iconPath(iconName));
|
||||||
|
|
||||||
this.gtkCallback = new Gobject.GEventCallback() {
|
this.gtkCallback = new Gobject.GEventCallback() {
|
||||||
@Override
|
@Override
|
||||||
@ -56,15 +56,15 @@ class GtkSystemTray extends GtkTypeSystemTray {
|
|||||||
void callback(Pointer notUsed, final Gtk.GdkEventButton event) {
|
void callback(Pointer notUsed, final Gtk.GdkEventButton event) {
|
||||||
// BUTTON_PRESS only (any mouse click)
|
// BUTTON_PRESS only (any mouse click)
|
||||||
if (event.type == 4) {
|
if (event.type == 4) {
|
||||||
libgtk.gtk_menu_popup(menu, null, null, Gtk.gtk_status_icon_position_menu, trayIcon, 0, event.time);
|
gtk.gtk_menu_popup(menu, null, null, Gtk.gtk_status_icon_position_menu, trayIcon, 0, event.time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
button_press_event = libgobject.g_signal_connect_data(trayIcon, "button_press_event", gtkCallback, null, null, 0);
|
button_press_event = gobject.g_signal_connect_data(trayIcon, "button_press_event", gtkCallback, null, null, 0);
|
||||||
|
|
||||||
libgtk.gtk_status_icon_set_visible(trayIcon, true);
|
gtk.gtk_status_icon_set_visible(trayIcon, true);
|
||||||
|
|
||||||
libgtk.gdk_threads_leave();
|
gtk.gdk_threads_leave();
|
||||||
|
|
||||||
GtkSupport.startGui();
|
GtkSupport.startGui();
|
||||||
}
|
}
|
||||||
@ -81,11 +81,11 @@ class GtkSystemTray extends GtkTypeSystemTray {
|
|||||||
@Override
|
@Override
|
||||||
public synchronized
|
public synchronized
|
||||||
void shutdown() {
|
void shutdown() {
|
||||||
libgtk.gdk_threads_enter();
|
gtk.gdk_threads_enter();
|
||||||
|
|
||||||
// this hides the indicator
|
// this hides the indicator
|
||||||
libgtk.gtk_status_icon_set_visible(this.trayIcon, false);
|
gtk.gtk_status_icon_set_visible(this.trayIcon, false);
|
||||||
libgobject.g_object_unref(this.trayIcon);
|
gobject.g_object_unref(this.trayIcon);
|
||||||
|
|
||||||
// GC it
|
// GC it
|
||||||
this.trayIcon = null;
|
this.trayIcon = null;
|
||||||
@ -97,8 +97,8 @@ class GtkSystemTray extends GtkTypeSystemTray {
|
|||||||
@Override
|
@Override
|
||||||
public synchronized
|
public synchronized
|
||||||
void setIcon(final String iconName) {
|
void setIcon(final String iconName) {
|
||||||
libgtk.gdk_threads_enter();
|
gtk.gdk_threads_enter();
|
||||||
libgtk.gtk_status_icon_set_from_file(trayIcon, iconPath(iconName));
|
gtk.gtk_status_icon_set_from_file(trayIcon, iconPath(iconName));
|
||||||
libgtk.gdk_threads_leave();
|
gtk.gdk_threads_leave();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,9 @@ import java.util.concurrent.Executors;
|
|||||||
|
|
||||||
public abstract
|
public abstract
|
||||||
class GtkTypeSystemTray extends SystemTray {
|
class GtkTypeSystemTray extends SystemTray {
|
||||||
protected static final Gobject libgobject = Gobject.INSTANCE;
|
protected static final Gobject gobject = Gobject.INSTANCE;
|
||||||
protected static final Gtk libgtk = Gtk.INSTANCE;
|
protected static final Gtk gtk = Gtk.INSTANCE;
|
||||||
|
// protected static final GLib glib = GLib.INSTANCE;
|
||||||
|
|
||||||
final static ExecutorService callbackExecutor = Executors.newSingleThreadExecutor(new NamedThreadFactory("SysTrayExecutor", false));
|
final static ExecutorService callbackExecutor = Executors.newSingleThreadExecutor(new NamedThreadFactory("SysTrayExecutor", false));
|
||||||
|
|
||||||
@ -44,38 +45,38 @@ class GtkTypeSystemTray extends SystemTray {
|
|||||||
obliterateMenu();
|
obliterateMenu();
|
||||||
GtkSupport.shutdownGui();
|
GtkSupport.shutdownGui();
|
||||||
|
|
||||||
libgtk.gdk_threads_leave();
|
gtk.gdk_threads_leave();
|
||||||
|
|
||||||
callbackExecutor.shutdown();
|
callbackExecutor.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized
|
public synchronized
|
||||||
void setStatus(String infoString) {
|
void setStatus(final String infoString) {
|
||||||
libgtk.gdk_threads_enter();
|
gtk.gdk_threads_enter();
|
||||||
|
|
||||||
if (this.connectionStatusItem == null && infoString != null && !infoString.isEmpty()) {
|
if (this.connectionStatusItem == null && infoString != null && !infoString.isEmpty()) {
|
||||||
deleteMenu();
|
deleteMenu();
|
||||||
|
|
||||||
this.connectionStatusItem = libgtk.gtk_menu_item_new_with_label("");
|
this.connectionStatusItem = gtk.gtk_menu_item_new_with_label("");
|
||||||
libgobject.g_object_ref(connectionStatusItem); // so it matches with 'createMenu'
|
gobject.g_object_ref(connectionStatusItem); // so it matches with 'createMenu'
|
||||||
|
|
||||||
// evil hacks abound...
|
// evil hacks abound...
|
||||||
Pointer label = libgtk.gtk_bin_get_child(connectionStatusItem);
|
Pointer label = gtk.gtk_bin_get_child(connectionStatusItem);
|
||||||
libgtk.gtk_label_set_use_markup(label, Gtk.TRUE);
|
gtk.gtk_label_set_use_markup(label, Gtk.TRUE);
|
||||||
Pointer markup = libgobject.g_markup_printf_escaped("<b>%s</b>", infoString);
|
Pointer markup = gobject.g_markup_printf_escaped("<b>%s</b>", infoString);
|
||||||
libgtk.gtk_label_set_markup(label, markup);
|
gtk.gtk_label_set_markup(label, markup);
|
||||||
libgobject.g_free(markup);
|
gobject.g_free(markup);
|
||||||
|
|
||||||
|
|
||||||
libgtk.gtk_widget_set_sensitive(this.connectionStatusItem, Gtk.FALSE);
|
gtk.gtk_widget_set_sensitive(this.connectionStatusItem, Gtk.FALSE);
|
||||||
|
|
||||||
createMenu();
|
createMenu();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (infoString == null || infoString.isEmpty()) {
|
if (infoString == null || infoString.isEmpty()) {
|
||||||
deleteMenu();
|
deleteMenu();
|
||||||
libgtk.gtk_widget_destroy(connectionStatusItem);
|
gtk.gtk_widget_destroy(connectionStatusItem);
|
||||||
connectionStatusItem = null;
|
connectionStatusItem = null;
|
||||||
|
|
||||||
createMenu();
|
createMenu();
|
||||||
@ -85,17 +86,17 @@ class GtkTypeSystemTray extends SystemTray {
|
|||||||
// libgtk.gtk_menu_item_set_label(this.connectionStatusItem, infoString);
|
// libgtk.gtk_menu_item_set_label(this.connectionStatusItem, infoString);
|
||||||
|
|
||||||
// evil hacks abound...
|
// evil hacks abound...
|
||||||
Pointer label = libgtk.gtk_bin_get_child(connectionStatusItem);
|
Pointer label = gtk.gtk_bin_get_child(connectionStatusItem);
|
||||||
libgtk.gtk_label_set_use_markup(label, Gtk.TRUE);
|
gtk.gtk_label_set_use_markup(label, Gtk.TRUE);
|
||||||
Pointer markup = libgobject.g_markup_printf_escaped("<b>%s</b>", infoString);
|
Pointer markup = gobject.g_markup_printf_escaped("<b>%s</b>", infoString);
|
||||||
libgtk.gtk_label_set_markup(label, markup);
|
gtk.gtk_label_set_markup(label, markup);
|
||||||
libgobject.g_free(markup);
|
gobject.g_free(markup);
|
||||||
|
|
||||||
libgtk.gtk_widget_show_all(menu);
|
gtk.gtk_widget_show_all(menu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
libgtk.gdk_threads_leave();
|
gtk.gdk_threads_leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -115,7 +116,7 @@ class GtkTypeSystemTray extends SystemTray {
|
|||||||
if (menu != null) {
|
if (menu != null) {
|
||||||
// have to remove status from menu
|
// have to remove status from menu
|
||||||
if (connectionStatusItem != null) {
|
if (connectionStatusItem != null) {
|
||||||
libgtk.gtk_widget_destroy(connectionStatusItem);
|
gtk.gtk_widget_destroy(connectionStatusItem);
|
||||||
connectionStatusItem = null;
|
connectionStatusItem = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +129,7 @@ class GtkTypeSystemTray extends SystemTray {
|
|||||||
menuEntries.clear();
|
menuEntries.clear();
|
||||||
|
|
||||||
// GTK menu needs a "ref_sink"
|
// GTK menu needs a "ref_sink"
|
||||||
libgobject.g_object_ref_sink(menu);
|
gobject.g_object_ref_sink(menu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,37 +140,32 @@ class GtkTypeSystemTray extends SystemTray {
|
|||||||
if (menu != null) {
|
if (menu != null) {
|
||||||
// have to remove status from menu
|
// have to remove status from menu
|
||||||
if (connectionStatusItem != null) {
|
if (connectionStatusItem != null) {
|
||||||
libgobject.g_object_ref(connectionStatusItem);
|
gobject.g_object_ref(connectionStatusItem);
|
||||||
|
|
||||||
libgtk.gtk_container_remove(menu, connectionStatusItem);
|
gtk.gtk_container_remove(menu, connectionStatusItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// have to remove all other menu entries
|
// have to remove all other menu entries
|
||||||
for (int i = 0; i < menuEntries.size(); i++) {
|
for (int i = 0; i < menuEntries.size(); i++) {
|
||||||
GtkMenuEntry menuEntry__ = (GtkMenuEntry) menuEntries.get(i);
|
GtkMenuEntry menuEntry__ = (GtkMenuEntry) menuEntries.get(i);
|
||||||
|
|
||||||
libgobject.g_object_ref(menuEntry__.menuItem);
|
gobject.g_object_ref(menuEntry__.menuItem);
|
||||||
libgtk.gtk_container_remove(menu, menuEntry__.menuItem);
|
gtk.gtk_container_remove(menu, menuEntry__.menuItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// GTK menu needs a "ref_sink"
|
// GTK menu needs a "ref_sink"
|
||||||
libgobject.g_object_ref_sink(menu);
|
gobject.g_object_ref_sink(menu);
|
||||||
|
|
||||||
// have to 'blip' the thread, so that the state can catch up. Stupid, i know, and I am open to suggestions to fixing bizzare
|
|
||||||
// race conditions with GTK...
|
|
||||||
libgtk.gdk_threads_leave();
|
|
||||||
libgtk.gdk_threads_enter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
menu = libgtk.gtk_menu_new();
|
menu = gtk.gtk_menu_new();
|
||||||
}
|
}
|
||||||
|
|
||||||
// UNSAFE. must be protected inside synchronized, and inside threads_enter/exit
|
// UNSAFE. must be protected inside synchronized, and inside threads_enter/exit
|
||||||
void createMenu() {
|
void createMenu() {
|
||||||
// now add status
|
// now add status
|
||||||
if (connectionStatusItem != null) {
|
if (connectionStatusItem != null) {
|
||||||
libgtk.gtk_menu_shell_append(this.menu, this.connectionStatusItem);
|
gtk.gtk_menu_shell_append(this.menu, this.connectionStatusItem);
|
||||||
libgobject.g_object_unref(connectionStatusItem);
|
gobject.g_object_unref(connectionStatusItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// now add back other menu entries
|
// now add back other menu entries
|
||||||
@ -177,12 +173,12 @@ class GtkTypeSystemTray extends SystemTray {
|
|||||||
GtkMenuEntry menuEntry__ = (GtkMenuEntry) menuEntries.get(i);
|
GtkMenuEntry menuEntry__ = (GtkMenuEntry) menuEntries.get(i);
|
||||||
|
|
||||||
// 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'
|
||||||
libgtk.gtk_menu_shell_append(this.menu, menuEntry__.menuItem);
|
gtk.gtk_menu_shell_append(this.menu, menuEntry__.menuItem);
|
||||||
libgobject.g_object_unref(menuEntry__.menuItem);
|
gobject.g_object_unref(menuEntry__.menuItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMenuAdded(menu);
|
onMenuAdded(menu);
|
||||||
libgtk.gtk_widget_show_all(menu);
|
gtk.gtk_widget_show_all(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -201,7 +197,7 @@ class GtkTypeSystemTray extends SystemTray {
|
|||||||
throw new IllegalArgumentException("Menu entry already exists for given label '" + menuText + "'");
|
throw new IllegalArgumentException("Menu entry already exists for given label '" + menuText + "'");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
libgtk.gdk_threads_enter();
|
gtk.gdk_threads_enter();
|
||||||
|
|
||||||
// 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 one is added.
|
// To work around this issue, we destroy then recreate the menu every time one is added.
|
||||||
@ -209,12 +205,12 @@ class GtkTypeSystemTray extends SystemTray {
|
|||||||
|
|
||||||
menuEntry = new GtkMenuEntry(menu, menuText, imagePath, callback, this);
|
menuEntry = new GtkMenuEntry(menu, menuText, imagePath, callback, this);
|
||||||
|
|
||||||
libgobject.g_object_ref(menuEntry.menuItem); // so it matches with 'createMenu'
|
gobject.g_object_ref(menuEntry.menuItem); // so it matches with 'createMenu'
|
||||||
this.menuEntries.add(menuEntry);
|
this.menuEntries.add(menuEntry);
|
||||||
|
|
||||||
createMenu();
|
createMenu();
|
||||||
|
|
||||||
libgtk.gdk_threads_leave();
|
gtk.gdk_threads_leave();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user