diff --git a/src/shell-app.c b/src/shell-app.c index a96b06205..cc8609112 100644 --- a/src/shell-app.c +++ b/src/shell-app.c @@ -40,13 +40,8 @@ typedef struct { gboolean window_sort_stale : 1; /* See GApplication documentation */ - gint name_watcher_id; - gchar *dbus_name; - GDBusProxy *app_proxy; - GActionGroup *remote_actions; - GMenuModel *remote_menu; + GDBusMenuModel *remote_menu; GActionMuxer *muxer; - GCancellable *dbus_cancellable; } ShellAppRunningState; /** @@ -99,14 +94,8 @@ enum { static guint shell_app_signals[LAST_SIGNAL] = { 0 }; static void create_running_state (ShellApp *app); +static void setup_running_state (ShellApp *app, MetaWindow *window); static void unref_running_state (ShellAppRunningState *state); -static void on_dbus_name_appeared (GDBusConnection *bus, - const gchar *name, - const gchar *name_owner, - gpointer user_data); -static void on_dbus_name_disappeared (GDBusConnection *bus, - const gchar *name, - gpointer user_data); G_DEFINE_TYPE (ShellApp, shell_app, G_TYPE_OBJECT) @@ -126,9 +115,6 @@ shell_app_get_property (GObject *gobject, case PROP_ID: g_value_set_string (value, shell_app_get_id (app)); break; - case PROP_DBUS_ID: - g_value_set_string (value, shell_app_get_dbus_id (app)); - break; case PROP_ACTION_GROUP: if (app->running_state) g_value_set_object (value, app->running_state->muxer); @@ -186,15 +172,6 @@ window_backed_app_get_icon (ShellApp *app, return actor; } -const char * -shell_app_get_dbus_id (ShellApp *app) -{ - if (app->running_state) - return app->running_state->dbus_name; - else - return NULL; -} - /** * shell_app_create_icon_texture: * @@ -563,7 +540,7 @@ shell_app_update_window_actions (ShellApp *app, MetaWindow *window) { const char *object_path; - object_path = meta_window_get_dbus_object_path (window); + object_path = meta_window_get_gtk_window_object_path (window); if (object_path != NULL) { GActionGroup *actions; @@ -572,7 +549,7 @@ shell_app_update_window_actions (ShellApp *app, MetaWindow *window) if (actions == NULL) { actions = G_ACTION_GROUP (g_dbus_action_group_get (g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL), - meta_window_get_dbus_unique_name (window), + meta_window_get_gtk_unique_bus_name (window), object_path)); g_object_set_data_full (G_OBJECT (window), "actions", actions, g_object_unref); } @@ -975,34 +952,6 @@ shell_app_on_ws_switch (MetaScreen *screen, g_signal_emit (app, shell_app_signals[WINDOWS_CHANGED], 0); } -static void -on_dbus_application_id_changed (MetaWindow *window, - GParamSpec *pspec, - gpointer user_data) -{ - const char *appid; - ShellApp *app = SHELL_APP (user_data); - - /* Ignore changes in the appid after it's set, shouldn't happen */ - if (app->running_state->dbus_name != NULL) - return; - - appid = meta_window_get_dbus_application_id (window); - - if (!appid) - return; - - g_assert (app->running_state != NULL); - app->running_state->dbus_name = g_strdup (appid); - app->running_state->name_watcher_id = g_bus_watch_name (G_BUS_TYPE_SESSION, - appid, - G_BUS_NAME_WATCHER_FLAGS_NONE, - on_dbus_name_appeared, - on_dbus_name_disappeared, - g_object_ref (app), - g_object_unref); -} - void _shell_app_add_window (ShellApp *app, MetaWindow *window) @@ -1020,12 +969,11 @@ _shell_app_add_window (ShellApp *app, g_signal_connect (window, "unmanaged", G_CALLBACK(shell_app_on_unmanaged), app); g_signal_connect (window, "notify::user-time", G_CALLBACK(shell_app_on_user_time_changed), app); + setup_running_state (app, window); + if (app->state != SHELL_APP_STATE_STARTING) shell_app_state_transition (app, SHELL_APP_STATE_RUNNING); - g_signal_connect (window, "notify::dbus-application-id", G_CALLBACK(on_dbus_application_id_changed), app); - on_dbus_application_id_changed (window, NULL, app); - g_object_thaw_notify (G_OBJECT (app)); g_signal_emit (app, shell_app_signals[WINDOWS_CHANGED], 0); @@ -1042,7 +990,6 @@ _shell_app_remove_window (ShellApp *app, g_signal_handlers_disconnect_by_func (window, G_CALLBACK(shell_app_on_unmanaged), app); g_signal_handlers_disconnect_by_func (window, G_CALLBACK(shell_app_on_user_time_changed), app); - g_signal_handlers_disconnect_by_func (window, G_CALLBACK(on_dbus_application_id_changed), app); g_object_unref (window); app->running_state->windows = g_slist_remove (app->running_state->windows, window); @@ -1052,137 +999,6 @@ _shell_app_remove_window (ShellApp *app, g_signal_emit (app, shell_app_signals[WINDOWS_CHANGED], 0); } -static void -on_dbus_proxy_gotten (GObject *initable, - GAsyncResult *result, - gpointer user_data) -{ - ShellApp *self = SHELL_APP (user_data); - ShellAppRunningState *state = self->running_state; - GError *error = NULL; - GVariant *menu_property; - - state->app_proxy = g_dbus_proxy_new_finish (result, - &error); - - if (error) - { - if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) && - !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) - { - g_warning ("Unexpected error while creating application proxy: %s", error->message); - } - - g_clear_error (&error); - g_clear_object (&state->dbus_cancellable); - - if (state->name_watcher_id) - { - g_bus_unwatch_name (state->name_watcher_id); - state->name_watcher_id = 0; - } - - g_free (state->dbus_name); - state->dbus_name = NULL; - - g_object_unref (self); - return; - } - - /* on to the second step, the primary action group */ - - state->remote_actions = (GActionGroup*)g_dbus_action_group_get ( - g_dbus_proxy_get_connection (state->app_proxy), - g_dbus_proxy_get_name (state->app_proxy), - g_dbus_proxy_get_object_path (state->app_proxy)); - - if (!state->muxer) - state->muxer = g_action_muxer_new (); - - g_action_muxer_insert (state->muxer, "app", state->remote_actions); - g_strfreev (g_action_group_list_actions (state->remote_actions)); - - g_object_notify (G_OBJECT (self), "action-group"); - - menu_property = g_dbus_proxy_get_cached_property (state->app_proxy, "AppMenu"); - - if (menu_property && g_variant_n_children (menu_property) > 0) - { - const gchar *object_path; - - g_variant_get_child (menu_property, 0, "&o", &object_path); - - state->remote_menu = G_MENU_MODEL (g_dbus_menu_model_get (g_dbus_proxy_get_connection (state->app_proxy), - g_dbus_proxy_get_name (state->app_proxy), - object_path)); - - g_object_notify (G_OBJECT (self), "menu"); - } -} - -static void -on_dbus_name_appeared (GDBusConnection *bus, - const gchar *name, - const gchar *name_owner, - gpointer user_data) -{ - ShellApp *self = SHELL_APP (user_data); - ShellAppRunningState *state = self->running_state; - char *object_path; - - g_assert (state != NULL); - - object_path = g_strconcat ("/", name, NULL); - g_strdelimit (object_path, ".", '/'); - - if (!state->dbus_cancellable) - state->dbus_cancellable = g_cancellable_new (); - - /* first step: the application proxy */ - - g_dbus_proxy_new (bus, - G_DBUS_PROXY_FLAGS_NONE, - NULL, /* interface info */ - name_owner, - object_path, - "org.gtk.Application", - state->dbus_cancellable, - on_dbus_proxy_gotten, - g_object_ref (self)); - - g_object_notify (G_OBJECT (self), "dbus-id"); - - g_free (object_path); -} - -static void -on_dbus_name_disappeared (GDBusConnection *bus, - const gchar *name, - gpointer user_data) -{ - ShellApp *self = SHELL_APP (user_data); - ShellAppRunningState *state = self->running_state; - - g_assert (state != NULL); - - if (state->dbus_cancellable) - { - g_cancellable_cancel (state->dbus_cancellable); - g_clear_object (&state->dbus_cancellable); - } - - g_clear_object (&state->app_proxy); - g_clear_object (&state->remote_actions); - g_clear_object (&state->remote_menu); - g_clear_object (&state->muxer); - - g_free (state->dbus_name); - state->dbus_name = NULL; - - g_bus_unwatch_name (state->name_watcher_id); - state->name_watcher_id = 0; -} - /** * shell_app_get_pids: * @app: a #ShellApp @@ -1395,6 +1211,47 @@ create_running_state (ShellApp *app) app->running_state->refcount = 1; app->running_state->workspace_switch_id = g_signal_connect (screen, "workspace-switched", G_CALLBACK(shell_app_on_ws_switch), app); + + app->running_state->muxer = g_action_muxer_new (); +} + +static void +setup_running_state (ShellApp *app, + MetaWindow *window) +{ + /* We assume that 'gtk-unique-bus-name', gtk-application-object-path' + * and 'gtk-app-menu-object-path' are the same for all windows which + * have it set. + * + * It could be possible, however, that the first window we see + * belonging to the app didn't have them set. For this reason, we + * take the values from the first window that has them set and ignore + * all the rest (until the app is stopped and restarted). + */ + + if (app->running_state->remote_menu == NULL) + { + const gchar *application_object_path; + const gchar *app_menu_object_path; + const gchar *unique_bus_name; + GDBusConnection *session; + GDBusActionGroup *actions; + + application_object_path = meta_window_get_gtk_application_object_path (window); + app_menu_object_path = meta_window_get_gtk_app_menu_object_path (window); + unique_bus_name = meta_window_get_gtk_unique_bus_name (window); + + if (application_object_path == NULL || app_menu_object_path == NULL || unique_bus_name == NULL) + return; + + session = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); + g_assert (session != NULL); + app->running_state->remote_menu = g_dbus_menu_model_get (session, unique_bus_name, app_menu_object_path); + actions = g_dbus_action_group_get (session, unique_bus_name, application_object_path); + g_action_muxer_insert (app->running_state->muxer, "app", G_ACTION_GROUP (actions)); + g_object_unref (actions); + g_object_unref (session); + } } static void @@ -1411,20 +1268,8 @@ unref_running_state (ShellAppRunningState *state) screen = shell_global_get_screen (shell_global_get ()); g_signal_handler_disconnect (screen, state->workspace_switch_id); - if (state->dbus_cancellable) - { - g_cancellable_cancel (state->dbus_cancellable); - g_object_unref (state->dbus_cancellable); - } - - g_clear_object (&state->app_proxy); - g_clear_object (&state->remote_actions); g_clear_object (&state->remote_menu); g_clear_object (&state->muxer); - g_free (state->dbus_name); - - if (state->name_watcher_id) - g_bus_unwatch_name (state->name_watcher_id); g_slice_free (ShellAppRunningState, state); } @@ -1669,20 +1514,6 @@ shell_app_class_init(ShellAppClass *klass) NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - /** - * ShellApp:dbus-id: - * - * The DBus well-known name of the application, if one can be associated - * to this ShellApp (it means that the application is using GApplication) - */ - g_object_class_install_property (gobject_class, - PROP_DBUS_ID, - g_param_spec_string ("dbus-id", - "Application DBus Id", - "The DBus well-known name of the application", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - /** * ShellApp:action-group: * diff --git a/src/shell-app.h b/src/shell-app.h index 4fa6686c8..7e14c69c7 100644 --- a/src/shell-app.h +++ b/src/shell-app.h @@ -41,8 +41,6 @@ const char *shell_app_get_id (ShellApp *app); GMenuTreeEntry *shell_app_get_tree_entry (ShellApp *app); GDesktopAppInfo *shell_app_get_app_info (ShellApp *app); -const char *shell_app_get_dbus_id (ShellApp *app); - ClutterActor *shell_app_create_icon_texture (ShellApp *app, int size); ClutterActor *shell_app_get_faded_icon (ShellApp *app, int size); const char *shell_app_get_name (ShellApp *app);