diff --git a/src/shell-app-system.c b/src/shell-app-system.c index 0cf0bbb8b..0d5490168 100644 --- a/src/shell-app-system.c +++ b/src/shell-app-system.c @@ -12,6 +12,7 @@ #include #include "shell-app-private.h" +#include "shell-window-tracker-private.h" #include "shell-global.h" #include "display.h" #include "st.h" @@ -1296,6 +1297,26 @@ shell_app_info_get_source_window (ShellAppInfo *info) return NULL; } +static void +_gather_pid_callback (GDesktopAppInfo *gapp, + GPid pid, + gpointer data) +{ + ShellApp *app; + ShellAppSystem *appsys; + ShellWindowTracker *tracker; + + g_return_if_fail (data != NULL); + + app = SHELL_APP (data); + tracker = shell_window_tracker_get_default (); + appsys = shell_app_system_get_default (); + + _shell_window_tracker_add_child_process_app (tracker, + pid, + app); +} + /** * shell_app_info_launch_full: * @timestamp: Event timestamp, or 0 for current event timestamp @@ -1312,6 +1333,7 @@ shell_app_info_launch_full (ShellAppInfo *info, char **startup_id, GError **error) { + ShellApp *shell_app; GDesktopAppInfo *gapp; GdkAppLaunchContext *context; gboolean ret; @@ -1363,7 +1385,15 @@ shell_app_info_launch_full (ShellAppInfo *info, gdk_app_launch_context_set_timestamp (context, timestamp); gdk_app_launch_context_set_desktop (context, workspace); - ret = g_app_info_launch (G_APP_INFO (gapp), uris, (GAppLaunchContext*) context, error); + shell_app = shell_app_system_get_app (shell_app_system_get_default (), + shell_app_info_get_id (info)); + + ret = g_desktop_app_info_launch_uris_as_manager (gapp, uris, + (GAppLaunchContext*) context, + G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, + NULL, NULL, + _gather_pid_callback, shell_app, + error); g_object_unref (G_OBJECT (gapp)); diff --git a/src/shell-window-tracker-private.h b/src/shell-window-tracker-private.h index b854615b1..0b60a8896 100644 --- a/src/shell-window-tracker-private.h +++ b/src/shell-window-tracker-private.h @@ -6,4 +6,8 @@ void _shell_window_tracker_notify_app_state_changed (ShellWindowTracker *tracker, ShellApp *self); +void _shell_window_tracker_add_child_process_app (ShellWindowTracker *tracker, + GPid pid, + ShellApp *app); + #endif diff --git a/src/shell-window-tracker.c b/src/shell-window-tracker.c index c2ff93281..61912bda6 100644 --- a/src/shell-window-tracker.c +++ b/src/shell-window-tracker.c @@ -71,6 +71,9 @@ struct _ShellWindowTracker /* */ GHashTable *running_apps; + + /* */ + GHashTable *launched_pid_to_app; }; G_DEFINE_TYPE (ShellWindowTracker, shell_window_tracker, G_TYPE_OBJECT); @@ -379,6 +382,20 @@ get_app_from_window_group (ShellWindowTracker *monitor, return result; } +static ShellApp * +get_app_from_window_pid (ShellWindowTracker *tracker, + MetaWindow *window) +{ + int pid; + + if (meta_window_is_remote (window)) + return NULL; + + pid = meta_window_get_pid (window); + + return g_hash_table_lookup (tracker->launched_pid_to_app, GINT_TO_POINTER (pid)); +} + /** * get_app_for_window: * @@ -410,6 +427,10 @@ get_app_for_window (ShellWindowTracker *monitor, } } + result = get_app_from_window_pid (monitor, window); + if (result != NULL) + return result; + /* Check if the app's WM_CLASS specifies an app */ result = get_app_from_window_wmclass (window); if (result != NULL) @@ -673,6 +694,8 @@ shell_window_tracker_init (ShellWindowTracker *self) self->running_apps = g_hash_table_new (g_str_hash, g_str_equal); + self->launched_pid_to_app = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_object_unref); + screen = shell_global_get_screen (shell_global_get ()); g_signal_connect (G_OBJECT (screen), "startup-sequence-changed", @@ -690,6 +713,8 @@ shell_window_tracker_finalize (GObject *object) g_hash_table_destroy (self->running_apps); g_hash_table_destroy (self->window_to_app); + g_hash_table_destroy (self->launched_pid_to_app); + for (i = 0; title_patterns[i].app_id; i++) g_regex_unref (title_patterns[i].regex); @@ -802,6 +827,40 @@ shell_window_tracker_get_running_apps (ShellWindowTracker *monitor, return ret; } +static void +on_child_exited (GPid pid, + gint status, + gpointer unused_data) +{ + ShellWindowTracker *tracker; + + tracker = shell_window_tracker_get_default (); + + g_hash_table_remove (tracker->launched_pid_to_app, GINT_TO_POINTER((gint)pid)); +} + +void +_shell_window_tracker_add_child_process_app (ShellWindowTracker *tracker, + GPid pid, + ShellApp *app) +{ + int pid_int = (int) pid; + + if (g_hash_table_lookup (tracker->launched_pid_to_app, + &pid_int)) + return; + + g_hash_table_insert (tracker->launched_pid_to_app, + GINT_TO_POINTER (pid_int), + g_object_ref (app)); + g_child_watch_add (pid, on_child_exited, NULL); + /* TODO: rescan unassociated windows + * Very unlikely in practice that the launched app gets ahead of us + * enough to map an X window before we get scheduled after the fork(), + * but adding this note for future reference. + */ +} + static void set_focus_app (ShellWindowTracker *tracker, ShellApp *new_focus_app)