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