From 82757fd7bd099d849c11847be75f9f4cf43544a7 Mon Sep 17 00:00:00 2001
From: "Owen W. Taylor" <otaylor@fishsoup.net>
Date: Wed, 7 Oct 2015 22:56:11 -0400
Subject: [PATCH] Don't crash on accesses to stale window-backed apps
The JS code could still be holding on to a reference to a window-backed app
after all windows have vanished. (For example, the dash queues an idle to
refetch apps and display them.) Avoid dying with an error message if we
attempt to activate or otherwise manipulate such a window.
https://bugzilla.gnome.org/show_bug.cgi?id=674799
---
src/shell-app.c | 32 +++++++++++++++++++++++---------
1 file changed, 23 insertions(+), 9 deletions(-)
diff --git a/src/shell-app.c b/src/shell-app.c
index 051f84f..36aa47a 100644
--- a/src/shell-app.c
+++ b/src/shell-app.c
@@ -146,93 +146,99 @@ static void
shell_app_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ShellApp *app = SHELL_APP (gobject);
switch (prop_id)
{
case PROP_APP_INFO:
_shell_app_set_app_info (app, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
const char *
shell_app_get_id (ShellApp *app)
{
if (app->info)
return g_app_info_get_id (G_APP_INFO (app->info));
return app->window_id_string;
}
static MetaWindow *
window_backed_app_get_window (ShellApp *app)
{
g_assert (app->info == NULL);
- g_assert (app->running_state);
- g_assert (app->running_state->windows);
- return app->running_state->windows->data;
+ if (app->running_state)
+ {
+ g_assert (app->running_state->windows);
+ return app->running_state->windows->data;
+ }
+ else
+ return NULL;
}
static ClutterActor *
window_backed_app_get_icon (ShellApp *app,
int size)
{
- MetaWindow *window;
+ MetaWindow *window = NULL;
ClutterActor *actor;
gint scale;
ShellGlobal *global;
StThemeContext *context;
global = shell_global_get ();
context = st_theme_context_get_for_stage (shell_global_get_stage (global));
g_object_get (context, "scale-factor", &scale, NULL);
size *= scale;
/* During a state transition from running to not-running for
* window-backend apps, it's possible we get a request for the icon.
* Avoid asserting here and just return an empty image.
*/
- if (app->running_state == NULL)
+ if (app->running_state != NULL)
+ window = window_backed_app_get_window (app);
+
+ if (window == NULL)
{
actor = clutter_texture_new ();
g_object_set (actor, "opacity", 0, "width", (float) size, "height", (float) size, NULL);
return actor;
}
- window = window_backed_app_get_window (app);
actor = st_texture_cache_bind_pixbuf_property (st_texture_cache_get_default (),
G_OBJECT (window),
"icon");
g_object_set (actor, "width", (float) size, "height", (float) size, NULL);
return actor;
}
/**
* shell_app_create_icon_texture:
*
* Look up the icon for this application, and create a #ClutterTexture
* for it at the given size.
*
* Return value: (transfer none): A floating #ClutterActor
*/
ClutterActor *
shell_app_create_icon_texture (ShellApp *app,
int size)
{
GIcon *icon;
gint scale;
ClutterActor *ret;
ShellGlobal *global;
StThemeContext *context;
global = shell_global_get ();
context = st_theme_context_get_for_stage (shell_global_get_stage (global));
g_object_get (context, "scale-factor", &scale, NULL);
ret = NULL;
@@ -415,63 +421,65 @@ shell_app_get_faded_icon (ShellApp *app, int size, ClutterTextDirection directio
texture = st_texture_cache_load (st_texture_cache_get_default (),
cache_key,
ST_TEXTURE_CACHE_POLICY_FOREVER,
shell_app_create_faded_icon_cpu,
&data,
NULL);
g_free (cache_key);
if (texture != COGL_INVALID_HANDLE)
{
result = clutter_texture_new ();
clutter_texture_set_cogl_texture (CLUTTER_TEXTURE (result), texture);
}
else
{
result = clutter_texture_new ();
g_object_set (result, "opacity", 0, "width", (float) size * scale, "height", (float) size * scale, NULL);
}
return result;
}
const char *
shell_app_get_name (ShellApp *app)
{
if (app->info)
return g_app_info_get_name (G_APP_INFO (app->info));
else
{
MetaWindow *window = window_backed_app_get_window (app);
- const char *name;
+ const char *name = NULL;
+
+ if (window)
+ name = meta_window_get_title (window);
- name = meta_window_get_title (window);
if (!name)
name = C_("program", "Unknown");
return name;
}
}
const char *
shell_app_get_description (ShellApp *app)
{
if (app->info)
return g_app_info_get_description (G_APP_INFO (app->info));
else
return NULL;
}
/**
* shell_app_is_window_backed:
*
* A window backed application is one which represents just an open
* window, i.e. there's no .desktop file assocation, so we don't know
* how to launch it again.
*/
gboolean
shell_app_is_window_backed (ShellApp *app)
{
return app->info == NULL;
}
typedef struct {
MetaWorkspace *workspace;
@@ -1325,61 +1333,67 @@ app_child_setup (gpointer user_data)
do
res = dup2 (journalfd, 1);
while (G_UNLIKELY (res == -1 && errno == EINTR));
do
res = dup2 (journalfd, 2);
while (G_UNLIKELY (res == -1 && errno == EINTR));
(void) close (journalfd);
}
}
#endif
/**
* shell_app_launch:
* @timestamp: Event timestamp, or 0 for current event timestamp
* @workspace: Start on this workspace, or -1 for default
* @error: A #GError
*/
gboolean
shell_app_launch (ShellApp *app,
guint timestamp,
int workspace,
GError **error)
{
ShellGlobal *global;
GAppLaunchContext *context;
gboolean ret;
if (app->info == NULL)
{
MetaWindow *window = window_backed_app_get_window (app);
- meta_window_activate (window, timestamp);
+ /* We don't use an error return if there no longer any windows, because the
+ * user attempting to activate a stale window backed app isn't something
+ * we would expect the caller to meaningfully handle or display an error
+ * message to the user.
+ */
+ if (window)
+ meta_window_activate (window, timestamp);
return TRUE;
}
global = shell_global_get ();
context = shell_global_create_app_launch_context (global, timestamp, workspace);
ret = g_desktop_app_info_launch_uris_as_manager (app->info, NULL,
context,
G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
#ifdef HAVE_SYSTEMD
app_child_setup, (gpointer)shell_app_get_id (app),
#else
NULL, NULL,
#endif
_gather_pid_callback, app,
error);
g_object_unref (context);
return ret;
}
/**
* shell_app_launch_action:
* @app: the #ShellApp
* @action_name: the name of the action to launch (as obtained by
* g_desktop_app_info_list_actions())
* @timestamp: Event timestamp, or 0 for current event timestamp
* @workspace: Start on this workspace, or -1 for default
*/
void
--
2.7.4