/** * egg_desktop_file_parse_exec: * @desktop_file: a #EggDesktopFile * @documents: a list of document paths or URIs * @error: error pointer * * Parses @desktop_file's Exec key, inserting @documents into it, and * returns the result. * * If @documents contains non-file: URIs and @desktop_file does not * accept URIs, those URIs will be ignored. Likewise, if @documents * contains more elements than @desktop_file accepts, the extra * documents will be ignored. * * Return value: the parsed Exec string **/ char * egg_desktop_file_parse_exec (EggDesktopFile * desktop_file, GSList * documents, GError ** error) { GSList *translated, *docs; char *command; docs = translated = translate_document_list (desktop_file, documents); command = parse_exec (desktop_file, &docs, error); free_document_list (translated); return command; }
static gboolean egg_desktop_file_launchv (EggDesktopFile *desktop_file, GSList *documents, va_list args, GError **error) { EggDesktopFileLaunchOption option; GSList *translated_documents = NULL, *docs = NULL; char *command, **argv; int argc, i, screen_num; gboolean success, current_success; GdkDisplay *display; char *startup_id; GPtrArray *env = NULL; char **variables = NULL; GdkScreen *screen = NULL; int workspace = -1; const char *directory = NULL; guint32 launch_time = (guint32)-1; GSpawnFlags flags = G_SPAWN_SEARCH_PATH; GSpawnChildSetupFunc setup_func = NULL; gpointer setup_data = NULL; GPid *ret_pid = NULL; int *ret_stdin = NULL, *ret_stdout = NULL, *ret_stderr = NULL; char **ret_startup_id = NULL; if (documents && desktop_file->document_code == 0) { g_set_error (error, EGG_DESKTOP_FILE_ERROR, EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE, _("Application does not accept documents on command line")); return FALSE; } /* Read the options: technically it's incorrect for the caller to * NULL-terminate the list of options (rather than 0-terminating * it), but NULL-terminating lets us use G_GNUC_NULL_TERMINATED, * it's more consistent with other glib/gtk methods, and it will * work as long as sizeof (int) <= sizeof (NULL), and NULL is * represented as 0. (Which is true everywhere we care about.) */ while ((option = va_arg (args, EggDesktopFileLaunchOption))) { switch (option) { case EGG_DESKTOP_FILE_LAUNCH_CLEARENV: if (env) g_ptr_array_free (env, TRUE); env = g_ptr_array_new (); break; case EGG_DESKTOP_FILE_LAUNCH_PUTENV: variables = va_arg (args, char **); for (i = 0; variables[i]; i++) env = array_putenv (env, variables[i]); break; case EGG_DESKTOP_FILE_LAUNCH_SCREEN: screen = va_arg (args, GdkScreen *); break; case EGG_DESKTOP_FILE_LAUNCH_WORKSPACE: workspace = va_arg (args, int); break; case EGG_DESKTOP_FILE_LAUNCH_DIRECTORY: directory = va_arg (args, const char *); break; case EGG_DESKTOP_FILE_LAUNCH_TIME: launch_time = va_arg (args, guint32); break; case EGG_DESKTOP_FILE_LAUNCH_FLAGS: flags |= va_arg (args, GSpawnFlags); /* Make sure they didn't set any flags that don't make sense. */ flags &= ~G_SPAWN_FILE_AND_ARGV_ZERO; break; case EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC: setup_func = va_arg (args, GSpawnChildSetupFunc); setup_data = va_arg (args, gpointer); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_PID: ret_pid = va_arg (args, GPid *); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE: ret_stdin = va_arg (args, int *); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE: ret_stdout = va_arg (args, int *); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE: ret_stderr = va_arg (args, int *); break; case EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID: ret_startup_id = va_arg (args, char **); break; default: g_set_error (error, EGG_DESKTOP_FILE_ERROR, EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION, _("Unrecognized launch option: %d"), GPOINTER_TO_INT (option)); success = FALSE; goto out; } } if (screen) { char *display_name = gdk_screen_make_display_name (screen); char *display_env = g_strdup_printf ("DISPLAY=%s", display_name); env = array_putenv (env, display_env); g_free (display_name); g_free (display_env); display = gdk_screen_get_display (screen); } else { display = gdk_display_get_default (); screen = gdk_display_get_default_screen (display); } screen_num = gdk_screen_get_number (screen); translated_documents = translate_document_list (desktop_file, documents); docs = translated_documents; success = FALSE; do { command = parse_exec (desktop_file, &docs, error); if (!command) goto out; if (!g_shell_parse_argv (command, &argc, &argv, error)) { g_free (command); goto out; } g_free (command); #if GTK_CHECK_VERSION (2, 12, 0) startup_id = start_startup_notification (display, desktop_file, argv[0], screen_num, workspace, launch_time); if (startup_id) { char *startup_id_env = g_strdup_printf ("DESKTOP_STARTUP_ID=%s", startup_id); env = array_putenv (env, startup_id_env); g_free (startup_id_env); } #else startup_id = NULL; #endif /* GTK 2.12 */ if (env != NULL) g_ptr_array_add (env, NULL); current_success = g_spawn_async_with_pipes (directory, argv, env ? (char **)(env->pdata) : NULL, flags, setup_func, setup_data, ret_pid, ret_stdin, ret_stdout, ret_stderr, error); g_strfreev (argv); if (startup_id) { #if GTK_CHECK_VERSION (2, 12, 0) if (current_success) { set_startup_notification_timeout (display, startup_id); if (ret_startup_id) *ret_startup_id = startup_id; else g_free (startup_id); } else #endif /* GTK 2.12 */ g_free (startup_id); } else if (ret_startup_id) *ret_startup_id = NULL; if (current_success) { /* If we successfully launch any instances of the app, make * sure we return TRUE and don't set @error. */ success = TRUE; error = NULL; /* Also, only set the output params on the first one */ ret_pid = NULL; ret_stdin = ret_stdout = ret_stderr = NULL; ret_startup_id = NULL; } } while (docs && current_success); out: if (env) { g_ptr_array_foreach (env, (GFunc)g_free, NULL); g_ptr_array_free (env, TRUE); } free_document_list (translated_documents); return success; }