diff options
author | Robert Tari <robert@tari.in> | 2024-09-26 10:41:33 +0200 |
---|---|---|
committer | Mike Gabriel <mike.gabriel@das-netzwerkteam.de> | 2025-07-11 08:43:34 +0200 |
commit | 7949738e86f832cea414410c1997d3195e095549 (patch) | |
tree | 57197e45b9d2796d114891738df05530abdb324e /src/indicator-application.c | |
parent | 26523e2d825d089b099b36f49e7a84ccf03f8a06 (diff) | |
download | ayatana-indicator-application-7949738e86f832cea414410c1997d3195e095549.tar.gz ayatana-indicator-application-7949738e86f832cea414410c1997d3195e095549.tar.bz2 ayatana-indicator-application-7949738e86f832cea414410c1997d3195e095549.zip |
Allow the service to handle both legacy menus and the new GMenu
Diffstat (limited to 'src/indicator-application.c')
-rw-r--r-- | src/indicator-application.c | 66 |
1 files changed, 53 insertions, 13 deletions
diff --git a/src/indicator-application.c b/src/indicator-application.c index ac674c3..1fb13b7 100644 --- a/src/indicator-application.c +++ b/src/indicator-application.c @@ -4,9 +4,11 @@ given by the service and turns it into real-world pixels that users can actually use. Well, GTK does that, but this asks nicely. Copyright 2009 Canonical Ltd. +Copyright 2024 Robert Tari Authors: Ted Gould <ted@canonical.com> + Robert Tari <robert@tari.in> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3, as published @@ -81,6 +83,7 @@ typedef struct { guint disconnect_kill; GCancellable * get_apps_cancel; guint watch; + GDBusConnection *pConnection; } IndicatorApplicationPrivate; typedef struct _ApplicationEntry ApplicationEntry; @@ -92,6 +95,9 @@ struct _ApplicationEntry { gchar * dbusaddress; gchar * guide; gchar * longname; + gint nPosition; + GMenuModel *pModel; + GActionGroup *pActions; }; static void indicator_application_class_init (IndicatorApplicationClass *klass); @@ -160,7 +166,7 @@ indicator_application_init (IndicatorApplication *self) NULL); priv->applications = NULL; - + priv->pConnection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); priv->theme_dirs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); priv->get_apps_cancel = NULL; @@ -215,6 +221,8 @@ indicator_application_dispose (GObject *object) priv->watch = 0; } + g_clear_object (&priv->pConnection); + G_OBJECT_CLASS (indicator_application_parent_class)->dispose (object); return; } @@ -484,6 +492,30 @@ guess_label_size (ApplicationEntry * app) return; } +static void applicationAddedFinish (ApplicationEntry *pEntry) +{ + /* Keep copies of these for ourself, just in case. */ + g_object_ref (pEntry->entry.image); + g_object_ref (pEntry->entry.menu); + + gtk_widget_show (GTK_WIDGET (pEntry->entry.image)); + IndicatorApplicationPrivate * pPrivate = indicator_application_get_instance_private (INDICATOR_APPLICATION (pEntry->entry.parent_object)); + pPrivate->applications = g_list_insert (pPrivate->applications, pEntry, pEntry->nPosition); + g_signal_emit (G_OBJECT (pEntry->entry.parent_object), INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED_ID, 0, &(pEntry->entry), TRUE); +} + +static void onMenuModelChanged (GMenuModel *pModel, gint nPosition, gint nRemoved, gint nAdded, gpointer pData) +{ + ApplicationEntry *pEntry = (ApplicationEntry*) pData; + g_signal_handlers_disconnect_by_data (pEntry->pModel, pEntry); + pEntry->entry.menu = GTK_MENU (gtk_menu_new_from_model (G_MENU_MODEL (pModel))); + gtk_menu_shell_bind_model (GTK_MENU_SHELL (pEntry->entry.menu), pModel, NULL, TRUE); + IndicatorApplicationPrivate *pPrivate = indicator_application_get_instance_private (INDICATOR_APPLICATION (pEntry->entry.parent_object)); + pEntry->pActions = G_ACTION_GROUP (g_dbus_action_group_get (pPrivate->pConnection, pEntry->dbusaddress, pEntry->dbusobject)); + gtk_widget_insert_action_group (GTK_WIDGET (pEntry->entry.menu), "indicator", pEntry->pActions); + applicationAddedFinish (pEntry); +} + /* Here we respond to new applications by building up the ApplicationEntry and signaling the indicator host that we've got a new indicator. */ @@ -492,11 +524,10 @@ application_added (IndicatorApplication * application, const gchar * iconname, g { g_return_if_fail(IS_INDICATOR_APPLICATION(application)); g_debug("Building new application entry: %s with icon: %s at position %i", dbusaddress, iconname, position); - IndicatorApplicationPrivate * priv = indicator_application_get_instance_private(application); - ApplicationEntry * app = g_new0(ApplicationEntry, 1); app->entry.parent_object = INDICATOR_OBJECT(application); + app->nPosition = position; app->old_service = FALSE; app->icon_theme_path = NULL; if (icon_theme_path != NULL && icon_theme_path[0] != '\0') { @@ -550,18 +581,24 @@ application_added (IndicatorApplication * application, const gchar * iconname, g app->entry.name_hint = g_strdup(hint); } - app->entry.menu = GTK_MENU(dbusmenu_gtkmenu_new((gchar *)dbusaddress, (gchar *)dbusobject)); - - /* Keep copies of these for ourself, just in case. */ - g_object_ref(app->entry.image); - g_object_ref(app->entry.menu); - - gtk_widget_show(GTK_WIDGET(app->entry.image)); + gboolean bGLibMenu = g_str_has_prefix (dbusobject, "/org/ayatana/appindicator/"); - priv->applications = g_list_insert(priv->applications, app, position); + if (bGLibMenu) + { + IndicatorApplicationPrivate * pPrivate = indicator_application_get_instance_private (application); + app->pModel = G_MENU_MODEL (g_dbus_menu_model_get (pPrivate->pConnection, dbusaddress, dbusobject)); + g_signal_connect (app->pModel, "items-changed", G_CALLBACK (onMenuModelChanged), app); - g_signal_emit(G_OBJECT(application), INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED_ID, 0, &(app->entry), TRUE); - return; + if (g_menu_model_get_n_items (app->pModel)) + { + onMenuModelChanged (app->pModel, 0, 0, 1, app); + } + } + else + { + app->entry.menu = GTK_MENU (dbusmenu_gtkmenu_new ((gchar*) dbusaddress, (gchar*) dbusobject)); + applicationAddedFinish (app); + } } /* This removes the application from the list and free's all @@ -612,6 +649,9 @@ application_removed (IndicatorApplication * application, gint position) if (app->entry.name_hint != NULL) { g_free((gchar *)app->entry.name_hint); } + + g_clear_object (&app->pModel); + g_clear_object (&app->pActions); g_free(app); return; |