commit 5420ac3f72571a2eb73918e41c59834100469ce2
parent 3fcbff751fa7f2b447d290212da3317e6db2024d
Author: Janne Veteläinen <janne.vetelainen@elisanet.fi>
Date: Mon, 15 Apr 2024 14:44:05 +0300
Merge testing branch -- add dynamically changing menus and lots of refactoring
Diffstat:
| M | dbusmenu.c | | | 256 | +++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------- |
| M | dwlb.c | | | 82 | +++++++++++++++++++++++++++++++++++++++++++++---------------------------------- |
| M | dwlbtray.c | | | 18 | +++++++++++++++++- |
| M | dwlbtray.h | | | 30 | +++++++++++------------------- |
| M | statusnotifierhost.c | | | 258 | +++++++++++++++++++++++++++++++++++++++++++++++++------------------------------ |
| M | statusnotifieritem.c | | | 249 | ++++++++++++++++++++++++++++++++++++++++++++++++------------------------------- |
6 files changed, 551 insertions(+), 342 deletions(-)
diff --git a/dbusmenu.c b/dbusmenu.c
@@ -1,3 +1,6 @@
+/*
+ * This whole thing is a mess .......
+ */
#include <time.h>
#include <glib.h>
@@ -11,8 +14,6 @@ static GMenu* create_menumodel(GVariant *data, StatusNotifierItem *snitem);
static void
action_activated_cb(GSimpleAction *action, GVariant* param, ActionCallbackData *data)
{
- // GError *err = NULL;
-
g_dbus_proxy_call(data->proxy,
"Event",
g_variant_new("(isvu)",
@@ -25,26 +26,6 @@ action_activated_cb(GSimpleAction *action, GVariant* param, ActionCallbackData *
NULL,
NULL,
NULL);
- /*
- GVariant *retval = g_dbus_proxy_call_sync(data->proxy,
- "Event",
- g_variant_new("(isvu)",
- data->id,
- "clicked",
- g_variant_new_string(""),
- time(NULL)),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- NULL,
- &err);
-
- if (err) {
- fprintf(stderr, "%s\n", err->message);
- g_error_free(err);
- } else {
- g_variant_unref(retval);
- }
- */
}
@@ -67,6 +48,28 @@ create_action(uint32_t id, StatusNotifierItem *snitem)
}
+static gboolean
+check_has_sections(GVariant *data, StatusNotifierItem *snitem)
+{
+ gboolean ret = FALSE;
+ char *val;
+ GVariant *menuitem_data;
+
+ GVariantIter iter;
+ g_variant_iter_init(&iter, data);
+ while ((g_variant_iter_next(&iter, "v", &menuitem_data))) {
+ GVariant *menu_data = g_variant_get_child_value(menuitem_data, 1);
+ gboolean check = g_variant_lookup(menu_data, "type", "&s", &val);
+ if (check && strcmp(val, "separator") == 0)
+ ret = TRUE;
+ g_variant_unref(menu_data);
+ }
+
+ return ret;
+}
+
+
+//TODO: Ignore visible=false items
static GMenuItem*
create_menuitem(GVariant *data, StatusNotifierItem *snitem)
{
@@ -87,7 +90,7 @@ create_menuitem(GVariant *data, StatusNotifierItem *snitem)
gboolean isvisible = TRUE;
gboolean has_submenu = FALSE;
- /* TODO: dynamic menu updates
+ /*
* gboolean ischeckmark = FALSE;
* gboolean isradio = FALSE;
* int32_t toggle_state = 99;
@@ -102,16 +105,18 @@ create_menuitem(GVariant *data, StatusNotifierItem *snitem)
g_variant_dict_lookup(&dict, "enabled", "b", &isenabled);
g_variant_dict_lookup(&dict, "visible", "b", &isvisible);
g_variant_dict_lookup(&dict, "children-display", "&s", &has_submenu_s);
- /* TODO: dynamic menu updates
+
+ /*
* g_variant_dict_lookup(&dict, "toggle-type", "&s", &toggle_type);
* g_variant_dict_lookup(&dict, "toggle-state", "i", &toggle_state);
*/
+
g_variant_dict_clear(&dict);
if (has_submenu_s && strcmp(has_submenu_s, "submenu") == 0)
has_submenu = TRUE;
- /* TODO: dynamic menu updates
+ /*
* if (toggle_type && strcmp(toggle_type, "checkmark") == 0)
* ischeckmark = TRUE;
* else if (toggle_type && strcmp(toggle_type, "radio") == 0)
@@ -127,9 +132,8 @@ create_menuitem(GVariant *data, StatusNotifierItem *snitem)
g_free(action_name);
g_object_unref(action);
- } else if ((label && (!isvisible || !isenabled)) && !(type && strcmp(type, "separator") == 0)) {
- if (!isvisible)
- g_debug("menuitem %i, label %s should be invisible\n", id, label);
+
+ } else if ((label && !(type && strcmp(type, "separator") == 0))) {
GSimpleAction *action = create_action(id, snitem);
g_simple_action_set_enabled(action, FALSE);
char *action_name = g_strdup_printf("%s.%u", "menuitem", id);
@@ -150,6 +154,7 @@ create_menuitem(GVariant *data, StatusNotifierItem *snitem)
}
g_variant_unref(menu_data);
+ g_variant_unref(data);
return menuitem;
}
@@ -158,38 +163,40 @@ create_menuitem(GVariant *data, StatusNotifierItem *snitem)
static GMenu*
create_menumodel(GVariant *data, StatusNotifierItem *snitem)
{
- GMenu *ret = NULL;
-
+ GMenu *ret = g_menu_new();
GVariantIter iter;
GVariant *menuitem_data;
- gboolean has_sections = FALSE;
- GMenu *menu = g_menu_new();
- GMenu *section = g_menu_new();
- g_variant_iter_init(&iter, data);
-
- while ((g_variant_iter_next(&iter, "v", &menuitem_data))) {
- GMenuItem *menuitem = create_menuitem(menuitem_data, snitem);
- if (menuitem) {
- g_menu_append_item(section, menuitem);
- g_object_unref(menuitem);
- }
- else {
- g_menu_append_section(menu, NULL, G_MENU_MODEL(section));
- g_object_unref(section);
- has_sections = TRUE;
- section = g_menu_new();
- }
-
- g_variant_unref(menuitem_data);
- }
+ gboolean has_sections = check_has_sections(data, snitem);
if (has_sections) {
- g_menu_append_section(menu, NULL, G_MENU_MODEL(section));
- ret = menu;
+ GMenu *section = g_menu_new();
+ g_variant_iter_init(&iter, data);
+ while ((g_variant_iter_next(&iter, "v", &menuitem_data))) {
+ GMenuItem *menuitem = create_menuitem(menuitem_data, snitem);
+ if (menuitem) {
+ g_menu_append_item(section, menuitem);
+ g_object_unref(menuitem);
+ }
+ else {
+ g_menu_append_section(ret, NULL, G_MENU_MODEL(section));
+ g_object_unref(section);
+ section = g_menu_new();
+ }
+ g_variant_unref(menuitem_data);
+ }
+ g_menu_append_section(ret, NULL, G_MENU_MODEL(section));
g_object_unref(section);
+
} else {
- ret = section;
- g_object_unref(menu);
+ g_variant_iter_init(&iter, data);
+ while ((g_variant_iter_next(&iter, "v", &menuitem_data))) {
+ GMenuItem *menuitem = create_menuitem(menuitem_data, snitem);
+ if (menuitem) {
+ g_menu_append_item(ret, menuitem);
+ g_object_unref(menuitem);
+ }
+ g_variant_unref(menuitem_data);
+ }
}
return ret;
@@ -203,50 +210,86 @@ on_menulayout_ready(GDBusProxy *proxy, GAsyncResult *res, StatusNotifierItem *sn
GVariant *data = g_dbus_proxy_call_finish(proxy, res, &err);
// (u(ia{sv}av))
- if (err) {
- // Sometimes apps send update messages just as they are closing
- // So the dbus object might not exist in this case
- g_debug("%s\n", err->message);
+ // "No such object path '/NO_DBUSMENU'"
+ // generated by QBittorrent when it sends a broken trayitem on startup
+ // and replaces it later
+ if (err && g_error_matches(err, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_OBJECT)) {
+ g_error_free(err);
+ return;
+ } else if (err) {
+ g_warning("%sfrom on_menulayout_ready\n", err->message);
g_error_free(err);
-
return;
}
-
- uint32_t revision;
+ uint32_t revision = 0;
GVariant *layout;
- // (ia{sv}av)
- // uint32_t GVariant * GVariant *
- // 0, {"children-display": "submenu"}, {GVariant *menuitem, GVariant *menuitem ...}
GVariant *menuitems;
- // (ia{sv}av)
- // uint32_t GVariant * GVariant *
- // 1, {"label": "foobar", ...}, {GVariant *menuitem, GVariant *menuitem ...}
g_variant_get_child(data, 0, "u", &revision);
- if (snitem->menurevision != UINT32_MAX && revision <= snitem->menurevision) {
- g_variant_unref(data);
+
+ layout = g_variant_get_child_value(data, 1);
+ menuitems = g_variant_get_child_value(layout, 2);
+
+ GMenu *menu = create_menumodel(menuitems, snitem);
+ GtkWidget *popovermenu = gtk_popover_menu_new_from_model(NULL);
+ gtk_popover_set_has_arrow(GTK_POPOVER(popovermenu), FALSE);
+ gtk_popover_menu_set_menu_model(GTK_POPOVER_MENU(popovermenu), G_MENU_MODEL(menu));
+ gtk_widget_set_parent(popovermenu, snitem->icon);
+
+ snitem->popovermenu = popovermenu;
+
+ g_object_unref(menu);
+ g_variant_unref(menuitems);
+ g_variant_unref(layout);
+ g_variant_unref(data);
+}
+
+
+static void
+on_layout_updated(GDBusProxy *proxy, GAsyncResult *res, StatusNotifierItem *snitem)
+{
+ GError *err = NULL;
+ GVariant *data = g_dbus_proxy_call_finish(proxy, res, &err);
+
+ // Errors which might occur when the tray is running slowly (eg under valgrind)
+ // and user is spam clicking already exited icons
+
+ // "No such object path '/MenuBar'
+ if (err && g_error_matches(err, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_OBJECT)) {
+ g_error_free(err);
+ return;
+
+ // "The name is not activatable"
+ } else if (err && g_error_matches(err, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) {
+ g_error_free(err);
+ return;
+
+ // "Remote peer disconnected"
+ } else if (err && g_error_matches(err, G_DBUS_ERROR, G_DBUS_ERROR_NO_REPLY)) {
+ g_error_free(err);
return;
- } else {
- snitem->menurevision = revision;
- }
- if (snitem->menu && snitem->popovermenu) {
- gtk_widget_unparent(snitem->popovermenu);
- g_menu_remove_all(snitem->menu);
+ } else if (err) {
+ g_warning("%s\n", err->message);
+ fprintf(stderr, "from on_layout_updated\n");
+ g_error_free(err);
+ return;
}
- layout = g_variant_get_child_value(data, 1);
+ GVariant *layout;
+ GVariant *menuitems;
+
+ layout = g_variant_get_child_value(data, 1);
menuitems = g_variant_get_child_value(layout, 2);
- GMenu *menu = create_menumodel(menuitems, snitem);
- snitem->menu = menu;
- snitem->popovermenu = gtk_popover_menu_new_from_model(G_MENU_MODEL(snitem->menu));
- gtk_popover_set_has_arrow(GTK_POPOVER(snitem->popovermenu), FALSE);
- gtk_popover_menu_set_menu_model(GTK_POPOVER_MENU(snitem->popovermenu),
- G_MENU_MODEL(snitem->menu));
- gtk_widget_set_parent(snitem->popovermenu, snitem->icon);
+ if (snitem && snitem->icon && GTK_IS_WIDGET(snitem->icon) &&
+ snitem->popovermenu && GTK_IS_WIDGET(snitem->popovermenu)) {
+ GMenu *newmenu = create_menumodel(menuitems, snitem);
+
+ gtk_popover_menu_set_menu_model(GTK_POPOVER_MENU(snitem->popovermenu), G_MENU_MODEL(newmenu));
+ }
g_variant_unref(menuitems);
g_variant_unref(layout);
@@ -254,6 +297,10 @@ on_menulayout_ready(GDBusProxy *proxy, GAsyncResult *res, StatusNotifierItem *sn
}
+// We just rebuild the entire menu every time...
+// ItemsPropertiesUpdated signal would carry data of
+// which menuitems got updated and which got removed
+// but the GMenu api doesn't allow easy manipulation as it is
static void
on_menuproxy_signal(GDBusProxy *proxy,
const char *sender,
@@ -262,36 +309,63 @@ on_menuproxy_signal(GDBusProxy *proxy,
StatusNotifierItem *snitem)
{
if (strcmp(signal, "LayoutUpdated") == 0) {
- g_debug("%s's menu got LayoutUpdated\n", snitem->busname);
+ uint32_t revision = UINT32_MAX;
+ int32_t parentid;
+ g_variant_get(params, "(ui)", &revision, &parentid);
+ if (snitem->menurevision != UINT32_MAX && revision <= snitem->menurevision) {
+ // g_debug("%s got %s, but menurevision didn't change. Ignoring\n", snitem->busname, signal);
+ return;
+ } else if (!snitem || !snitem->icon || !GTK_IS_WIDGET(snitem->icon) ||
+ !snitem->popovermenu || !GTK_IS_WIDGET(snitem->popovermenu)) {
+ // g_debug("%s got %s, but menu was already in destruction. Ignoring\n", snitem->busname, signal);
+ return;
+ } else {
+ snitem->menurevision = revision;
+ }
+
g_dbus_proxy_call(snitem->menuproxy,
"GetLayout",
g_variant_new("(iias)", 0, -1, NULL),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
- (GAsyncReadyCallback)on_menulayout_ready,
+ (GAsyncReadyCallback)on_layout_updated,
snitem);
- // TODO: dynamic menu updates
+
} else if (strcmp(signal, "ItemsPropertiesUpdated") == 0) {
- g_debug("%s's menu got LayoutUpdated\n", snitem->busname);
+ if (!snitem || !snitem->icon || !GTK_IS_WIDGET(snitem->icon) ||
+ !snitem->popovermenu || !GTK_IS_WIDGET(snitem->popovermenu)) {
+ // g_debug("Menu was already in destruction\n");
+ return;
+ }
+ g_dbus_proxy_call(snitem->menuproxy,
+ "GetLayout",
+ g_variant_new("(iias)", 0, -1, NULL),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ (GAsyncReadyCallback)on_layout_updated,
+ snitem);
}
}
void
-create_menu(GDBusProxy *proxy, GAsyncResult *res, StatusNotifierItem *snitem)
+create_menu(GObject *obj, GAsyncResult *res, StatusNotifierItem *snitem)
{
GError *err = NULL;
- snitem->menuproxy = g_dbus_proxy_new_for_bus_finish(res, &err);
+ GDBusProxy *proxy = g_dbus_proxy_new_for_bus_finish(res, &err);
+ snitem->menuproxy = proxy;
snitem->menurevision = UINT32_MAX;
if (err) {
- g_debug("%s\n", err->message);
+ g_warning("%s\n", err->message);
+ fprintf(stderr, "from create_menu\n");
g_error_free(err);
return;
}
- g_dbus_proxy_call(snitem->menuproxy,
+ g_dbus_proxy_call(proxy,
"GetLayout",
g_variant_new ("(iias)", 0, -1, NULL),
G_DBUS_CALL_FLAGS_NONE,
diff --git a/dwlb.c b/dwlb.c
@@ -1432,6 +1432,9 @@ copy_customtext(CustomText *from, CustomText *to)
static void
request_resize(Bar *bar, char *data)
{
+ if (!bar)
+ return;
+
uint32_t traywidth = (uint32_t)atoi(data);
bar->width = bar->width_orig - traywidth;
@@ -1586,7 +1589,12 @@ read_socket(void)
set_bottom(bar);
}
} else if (!strcmp(wordbeg, "resize")) {
- request_resize(bar, wordend);
+ if (all) {
+ wl_list_for_each(bar, &bar_list, link)
+ request_resize(bar, wordend);
+ } else {
+ request_resize(bar, wordend);
+ }
}
}
@@ -1678,6 +1686,41 @@ sig_handler(int sig)
run_display = false;
}
+static void
+start_systray(const char *parent_progname, const char *traymon)
+{
+ char tray_exe_path[PATH_MAX];
+ char traypath_maybe[PATH_MAX];
+ char traybg_arg[64];
+ char height_arg[64];
+ char traymon_arg[64];
+
+ pixman_color_t *traybg_clr = &inactive_bg_color;
+ snprintf(traybg_arg,
+ sizeof(traybg_arg),
+ "--bg-color=#%02x%02x%02x",
+ (traybg_clr->red / 0x100),
+ (traybg_clr->green / 0x100),
+ (traybg_clr->blue) / 0x100);
+
+ snprintf(traypath_maybe, sizeof(traypath_maybe), "%stray", parent_progname);
+ if (access(traypath_maybe, X_OK) == 0)
+ strcpy(tray_exe_path, traypath_maybe);
+ else
+ strcpy(tray_exe_path, "dwlbtray");
+
+ snprintf(height_arg, sizeof(height_arg), "--height=%u", height);
+ snprintf(traymon_arg, sizeof(traymon_arg), "--traymon=%s", traymon);
+ char *args[] = { tray_exe_path, height_arg, traybg_arg, traymon_arg, NULL };
+ if (!traymon)
+ args[3] = NULL;
+
+ int child_pid = fork();
+ if (child_pid == 0) {
+ execvp(args[0], args);
+ }
+}
+
int
main(int argc, char **argv)
{
@@ -1685,7 +1728,7 @@ main(int argc, char **argv)
struct sockaddr_un sock_address;
Bar *bar, *bar2;
Seat *seat, *seat2;
- char *traymon = NULL;
+ const char *traymon = NULL;
/* Establish socket directory */
if (!(xdgruntimedir = getenv("XDG_RUNTIME_DIR")))
@@ -1960,40 +2003,9 @@ main(int argc, char **argv)
signal(SIGHUP, sig_handler);
signal(SIGTERM, sig_handler);
signal(SIGCHLD, SIG_IGN);
-
- /* Start tray program */
- char tray_exe_path[PATH_MAX];
- char traypath_maybe[PATH_MAX];
- char traybg_arg[64];
- char height_arg[64];
- char traymon_arg[64];
-
- pixman_color_t *traybg_clr = &inactive_bg_color;
- snprintf(traybg_arg,
- sizeof(traybg_arg),
- "--bg-color=#%02x%02x%02x",
- (traybg_clr->red / 0x100),
- (traybg_clr->green / 0x100),
- (traybg_clr->blue) / 0x100);
- printf("%s\n", traybg_arg);
-
- snprintf(traypath_maybe, sizeof(traypath_maybe), "%stray", argv[0]);
- if (access(traypath_maybe, X_OK) == 0)
- strcpy(tray_exe_path, traypath_maybe);
- else
- strcpy(tray_exe_path, "dwlbtray");
-
- snprintf(height_arg, sizeof(height_arg), "--height=%u", height);
- snprintf(traymon_arg, sizeof(traymon_arg), "--traymon=%s", traymon);
- char *args[] = { tray_exe_path, height_arg, traybg_arg, traymon_arg, NULL };
- if (!traymon)
- args[3] = NULL;
-
- int child_pid = fork();
- if (child_pid == 0) {
- execvp(args[0], args);
- }
+ /* Start tray program */
+ start_systray(argv[0], traymon);
/* Run */
run_display = true;
diff --git a/dwlbtray.c b/dwlbtray.c
@@ -2,6 +2,7 @@
#include <unistd.h>
#include <glib.h>
+#include <glib-unix.h>
#include <gtk4-layer-shell.h>
#include <gtk/gtk.h>
@@ -22,6 +23,8 @@ activate(GtkApplication* app, StatusNotifierHost *snhost)
GTK_STYLE_PROVIDER(css),
GTK_STYLE_PROVIDER_PRIORITY_USER);
gtk_widget_add_css_class(GTK_WIDGET(window), "dwlbtray");
+ g_free(snhost->cssdata);
+ snhost->cssdata = NULL;
gtk_layer_init_for_window(window);
@@ -49,11 +52,21 @@ activate(GtkApplication* app, StatusNotifierHost *snhost)
gtk_widget_set_margin_start(box, snhost->margin);
gtk_widget_set_margin_end(box, snhost->margin);
gtk_window_set_child(window, box);
- snhost->box = box;
dwlb_request_resize(snhost);
gtk_window_present(window);
+ snhost->box = box;
+ snhost->window = window;
+}
+
+
+static gboolean
+terminate_app(StatusNotifierHost *snhost)
+{
+ terminate_statusnotifierhost(snhost);
+
+ return G_SOURCE_REMOVE;
}
@@ -91,6 +104,9 @@ main(int argc, char *argv[])
g_signal_connect(app, "activate", G_CALLBACK(activate), snhost);
+ g_unix_signal_add(SIGINT, (GSourceFunc)terminate_app, snhost);
+ g_unix_signal_add(SIGTERM, (GSourceFunc)terminate_app, snhost);
+
char *argv_inner[] = { argv[0], NULL };
int status = g_application_run(G_APPLICATION(app), 1, argv_inner);
diff --git a/dwlbtray.h b/dwlbtray.h
@@ -13,29 +13,24 @@ typedef struct {
typedef struct StatusNotifierHost {
GDBusConnection *conn;
- GDBusNodeInfo *nodeinfo;
- GDBusProxy *watcherproxy;
GSList *trayitems;
GtkWidget *box;
GtkWindow *window;
- int bus_obj_reg_id;
- int cursize;
+ char *cssdata;
+ char *traymon;
+ int curwidth;
int height;
int margin;
int noitems;
+ int obj_id;
int owner_id;
- uint nameowner_sig_sub_id;
- uint watcher_id;
- char *traymon;
- char *cssdata;
+ int sub_id;
} StatusNotifierHost;
+
typedef struct StatusNotifierItem {
- GDBusNodeInfo *menunodeinfo;
- GDBusNodeInfo *nodeinfo;
GDBusProxy *menuproxy;
GDBusProxy *proxy;
- GMenu *menu;
GSList *action_cb_data_slist;
GSimpleActionGroup *actiongroup;
GVariant *iconpixmap_v;
@@ -44,20 +39,17 @@ typedef struct StatusNotifierItem {
GtkWidget *popovermenu;
StatusNotifierHost *host;
char *busname;
- char *busobj;
char *iconname;
- char *menuobj;
+ gboolean isclosing;
uint32_t menurevision;
- unsigned char *icon_data;
} StatusNotifierItem;
-void create_trayitem(GDBusConnection *conn, GAsyncResult *res, StatusNotifierItem *snitem);
-void create_menu(GDBusProxy *proxy, GAsyncResult *res, StatusNotifierItem *snitem);
+void create_trayitem(GObject *obj, GAsyncResult *res, StatusNotifierItem *snitem);
+void create_menu(GObject *obj, GAsyncResult *res, StatusNotifierItem *snitem);
StatusNotifierHost* start_statusnotifierhost();
-// void terminate_statusnotifierhost(StatusNotifierHost *snhost);
-GDBusNodeInfo* get_interface_info(const char *xmlpath);
void dwlb_request_resize(StatusNotifierHost *snhost);
+void terminate_statusnotifierhost(StatusNotifierHost *snhost);
#define DBUSMENU_XML \
@@ -210,4 +202,4 @@ void dwlb_request_resize(StatusNotifierHost *snhost);
" </interface>\n" \
"</node>\n"
-#endif /* STATUSNOTIFIERHOST_H */
+#endif /* GTKTRAY_H */
diff --git a/statusnotifierhost.c b/statusnotifierhost.c
@@ -9,14 +9,15 @@
#include "dwlbtray.h"
-
+static void unregister_all(StatusNotifierHost *snhost);
+static void sub_finalize(StatusNotifierHost *snhost);
+static void busobj_finalize(StatusNotifierHost *snhost);
+static void unregister_statusnotifieritem(StatusNotifierItem *snitem);
static void handle_method_call(GDBusConnection* conn, const char* sender,
const char* object_path, const char* iface, const char* method,
GVariant* parameters, GDBusMethodInvocation* invocation,
StatusNotifierHost* snhost
);
-
-
static GVariant* handle_get_prop(GDBusConnection* conn, const char* sender,
const char* obj_path, const char* iface_name,
const char* prop, GError** error, StatusNotifierHost* snhost
@@ -30,13 +31,44 @@ static GDBusInterfaceVTable interface_vtable = {
};
+static void
+add_trayitem_name_to_builder(StatusNotifierItem *snitem, GVariantBuilder *builder)
+{
+ g_variant_builder_add_value(builder, g_variant_new_string(snitem->busname));
+}
+
+
+static int
+find_snitem(StatusNotifierItem *snitem, const char *busname_match)
+{
+ if (strcmp(snitem->busname, busname_match) == 0)
+ return 0;
+ else
+ return -1;
+}
+
+
+static void
+unregister_all_wrap(StatusNotifierItem *snitem, void *data)
+{
+ unregister_statusnotifieritem(snitem);
+}
+
+
+static void
+unregister_all(StatusNotifierHost *snhost)
+{
+ g_slist_foreach(snhost->trayitems, (GFunc)unregister_all_wrap, NULL);
+}
+
+
void
dwlb_request_resize(StatusNotifierHost *snhost)
{
if (snhost->noitems <= 1)
- snhost->cursize = 22;
+ snhost->curwidth = 22;
else
- snhost->cursize = 22 * snhost->noitems - 6; // dunno why substract 6 to make it align, just trial and error until it worked
+ snhost->curwidth = 22 * snhost->noitems - 6; // dunno why substract 6 to make it align, just trial and error until it worked
struct sockaddr_un sockaddr;
sockaddr.sun_family = AF_UNIX;
@@ -44,10 +76,10 @@ dwlb_request_resize(StatusNotifierHost *snhost)
snprintf(sockaddr.sun_path, sizeof(sockaddr.sun_path), "%s", socketpath);
char *sockbuf = NULL;
if (snhost->traymon) {
- sockbuf = g_strdup_printf("%s %s %i", snhost->traymon, "resize", snhost->cursize);
+ sockbuf = g_strdup_printf("%s %s %i", snhost->traymon, "resize", snhost->curwidth);
}
else {
- sockbuf = g_strdup_printf("%s %s %i", "selected", "resize", snhost->cursize);
+ sockbuf = g_strdup_printf("%s %s %i", "all", "resize", snhost->curwidth);
}
size_t len = strlen(sockbuf);
@@ -59,45 +91,47 @@ dwlb_request_resize(StatusNotifierHost *snhost)
}
if (send(sock_fd, sockbuf, len, 0) == -1)
- fprintf(stderr, "Could not send size update to %s\n", sockaddr.sun_path);
+ g_error("Could not send size update to %s\n", sockaddr.sun_path);
close(sock_fd);
- g_free(sockbuf);
g_free(socketpath);
+ g_free(sockbuf);
}
static void
-register_statusnotifieritem(const char *busname,
+register_statusnotifieritem(GDBusConnection *conn,
+ const char *busname,
const char *busobj,
StatusNotifierHost *snhost)
{
+ g_debug("Registering %s\n", busname);
StatusNotifierItem *snitem;
snitem = g_malloc0(sizeof(StatusNotifierItem));
-
snitem->host = snhost;
snitem->busname = g_strdup(busname);
- snitem->busobj = g_strdup(busobj);
- snitem->nodeinfo = g_dbus_node_info_new_for_xml(STATUSNOTIFIERITEM_XML, NULL);
+ snitem->isclosing = FALSE;
+ snitem->host->noitems = snitem->host->noitems + 1;
- snhost->noitems = snhost->noitems + 1;
snhost->trayitems = g_slist_prepend(snhost->trayitems, snitem);
+ dwlb_request_resize(snitem->host);
- // g_free(xml_path);
- dwlb_request_resize(snhost);
+ GDBusNodeInfo *nodeinfo = g_dbus_node_info_new_for_xml(STATUSNOTIFIERITEM_XML, NULL);
- g_dbus_proxy_new(snhost->conn,
+ g_dbus_proxy_new(conn,
G_DBUS_PROXY_FLAGS_NONE,
- snitem->nodeinfo->interfaces[0],
+ nodeinfo->interfaces[0],
snitem->busname,
- snitem->busobj,
+ busobj,
"org.kde.StatusNotifierItem",
- NULL,
+ NULL,
(GAsyncReadyCallback)create_trayitem,
snitem);
+ g_dbus_node_info_unref(nodeinfo);
+
GError *err = NULL;
- g_dbus_connection_emit_signal(snhost->conn,
+ g_dbus_connection_emit_signal(conn,
NULL,
"/StatusNotifierWatcher",
"org.kde.StatusNotifierWatcher",
@@ -105,34 +139,36 @@ register_statusnotifieritem(const char *busname,
g_variant_new("(s)", snitem->busname),
&err);
if (err) {
- g_debug("%s\n", err->message);
+ g_warning("%s\n", err->message);
+ fprintf(stderr, "from register_statusnotifieritem\n");
g_error_free(err);
}
}
-static int
-find_snitem(StatusNotifierItem *snitem, char *busname_match)
-{
- if (strcmp(snitem->busname, busname_match) == 0)
- return 0;
- else
- return -1;
-}
-
-
static void
-unregister_statusnotifieritem(StatusNotifierItem *snitem, StatusNotifierHost *snhost)
+unregister_statusnotifieritem(StatusNotifierItem *snitem)
{
- g_debug("item %s is closing\n", snitem->busname);
- if (snitem->popovermenu)
+ g_debug("Unregistering %s\n", snitem->busname);
+ if (snitem->popovermenu) {
+ gtk_popover_menu_set_menu_model(GTK_POPOVER_MENU(snitem->popovermenu), NULL);
gtk_widget_unparent(snitem->popovermenu);
- if (snitem->icon)
- gtk_box_remove(GTK_BOX(snhost->box), snitem->icon);
+ snitem->popovermenu = NULL;
+ }
+
+ if (snitem->icon) {
+ // TODO: Why do we still have children left???
+ GtkWidget *test;
+ while ((test = gtk_widget_get_first_child(snitem->icon))) {
+ gtk_widget_unparent(test);
+ }
+ gtk_box_remove(GTK_BOX(snitem->host->box), snitem->icon);
+ snitem->icon = NULL;
+ }
GError *err = NULL;
- g_dbus_connection_emit_signal(snhost->conn,
+ g_dbus_connection_emit_signal(snitem->host->conn,
NULL,
"/StatusNotifierWatcher",
"org.kde.StatusNotifierWatcher",
@@ -140,17 +176,15 @@ unregister_statusnotifieritem(StatusNotifierItem *snitem, StatusNotifierHost *sn
g_variant_new("(s)", snitem->busname),
&err);
if (err) {
- g_debug("%s\n", err->message);
+ g_warning("%s\n", err->message);
+ fprintf(stderr, "from unregister_statusnotifieritem\n");
g_error_free(err);
}
- if (snitem->menu) {
+ if (snitem->menuproxy)
g_object_unref(snitem->menuproxy);
+ if (snitem->action_cb_data_slist)
g_slist_free_full(snitem->action_cb_data_slist, g_free);
- g_object_unref(snitem->menu);
- }
- if (snitem->menunodeinfo)
- g_dbus_node_info_unref(snitem->menunodeinfo);
if (snitem->paintable) {
g_object_unref(snitem->paintable);
@@ -160,19 +194,15 @@ unregister_statusnotifieritem(StatusNotifierItem *snitem, StatusNotifierHost *sn
g_free(snitem->iconname);
}
- g_object_unref(snitem->proxy);
- g_dbus_node_info_unref(snitem->nodeinfo);
g_object_unref(snitem->actiongroup);
g_free(snitem->busname);
- g_free(snitem->busobj);
- g_free(snitem->menuobj);
- snhost->trayitems = g_slist_remove(snhost->trayitems, snitem);
+ snitem->host->trayitems = g_slist_remove(snitem->host->trayitems, snitem);
+ snitem->host->noitems = snitem->host->noitems - 1;
+ dwlb_request_resize(snitem->host);
g_free(snitem);
snitem = NULL;
- snhost->noitems = snhost->noitems - 1;
- dwlb_request_resize(snhost);
}
@@ -187,10 +217,10 @@ handle_method_call(GDBusConnection *conn,
StatusNotifierHost *snhost)
{
if (strcmp(method_name, "RegisterStatusNotifierItem") == 0) {
- char *param;
+ const char *param;
const char *busobj;
- g_variant_get(parameters, "(s)", ¶m);
+ g_variant_get(parameters, "(&s)", ¶m);
if (g_str_has_prefix(param, "/")) {
busobj = param;
@@ -198,9 +228,9 @@ handle_method_call(GDBusConnection *conn,
busobj = "/StatusNotifierItem";
}
- register_statusnotifieritem(sender, busobj, snhost);
+ register_statusnotifieritem(conn, sender, busobj, snhost);
g_dbus_method_invocation_return_value(invocation, NULL);
- g_free(param);
+
} else {
g_dbus_method_invocation_return_dbus_error(invocation,
"org.freedesktop.DBus.Error.UnknownMethod",
@@ -209,12 +239,6 @@ handle_method_call(GDBusConnection *conn,
}
-static void
-add_trayitem_name_to_builder(StatusNotifierItem *snitem, GVariantBuilder *builder)
-{
- g_variant_builder_add_value(builder, g_variant_new_string(snitem->busname));
-}
-
static GVariant*
handle_get_prop(GDBusConnection* conn,
const char* sender,
@@ -250,6 +274,14 @@ handle_get_prop(GDBusConnection* conn,
}
}
+// ugly
+static gboolean
+unregister_after_timeout(StatusNotifierItem *snitem)
+{
+ unregister_statusnotifieritem(snitem);
+ return G_SOURCE_REMOVE;
+}
+
// Finds trayitems which dropped from the bus and untracks them
static void
@@ -265,29 +297,21 @@ monitor_bus(GDBusConnection* conn,
if (!snhost->trayitems)
return;
- char *name;
- char *old_owner;
- char *new_owner;
+ const char *name;
+ const char *old_owner;
+ const char *new_owner;
- g_variant_get(params, "(sss)", &name, &old_owner, &new_owner);
+ g_variant_get(params, "(&s&s&s)", &name, &old_owner, &new_owner);
if (strcmp(new_owner, "") == 0) {
GSList *pmatch = g_slist_find_custom(snhost->trayitems, name, (GCompareFunc)find_snitem);
-
-
- if (!pmatch) {
- g_free(name);
- g_free(old_owner);
- g_free(new_owner);
- return;
+ if (pmatch) {
+ StatusNotifierItem *snitem = pmatch->data;
+ snitem->isclosing = TRUE;
+ // ugly
+ g_timeout_add_seconds(2, (GSourceFunc)unregister_after_timeout, snitem);
}
-
- StatusNotifierItem *snitem = pmatch->data;
- unregister_statusnotifieritem(snitem, snhost);
}
- g_free(name);
- g_free(old_owner);
- g_free(new_owner);
}
}
@@ -295,15 +319,18 @@ monitor_bus(GDBusConnection* conn,
static void
bus_acquired_handler(GDBusConnection *conn, const char *busname, StatusNotifierHost *snhost)
{
- snhost->conn = conn;
GError *err = NULL;
- snhost->bus_obj_reg_id = g_dbus_connection_register_object(conn,
- "/StatusNotifierWatcher",
- snhost->nodeinfo->interfaces[0],
- &interface_vtable,
- snhost, // udata
- NULL, // udata_free_func
- &err);
+ GDBusNodeInfo *nodeinfo = g_dbus_node_info_new_for_xml(STATUSNOTIFIERWATCHER_XML, NULL);
+
+ snhost->obj_id = g_dbus_connection_register_object(conn,
+ "/StatusNotifierWatcher",
+ nodeinfo->interfaces[0],
+ &interface_vtable,
+ snhost, // udata
+ (GDestroyNotify)busobj_finalize, // udata_free_func
+ &err);
+
+ g_dbus_node_info_unref(nodeinfo);
if (err) {
g_error("%s\n", err->message);
@@ -311,16 +338,16 @@ bus_acquired_handler(GDBusConnection *conn, const char *busname, StatusNotifierH
exit(-1);
}
- snhost->nameowner_sig_sub_id = g_dbus_connection_signal_subscribe(conn,
- NULL, // Listen to all senders);
- "org.freedesktop.DBus",
- "NameOwnerChanged",
- NULL, // Match all obj paths
- NULL, // Match all arg0s
- G_DBUS_SIGNAL_FLAGS_NONE,
- (GDBusSignalCallback)monitor_bus,
- snhost, // udata
- NULL); // udata free func
+ snhost->sub_id = g_dbus_connection_signal_subscribe(conn,
+ NULL, // Listen to all senders);
+ "org.freedesktop.DBus",
+ "NameOwnerChanged",
+ NULL, // Match all obj paths
+ NULL, // Match all arg0s
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ (GDBusSignalCallback)monitor_bus,
+ snhost,
+ (GDestroyNotify)sub_finalize);
}
@@ -328,6 +355,7 @@ static void
name_acquired_handler(GDBusConnection *conn, const char *busname, StatusNotifierHost *snhost)
{
GError *err = NULL;
+ snhost->conn = conn;
g_dbus_connection_emit_signal(conn,
NULL,
@@ -338,7 +366,8 @@ name_acquired_handler(GDBusConnection *conn, const char *busname, StatusNotifier
&err);
if (err) {
- g_debug("%s\n", err->message);
+ g_warning("%s\n", err->message);
+ fprintf(stderr, "from name_acquired_handler\n");
g_error_free(err);
}
}
@@ -352,11 +381,42 @@ name_lost_handler(GDBusConnection *conn, const char *busname, StatusNotifierHost
}
+static void
+snhost_finalize(StatusNotifierHost *snhost)
+{
+ gtk_window_close(snhost->window);
+ g_free(snhost);
+ snhost = NULL;
+}
+
+
+static void
+busobj_finalize(StatusNotifierHost *snhost)
+{
+ unregister_all(snhost);
+ g_slist_free(snhost->trayitems);
+ g_bus_unown_name(snhost->owner_id);
+}
+
+
+static void
+sub_finalize(StatusNotifierHost *snhost)
+{
+ g_dbus_connection_unregister_object(snhost->conn, snhost->obj_id);
+}
+
+
+void
+terminate_statusnotifierhost(StatusNotifierHost *snhost)
+{
+ g_dbus_connection_signal_unsubscribe(snhost->conn, snhost->sub_id);
+}
+
+
StatusNotifierHost*
start_statusnotifierhost()
{
StatusNotifierHost *snhost = g_malloc0(sizeof(StatusNotifierHost));
- snhost->nodeinfo = g_dbus_node_info_new_for_xml(STATUSNOTIFIERWATCHER_XML, NULL);
snhost->height = 22;
snhost->margin = 4;
@@ -369,7 +429,7 @@ start_statusnotifierhost()
(GBusNameAcquiredCallback)name_acquired_handler,
(GBusNameLostCallback)name_lost_handler,
snhost,
- NULL); // (GDestroyNotify)snhost_finalize);
+ (GDestroyNotify)snhost_finalize);
return snhost;
}
diff --git a/statusnotifieritem.c b/statusnotifieritem.c
@@ -22,45 +22,59 @@ argb_to_rgba(int32_t width, int32_t height, unsigned char *icon_data)
static void
-about_to_show_cb(GDBusProxy *proxy, GAsyncResult *res, StatusNotifierItem *snitem)
-{
- GError *err = NULL;
- GVariant *retval = g_dbus_proxy_call_finish(proxy, res, &err);
-
- if (err) {
- // Some apps require "AboutToShow" to be called before activating a menuitem
- // Others do not implement this method
- // In case of the latter we log a debug warning and continue
- g_debug("%s\n", err->message);
- g_error_free(err);
- } else {
- g_variant_unref(retval);
- }
-
- // Widget may be about to be destroyed
- if (GTK_IS_WIDGET(snitem->popovermenu))
- gtk_popover_popup(GTK_POPOVER(snitem->popovermenu));
-}
-
-
-static void
on_leftclick_cb(GtkGestureClick *click,
int n_press,
double x,
double y,
StatusNotifierItem *snitem)
{
- g_dbus_proxy_call(snitem->proxy,
- "Activate",
- g_variant_new("(ii)", 0, 0),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- NULL,
- NULL,
- snitem);
+ if (snitem && snitem->menuproxy && !snitem->isclosing)
+ g_dbus_proxy_call(snitem->proxy,
+ "Activate",
+ g_variant_new("(ii)", 0, 0),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ NULL,
+ NULL);
}
+static void
+rightclick_validate(GDBusProxy *proxy, GAsyncResult *res, StatusNotifierItem *snitem)
+{
+ GError *err = NULL;
+ GVariant *val = g_dbus_proxy_call_finish(proxy, res, &err);
+
+ // This error is generated when answer for the call arrives after
+ // icon was finalized.
+ if (err && g_error_matches(err, G_DBUS_ERROR, G_DBUS_ERROR_NO_REPLY)) {
+ g_error_free(err);
+ return;
+
+ // Discord generates the following error here:
+ // 'G_DBUS_ERROR' 'G_DBUS_ERROR_FAILED' 'error occurred in AboutToShow'
+ // We ignore it.
+ } else if (err && g_error_matches(err, G_DBUS_ERROR, G_DBUS_ERROR_FAILED) &&
+ g_strrstr(err->message, "error occured in AboutToShow") == 0) {
+ g_error_free(err);
+
+ if (snitem && snitem->icon && GTK_IS_WIDGET(snitem->icon) &&
+ snitem->popovermenu && GTK_IS_WIDGET(snitem->popovermenu))
+ gtk_popover_popup(GTK_POPOVER(snitem->popovermenu));
+
+ // Report rest of possible errors
+ } else if (err) {
+ g_warning("%sfrom on_rightclick_cb\n", err->message);
+ g_error_free(err);
+
+ } else {
+ g_variant_unref(val);
+ if (snitem && snitem->icon && GTK_IS_WIDGET(snitem->icon) &&
+ snitem->popovermenu && GTK_IS_WIDGET(snitem->popovermenu))
+ gtk_popover_popup(GTK_POPOVER(snitem->popovermenu));
+ }
+}
static void
@@ -70,14 +84,20 @@ on_rightclick_cb(GtkGestureClick *click,
double y,
StatusNotifierItem *snitem)
{
- g_dbus_proxy_call(snitem->menuproxy,
- "AboutToShow",
- g_variant_new("(i)", 0),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- NULL,
- (GAsyncReadyCallback)about_to_show_cb,
- snitem);
+ if (snitem && snitem->menuproxy && !snitem->isclosing) {
+ if (snitem && snitem->icon && GTK_IS_WIDGET(snitem->icon) &&
+ snitem->popovermenu && GTK_IS_WIDGET(snitem->popovermenu))
+ gtk_popover_popdown(GTK_POPOVER(snitem->popovermenu));
+
+ g_dbus_proxy_call(snitem->menuproxy,
+ "AboutToShow",
+ g_variant_new("(i)", 0),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ (GAsyncReadyCallback)rightclick_validate,
+ snitem);
+ }
}
@@ -200,8 +220,12 @@ new_iconname_handler(GDBusProxy *proxy, GAsyncResult *res, StatusNotifierItem *s
GVariant *data = g_dbus_proxy_call_finish(proxy, res, &err);
// (v)
- if (err) {
- g_debug("%s\n", err->message);
+ if (err && g_error_matches(err, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_OBJECT)) {
+ g_error_free(err);
+ return;
+ } else if (err) {
+ g_warning("%s\n", err->message);
+ fprintf(stderr, "from new_iconname_handler\n");
g_error_free(err);
return;
}
@@ -213,7 +237,7 @@ new_iconname_handler(GDBusProxy *proxy, GAsyncResult *res, StatusNotifierItem *s
g_variant_unref(iconname_v);
if (strcmp(iconname, snitem->iconname) == 0) {
- g_debug("%s\n", "pixmap didnt change, nothing to");
+ // g_debug("%s got NewIcon, but iconname didn't change. Ignoring\n", snitem->busname);
g_variant_unref(data);
return;
}
@@ -236,8 +260,12 @@ new_iconpixmap_handler(GDBusProxy *proxy, GAsyncResult *res, StatusNotifierItem
GVariant *data = g_dbus_proxy_call_finish(proxy, res, &err);
// (v)
- if (err) {
- g_debug("%s\n", err->message);
+ if (err && g_error_matches(err, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_OBJECT)) {
+ g_error_free(err);
+ return;
+ } else if (err) {
+ g_warning("%s\n", err->message);
+ fprintf(stderr, "from new_iconpixmap_handler\n");
g_error_free(err);
return;
}
@@ -247,7 +275,7 @@ new_iconpixmap_handler(GDBusProxy *proxy, GAsyncResult *res, StatusNotifierItem
g_variant_unref(data);
if (g_variant_equal(newpixmap_v, snitem->iconpixmap_v)) {
- g_debug ("%s\n", "iconname didnt change, nothing to");
+ // g_debug ("%s got NewIcon, but iconpixmap didn't change. Ignoring\n", snitem->busname);
g_variant_unref(newpixmap_v);
return;
}
@@ -267,7 +295,6 @@ trayitem_signal_handler(GDBusProxy *proxy,
GVariant *data_v,
StatusNotifierItem *snitem)
{
- // TODO: this can fire many times in a short amount of time
if (strcmp(signal, "NewIcon") == 0) {
if (snitem->iconpixmap_v)
g_dbus_proxy_call(proxy,
@@ -330,78 +357,106 @@ create_icon(GDBusProxy *proxy, StatusNotifierItem *snitem)
void
-create_trayitem(GDBusConnection *conn, GAsyncResult *res, StatusNotifierItem *snitem)
+create_trayitem(GObject *obj, GAsyncResult *res, StatusNotifierItem *snitem)
{
GError *err = NULL;
- snitem->proxy = g_dbus_proxy_new_finish(res, &err);
+ GDBusProxy *proxy = g_dbus_proxy_new_finish(res, &err);
if (err) {
- fprintf(stderr, "%s\n", err->message);
+ g_error("%s\n", err->message);
g_error_free(err);
- return;
}
- GtkIconTheme *theme = gtk_icon_theme_get_for_display(gdk_display_get_default ());
- GVariant *iconthemepath_v = g_dbus_proxy_get_cached_property(snitem->proxy, "IconThemePath");
+ // If this happens for whatever reason, we lose track of
+ // our window size (there will be a gap between systray and bar)
+ if (!snitem && proxy) {
+ g_object_unref(proxy);
+ return;
+ } else if (!snitem) {
+ return;
+ }
+ snitem->proxy = proxy;
+
+ GVariant *iconthemepath_v;
+ const char *iconthemepath;
+ GtkIconTheme *theme;
+ GtkGesture *leftclick;
+ GtkGesture *rightclick;
+ GVariant *menu_buspath_v;
+ const char *menu_buspath;
+ GSimpleActionGroup *actiongroup;
+ GtkWidget *icon;
+
+ /*
+ * const char *valid_menupaths[] = {
+ * "/MenuBar",
+ * "/com/canonical/dbusmenu",
+ * "/org/ayatana/NotificationItem",
+ * NULL
+ * };
+ */
+
+ g_signal_connect(proxy, "g-signal", G_CALLBACK(trayitem_signal_handler), snitem);
+
+ iconthemepath_v = g_dbus_proxy_get_cached_property(proxy, "IconThemePath");
+ theme = gtk_icon_theme_get_for_display(gdk_display_get_default());
if (iconthemepath_v) {
- const char *path = g_variant_get_string(iconthemepath_v, NULL);
- gtk_icon_theme_add_search_path(theme, path);
+ g_variant_get(iconthemepath_v, "&s", &iconthemepath);
+ gtk_icon_theme_add_search_path(theme, iconthemepath);
g_variant_unref(iconthemepath_v);
}
- GtkGesture *leftclick = gtk_gesture_click_new();
+ icon = create_icon(proxy, snitem);
+
+ leftclick = gtk_gesture_click_new();
gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(leftclick), 1);
g_signal_connect(leftclick, "pressed", G_CALLBACK(on_leftclick_cb), snitem);
- GtkGesture *rightclick = gtk_gesture_click_new();
+ rightclick = gtk_gesture_click_new();
gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(rightclick), 3);
g_signal_connect(rightclick, "pressed", G_CALLBACK(on_rightclick_cb), snitem);
- const char *valid_menuobjects[] = {
- "/MenuBar",
- "/com/canonical/dbusmenu",
- "/org/ayatana/NotificationItem",
- NULL
- };
-
- GVariant *menuobj_v = g_dbus_proxy_get_cached_property(snitem->proxy, "Menu");
- if (menuobj_v) {
- snitem->menuobj = g_strdup(g_variant_get_string(menuobj_v, NULL));
- g_variant_unref(menuobj_v);
- } else {
- snitem->menuobj = g_strdup("Invalid_menuobj");
+ actiongroup = g_simple_action_group_new();
+ if (snitem && icon && GTK_IS_WIDGET(icon)) {
+ gtk_widget_insert_action_group(icon,
+ "menuitem",
+ G_ACTION_GROUP(actiongroup));
}
- snitem->actiongroup = g_simple_action_group_new();
-
- snitem->menunodeinfo = g_dbus_node_info_new_for_xml(DBUSMENU_XML, NULL);
-
- g_signal_connect(snitem->proxy, "g-signal", G_CALLBACK(trayitem_signal_handler), snitem);
-
- for (int i = 0; valid_menuobjects[i] != NULL; i++) {
- if (g_strrstr(snitem->menuobj, valid_menuobjects[i]) != NULL) {
- g_dbus_proxy_new_for_bus(G_BUS_TYPE_SESSION,
- G_DBUS_PROXY_FLAGS_NONE,
- snitem->menunodeinfo->interfaces[0],
- snitem->busname,
- snitem->menuobj,
- "com.canonical.dbusmenu",
- NULL,
- (GAsyncReadyCallback)create_menu,
- snitem);
- }
+ snitem->actiongroup = actiongroup;
+
+ menu_buspath_v = g_dbus_proxy_get_cached_property(proxy, "Menu");
+ if (menu_buspath_v)
+ g_variant_get(menu_buspath_v, "&o", &menu_buspath);
+ else
+ menu_buspath = NULL;
+
+ // for (int i = 0; valid_menupaths[i]; i++) {
+ // if (menu_buspath && g_strrstr(menu_buspath, valid_menupaths[i]) == 0) {
+ if (menu_buspath) {
+ GDBusNodeInfo *nodeinfo = g_dbus_node_info_new_for_xml(DBUSMENU_XML, NULL);
+ g_dbus_proxy_new_for_bus(G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ nodeinfo->interfaces[0],
+ snitem->busname,
+ menu_buspath,
+ "com.canonical.dbusmenu",
+ NULL,
+ (GAsyncReadyCallback)create_menu,
+ snitem);
+ g_dbus_node_info_unref(nodeinfo);
+ }
+ // }
+ // }
+
+ if (icon) {
+ gtk_widget_add_controller(icon, GTK_EVENT_CONTROLLER(leftclick));
+ gtk_widget_add_controller(icon, GTK_EVENT_CONTROLLER(rightclick));
+ gtk_box_append(GTK_BOX(snitem->host->box), icon);
+ snitem->icon = icon;
}
- GtkWidget *image = create_icon(snitem->proxy, snitem);
- if (!image)
- return;
-
- snitem->icon = image;
- gtk_box_append(GTK_BOX(snitem->host->box), snitem->icon);
- gtk_widget_add_controller(snitem->icon, GTK_EVENT_CONTROLLER(leftclick));
- gtk_widget_add_controller(snitem->icon, GTK_EVENT_CONTROLLER(rightclick));
- gtk_widget_insert_action_group(snitem->icon,
- "menuitem",
- G_ACTION_GROUP (snitem->actiongroup));
+ if (menu_buspath_v)
+ g_variant_unref(menu_buspath_v);
}