Adjust to gtk/mutter changes for Application API

https://bugzilla.gnome.org/show_bug.cgi?id=668118
This commit is contained in:
Ryan Lortie 2012-01-17 15:13:47 -05:00
parent 6195386a06
commit c5932c0f07
2 changed files with 47 additions and 218 deletions

View File

@ -40,13 +40,8 @@ typedef struct {
gboolean window_sort_stale : 1; gboolean window_sort_stale : 1;
/* See GApplication documentation */ /* See GApplication documentation */
gint name_watcher_id; GDBusMenuModel *remote_menu;
gchar *dbus_name;
GDBusProxy *app_proxy;
GActionGroup *remote_actions;
GMenuModel *remote_menu;
GActionMuxer *muxer; GActionMuxer *muxer;
GCancellable *dbus_cancellable;
} ShellAppRunningState; } ShellAppRunningState;
/** /**
@ -99,14 +94,8 @@ enum {
static guint shell_app_signals[LAST_SIGNAL] = { 0 }; static guint shell_app_signals[LAST_SIGNAL] = { 0 };
static void create_running_state (ShellApp *app); 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 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) G_DEFINE_TYPE (ShellApp, shell_app, G_TYPE_OBJECT)
@ -126,9 +115,6 @@ shell_app_get_property (GObject *gobject,
case PROP_ID: case PROP_ID:
g_value_set_string (value, shell_app_get_id (app)); g_value_set_string (value, shell_app_get_id (app));
break; break;
case PROP_DBUS_ID:
g_value_set_string (value, shell_app_get_dbus_id (app));
break;
case PROP_ACTION_GROUP: case PROP_ACTION_GROUP:
if (app->running_state) if (app->running_state)
g_value_set_object (value, app->running_state->muxer); g_value_set_object (value, app->running_state->muxer);
@ -186,15 +172,6 @@ window_backed_app_get_icon (ShellApp *app,
return actor; 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: * shell_app_create_icon_texture:
* *
@ -563,7 +540,7 @@ shell_app_update_window_actions (ShellApp *app, MetaWindow *window)
{ {
const char *object_path; 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) if (object_path != NULL)
{ {
GActionGroup *actions; GActionGroup *actions;
@ -572,7 +549,7 @@ shell_app_update_window_actions (ShellApp *app, MetaWindow *window)
if (actions == NULL) if (actions == NULL)
{ {
actions = G_ACTION_GROUP (g_dbus_action_group_get (g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, 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)); object_path));
g_object_set_data_full (G_OBJECT (window), "actions", actions, g_object_unref); 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); 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 void
_shell_app_add_window (ShellApp *app, _shell_app_add_window (ShellApp *app,
MetaWindow *window) 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, "unmanaged", G_CALLBACK(shell_app_on_unmanaged), app);
g_signal_connect (window, "notify::user-time", G_CALLBACK(shell_app_on_user_time_changed), 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) if (app->state != SHELL_APP_STATE_STARTING)
shell_app_state_transition (app, SHELL_APP_STATE_RUNNING); 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_object_thaw_notify (G_OBJECT (app));
g_signal_emit (app, shell_app_signals[WINDOWS_CHANGED], 0); 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_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(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); g_object_unref (window);
app->running_state->windows = g_slist_remove (app->running_state->windows, 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); 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: * shell_app_get_pids:
* @app: a #ShellApp * @app: a #ShellApp
@ -1395,6 +1211,47 @@ create_running_state (ShellApp *app)
app->running_state->refcount = 1; app->running_state->refcount = 1;
app->running_state->workspace_switch_id = app->running_state->workspace_switch_id =
g_signal_connect (screen, "workspace-switched", G_CALLBACK(shell_app_on_ws_switch), app); 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 static void
@ -1411,20 +1268,8 @@ unref_running_state (ShellAppRunningState *state)
screen = shell_global_get_screen (shell_global_get ()); screen = shell_global_get_screen (shell_global_get ());
g_signal_handler_disconnect (screen, state->workspace_switch_id); 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->remote_menu);
g_clear_object (&state->muxer); 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); g_slice_free (ShellAppRunningState, state);
} }
@ -1669,20 +1514,6 @@ shell_app_class_init(ShellAppClass *klass)
NULL, NULL,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); 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: * ShellApp:action-group:
* *

View File

@ -41,8 +41,6 @@ const char *shell_app_get_id (ShellApp *app);
GMenuTreeEntry *shell_app_get_tree_entry (ShellApp *app); GMenuTreeEntry *shell_app_get_tree_entry (ShellApp *app);
GDesktopAppInfo *shell_app_get_app_info (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_create_icon_texture (ShellApp *app, int size);
ClutterActor *shell_app_get_faded_icon (ShellApp *app, int size); ClutterActor *shell_app_get_faded_icon (ShellApp *app, int size);
const char *shell_app_get_name (ShellApp *app); const char *shell_app_get_name (ShellApp *app);