Adjust to gtk/mutter changes for Application API
https://bugzilla.gnome.org/show_bug.cgi?id=668118
This commit is contained in:
parent
6195386a06
commit
c5932c0f07
263
src/shell-app.c
263
src/shell-app.c
@ -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:
|
||||||
*
|
*
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user