/* nautilus-program-choosing.c - functions for selecting and activating
 *                                programs for opening/viewing particular files.
 *
 *  Copyright (C) 2000 Eazel, Inc.
 *
 *  The Gnome 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.
 *
 *  The Gnome 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 Library General Public
 *  License along with the Gnome Library; see the file COPYING.LIB.  If not,
 *  see <http://www.gnu.org/licenses/>.
 *
 *  Author: John Sullivan <sullivan@eazel.com>
 */

#include <config.h>
#include "nautilus-program-choosing.h"

#include "nautilus-file.h"
#include "nautilus-global-preferences.h"
#include "nautilus-icon-info.h"
#include "nautilus-scheme.h"
#include "nautilus-ui-utilities.h"
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <gio/gio.h>
#include <gio/gdesktopappinfo.h>
#include <stdlib.h>

#include <gdk/gdk.h>

static void
add_file_to_recent (NautilusFile *file,
                    GAppInfo     *application)
{
    const gchar *scheme;
    GtkRecentData recent_data;
    g_autofree char *uri = nautilus_file_get_activation_uri (file);
    if (uri == NULL)
    {
        uri = nautilus_file_get_uri (file);
    }

    /* do not add trash:// etc */
    scheme = g_uri_peek_scheme (uri);
    if (scheme != NULL &&
        (g_str_equal (scheme, SCHEME_TRASH) ||
         g_str_equal (scheme, SCHEME_SEARCH) ||
         g_str_equal (scheme, SCHEME_RECENT)))
    {
        return;
    }

    recent_data.display_name = NULL;
    recent_data.description = NULL;

    recent_data.mime_type = g_strdup (nautilus_file_get_mime_type (file));
    recent_data.app_name = g_strdup (g_get_application_name ());
    recent_data.app_exec = g_strdup (g_app_info_get_commandline (application));

    recent_data.groups = NULL;
    recent_data.is_private = FALSE;

    gtk_recent_manager_add_full (gtk_recent_manager_get_default (),
                                 uri, &recent_data);

    g_free (recent_data.mime_type);
    g_free (recent_data.app_name);
    g_free (recent_data.app_exec);
}
void
nautilus_launch_application_for_mount (GAppInfo  *app_info,
                                       GMount    *mount,
                                       GtkWindow *parent_window)
{
    g_autoptr (GFile) root = g_mount_get_root (mount);
    g_autoptr (NautilusFile) file = nautilus_file_get (root);

    nautilus_launch_application (app_info,
                                 &(NautilusFileList){ .data = file },
                                 parent_window);
}

/**
 * nautilus_launch_application:
 *
 * Fork off a process to launch an application with a given file as a
 * parameter. Provide a parent window for error dialogs.
 *
 * @application: The application to be launched.
 * @uris: The files whose locations should be passed as a parameter to the application.
 * @parent_window: A window to use as the parent for any error dialogs.
 */
void
nautilus_launch_application (GAppInfo         *application,
                             NautilusFileList *files,
                             GtkWindow        *parent_window)
{
    GList *uris, *l;

    uris = NULL;
    for (l = files; l != NULL; l = l->next)
    {
        uris = g_list_prepend (uris, nautilus_file_get_activation_uri (l->data));
    }
    uris = g_list_reverse (uris);
    nautilus_launch_application_by_uri (application, uris,
                                        parent_window);
    g_list_free_full (uris, g_free);
}

static GdkAppLaunchContext *
get_launch_context (GtkWindow *parent_window)
{
    GdkDisplay *display;
    GdkAppLaunchContext *launch_context;

    if (parent_window != NULL)
    {
        display = gtk_widget_get_display (GTK_WIDGET (parent_window));
    }
    else
    {
        display = gdk_display_get_default ();
    }

    launch_context = gdk_display_get_app_launch_context (display);

    return launch_context;
}

