/*- * Copyright (c) 2005-2006 Benedikt Meurer . * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H #include #endif #ifdef HAVE_GIO_UNIX #include #endif #include #include /** * SECTION: exo-execute * @title: Executing Applications * @short_description: Execute preferred applications * @include: exo/exo.h * @see_also: gtk_show_uri() * * This module provides functions to execute certain kinds of applications, * for which users can select their preferred ones. For example, whenever * you need to run a command in a terminal emulator from within your * application you should use exo_execute_terminal_shell() or * exo_execute_terminal_shell_on_screen() to make sure you run the user's * preferred terminal emulator. * On the other hand if you need to display an URL (i.e. you want to point * the user to the website of your application), you should use gtk_show_uri() * instead, as it will try to automatically determine the appropriate * viewer for a given URI. **/ /** * exo_execute_preferred_application: * @category : the category of the preferred application to launch. * @parameter : additional parameter to pass to the preferred application * (i.e. an URL to pass to the preferred browser) or %NULL * to pass no parameter. * @working_directory : path to the directory in which to execute the * preferred application for @category. * @envp : child's environment, or %NULL to inherit parent's. * @error : return location for errors or %NULL. * * Convenience wrapper to exo_execute_preferred_application_on_screen(), which * runs the preferred application for @category on the default #GdkScreen. * * Note that even if this method returns %TRUE there's no warranty that * the preferred application for @category was run successfully, because * of the way the helper framework is implemented. But you can be sure * that if the execution fails at a later stage, the library will popup * an error dialog to inform the user that the execution failed. * * Returns: %TRUE on success, else %FALSE. * * Since: 0.3.1.3 **/ gboolean exo_execute_preferred_application (const gchar *category, const gchar *parameter, const gchar *working_directory, gchar **envp, GError **error) { g_return_val_if_fail (category != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); return exo_execute_preferred_application_on_screen (category, parameter, working_directory, envp, gdk_screen_get_default (), error); } /* Set the DISPLAY variable, to be use by g_spawn_async. */ static void set_environment (gchar *display) { g_setenv ("DISPLAY", display, TRUE); } static gchar * find_fallback_application_from_rc_file (const gchar *category) { gchar *cfg = NULL; gchar *data = NULL; gchar *contents = NULL; gchar *app = NULL; gchar *path = NULL; GKeyFile *keyfile; cfg = g_strconcat(g_get_user_config_dir(), "/xfce4/helpers.rc", NULL); if (g_file_get_contents (cfg, &contents, NULL, NULL)) { data = g_strconcat("[Default]\n", contents, NULL); keyfile = g_key_file_new (); if (g_key_file_load_from_data (keyfile, data, -1, G_KEY_FILE_NONE, NULL)) { app = g_key_file_get_string (keyfile, "Default", category, NULL); if (app != NULL) { path = g_find_program_in_path(app); g_free (app); } } g_key_file_free (keyfile); g_free (data); g_free (contents); } g_free (cfg); return path; } #ifdef HAVE_GIO_UNIX static gchar * find_fallback_application_from_xdg_mime (const gchar *category) { const gchar *query = NULL; gchar *output = NULL; gchar *cmd = NULL; gchar *path = NULL; GDesktopAppInfo *info = NULL; if (g_strcmp0(category, "FileManager") == 0) { query = "xdg-mime query default inode/directory"; } else if (g_strcmp0(category, "MailReader") == 0) { query = "xdg-mime query default x-scheme-handler/mailto"; } else if (g_strcmp0(category, "WebBrowser") == 0) { query = "xdg-mime query default x-scheme-handler/http"; } else if (g_strcmp0(category, "TerminalEmulator") == 0) { info = g_desktop_app_info_new("xfce4-terminal.desktop"); } else { return NULL; } if (info == NULL && query != NULL) { if (g_spawn_command_line_sync(query, &output, NULL, NULL, NULL)) { if (output != NULL) { cmd = g_utf8_substring(output, 0, g_utf8_strlen(output, -1) - 1); g_free(output); info = g_desktop_app_info_new(cmd); } } } if (info != NULL) { gchar *executable = g_strdup(g_app_info_get_executable(G_APP_INFO(info))); if (g_strcmp0(executable, "exo-open") != 0) { path = g_find_program_in_path(executable); } g_free(executable); } if (cmd != NULL) { g_free(cmd); } return path; } #endif static gchar * find_fallback_application (const gchar *category) { gchar *path = NULL; path = find_fallback_application_from_rc_file (category); if (path != NULL) { return path; } #ifdef HAVE_GIO_UNIX path = find_fallback_application_from_xdg_mime (category); #endif return path; } /** * exo_execute_preferred_application_on_screen: * @category : the category of the preferred application to launch. * @parameter : additional parameter to pass to the preferred application * (i.e. an URL to pass to the preferred browser) or %NULL * to pass no parameter. * @working_directory : path to the directory in which to execute the * preferred application for @category. * @envp : child's environment, or %NULL to inherit parent's. * @screen : the #GdkScreen on which to run the preferred * application for @category. * @error : return location for errors or %NULL. * * Launches the preferred application for the given @category with the * @parameter on @screen in the specified @working_directory. * * libexo currently supports the following categories: %"WebBrowser", * %"MailReader" and %"TerminalEmulator". If you specify an invalid * @category here, the execution will fail at a later stage and the * user will be presented with an error dialog. * * Note that even if this method returns %TRUE there's no warranty that * the preferred application for @category was run successfully, because * of the way the helper framework is implemented. But you can be sure * that if the execution fails at a later stage, the library will popup * an error dialog to inform the user that the execution failed. * * Returns: %TRUE on success, else %FALSE. * * Since: 0.3.1.3 **/ gboolean exo_execute_preferred_application_on_screen (const gchar *category, const gchar *parameter, const gchar *working_directory, gchar **envp, GdkScreen *screen, GError **error) { GdkDisplay *display; gchar *argv[5]; gchar *display_name; gchar *path = NULL; gint argc = 0; gboolean success; g_return_val_if_fail (category != NULL, FALSE); g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); /* generate the argument vector */ path = g_find_program_in_path ("xfce4-mime-helper"); if (G_LIKELY(path != NULL)) { argv[argc++] = path; argv[argc++] = "--launch"; argv[argc++] = (gchar *)category; } else { // Fallback mode path = find_fallback_application (category); if (path == NULL) { g_set_error (error, G_SPAWN_ERROR, 0, "Could not find fallback %s application", category); return FALSE; } argv[argc++] = path; } /* append parameter if given */ if (G_LIKELY (parameter != NULL)) argv[argc++] = (gchar *) parameter; /* null terminate the argument vector */ argv[argc] = NULL; /* set the display environment variable */ display = gdk_screen_get_display (screen); display_name = g_strdup (gdk_display_get_name (display)); /* launch the command */ success = g_spawn_async (working_directory, argv, envp, 0, (GSpawnChildSetupFunc) set_environment, display_name, NULL, error); if (path) g_free (path); g_free (display_name); return success; } /** * exo_execute_terminal_shell: * @command_line : shell command line to execute. * @working_directory : path to the directory in which to execute @command_line * or %NULL to use the current working directory. * @envp : child's environment, or %NULL to inherit parent's. * @error : return location for errors or %NULL. * * Convenience wrapper to exo_execute_terminal_shell_on_screen(), which * executes the @command_line on the default #GdkScreen. * * Note that even if this method returns %TRUE there's no warranty that * the @command_line was run successfully, because of the way the helper * framework is implemented. But you can be sure that if the execution * fails at a later stage, the library will popup an error dialog to * inform the user that the execution failed. * * Returns: %TRUE on success, else %FALSE. * * Since: 0.3.1.3 **/ gboolean exo_execute_terminal_shell (const gchar *command_line, const gchar *working_directory, gchar **envp, GError **error) { g_return_val_if_fail (command_line != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); return exo_execute_terminal_shell_on_screen (command_line, working_directory, envp, gdk_screen_get_default (), error); } /** * exo_execute_terminal_shell_on_screen: * @command_line : shell command line to execute. * @working_directory : path to the directory in which to execute @command_line * or %NULL to use the current working directory. * @envp : child's environment, or %NULL to inherit parent's. * @screen : the #GdkScreen on which to run the @command_line. * @error : return location for errors or %NULL. * * Executes @command_line in the default terminal emulator on the specified * @screen. * * If no preferred terminal emulator was chosen by the user so far and * no sane fallback could be located, the user will be presented with * the preferred application chooser dialog, which prompts to choose * a default terminal emulator, and the @command_line will be run * afterwards using the new default. * * Note that even if this method returns %TRUE there's no warranty that * the @command_line was run successfully, because of the way the helper * framework is implemented. But you can be sure that if the execution * fails at a later stage, the library will popup an error dialog to * inform the user that the execution failed. * * Returns: %TRUE on success, else %FALSE. * * Since: 0.3.1.3 **/ gboolean exo_execute_terminal_shell_on_screen (const gchar *command_line, const gchar *working_directory, gchar **envp, GdkScreen *screen, GError **error) { g_return_val_if_fail (command_line != NULL, FALSE); g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); return exo_execute_preferred_application_on_screen ("TerminalEmulator", command_line, working_directory, envp, screen, error); } #define __EXO_EXECUTE_C__ #include