void
nautilus_launch_application_by_uri (GAppInfo  *application,
                                    GList     *uris,
                                    GtkWindow *parent_window)
{
    char *uri;
    GList *locations, *l;
    GFile *location;
    NautilusFile *file;
    gboolean result;
    GError *error;
    g_autoptr (GdkAppLaunchContext) launch_context = NULL;
    GIcon *icon;
    gboolean all_uris_local = TRUE;

    g_assert (uris != NULL);

    locations = NULL;
    for (l = uris; l != NULL; l = l->next)
    {
        uri = l->data;

        location = g_file_new_for_uri (uri);
        if (!g_file_is_native (location))
        {
            all_uris_local = FALSE;
        }
        locations = g_list_prepend (locations, location);
    }
    locations = g_list_reverse (locations);

    launch_context = get_launch_context (parent_window);

    file = nautilus_file_get_by_uri (uris->data);
    icon = nautilus_file_get_gicon (file, NAUTILUS_FILE_ICON_FLAGS_NONE);
    nautilus_file_unref (file);
    if (icon)
    {
        gdk_app_launch_context_set_icon (launch_context, icon);
        g_object_unref (icon);
    }

    error = NULL;

    if (all_uris_local)
    {
        /* All files are local, so we can use g_app_info_launch () with
         * the file list we constructed before.
         */
        result = g_app_info_launch (application,
                                    locations,
                                    G_APP_LAUNCH_CONTEXT (launch_context),
                                    &error);
    }
    else
    {
        /* Some files are non local, better use g_app_info_launch_uris ().
         */
        result = g_app_info_launch_uris (application,
                                         uris,
                                         G_APP_LAUNCH_CONTEXT (launch_context),
                                         &error);
    }

    if (result)
    {
        for (l = uris; l != NULL; l = l->next)
        {
            file = nautilus_file_get_by_uri (l->data);
            add_file_to_recent (file, application);
            nautilus_file_unref (file);
        }
    }

    g_list_free_full (locations, g_object_unref);
}

static void
launch_application_from_command_internal (const gchar *full_command,
                                          GdkDisplay  *display,
                                          gboolean     use_terminal)
{
    GAppInfoCreateFlags flags;
    g_autoptr (GError) error = NULL;
    g_autoptr (GAppInfo) app = NULL;

    flags = G_APP_INFO_CREATE_NONE;
    if (use_terminal)
    {
        flags = G_APP_INFO_CREATE_NEEDS_TERMINAL;
    }

    app = g_app_info_create_from_commandline (full_command, NULL, flags, &error);
    if (app != NULL && !(use_terminal && display == NULL))
    {
        g_autoptr (GdkAppLaunchContext) context = NULL;

        context = gdk_display_get_app_launch_context (display);

        g_app_info_launch (app, NULL, G_APP_LAUNCH_CONTEXT (context), &error);
    }

    if (error != NULL)
    {
        g_message ("Could not start app: %s", error->message);
    }
}

/**
 * nautilus_launch_application_from_command:
 *
 * Fork off a process to launch an application with a given uri as
 * a parameter.
 *
 * @command_string: The application to be launched, with any desired
 * command-line options.
 * @...: Passed as parameters to the application after quoting each of them.
 */
void
nautilus_launch_application_from_command (GdkDisplay *display,
                                          const char *command_string,
                                          gboolean    use_terminal,
                                          ...)
{
    char *full_command, *tmp;
    char *quoted_parameter;
    char *parameter;
    va_list ap;

    full_command = g_strdup (command_string);

    va_start (ap, use_terminal);

    while ((parameter = va_arg (ap, char *)) != NULL)
    {
        quoted_parameter = g_shell_quote (parameter);
        tmp = g_strconcat (full_command, " ", quoted_parameter, NULL);
        g_free (quoted_parameter);

        g_free (full_command);
        full_command = tmp;
    }

    va_end (ap);

    launch_application_from_command_internal (full_command, display, use_terminal);

    g_free (full_command);
}

/**
 * nautilus_launch_application_from_command:
 *
 * Fork off a process to launch an application with a given uri as
 * a parameter.
 *
 * @command_string: The application to be launched, with any desired
 * command-line options.
 * @parameters: Passed as parameters to the application after quoting each of them.
 */
void
nautilus_launch_application_from_command_array (GdkDisplay         *display,
                                                const char         *command_string,
                                                gboolean            use_terminal,
                                                const char * const *parameters)
{
    char *full_command, *tmp;
    char *quoted_parameter;
    const char * const *p;

    full_command = g_strdup (command_string);

    if (parameters != NULL)
    {
        for (p = parameters; *p != NULL; p++)
        {
            quoted_parameter = g_shell_quote (*p);
            tmp = g_strconcat (full_command, " ", quoted_parameter, NULL);
            g_free (quoted_parameter);

            g_free (full_command);
            full_command = tmp;
        }
    }

    launch_application_from_command_internal (full_command, display, use_terminal);

    g_free (full_command);
}
