Logo Search packages:      
Sourcecode: galeon version File versions

galeon-embed-helper-list.c

/*
 *  Copyright (C) 2000, 2001, 2002 Marco Pesenti Gritti
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "galeon-embed-helper-list.h"
#include "galeon-embed-persist.h"
#ifdef ENABLE_NAUTILUS_VIEW
#include "gul-bonobo-extensions.h"
#endif
#include "gul-string.h"
#include "gul-general.h"

#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <libgnomevfs/gnome-vfs-mime-handlers.h>
#include <libgnomevfs/gnome-vfs-mime.h>
#include <libgnomevfs/gnome-vfs-mime-info.h>
#include <libgnomevfs/gnome-vfs-utils.h>
#include <glib/gi18n.h>
#include <gtk/gtkmenuitem.h>
#include <gtk/gtkseparatormenuitem.h>
#include <gtk/gtkicontheme.h>
#include <gtk/gtkimage.h>
#include <gtk/gtkimagemenuitem.h>
#include <gtk/gtkiconfactory.h>
#include <gtk/gtkmain.h>

static void
galeon_embed_helper_list_class_init (GaleonEmbedHelperListClass *klass);
static void
galeon_embed_helper_list_init (GaleonEmbedHelperList *window);
static void
galeon_embed_helper_list_finalize (GObject *object);
static void
galeon_embed_helper_list_get_property (GObject *object,
                                           guint prop_id,
                                     GValue *value,
                                     GParamSpec *pspec);
static void
galeon_embed_helper_list_set_property (GObject *object,
                                           guint prop_id,
                                     const GValue *value,
                                     GParamSpec *pspec);

enum
{
      PROP_0,
      PROP_GALEON_EMBED
};

#define GALEON_EMBED_HELPER_LIST_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
                               GALEON_TYPE_EMBED_HELPER_LIST, GaleonEmbedHelperListPrivate))


struct GaleonEmbedHelperListPrivate
{
      GaleonEmbed *embed;
      GList *mime_types;
      char *uri;
};

typedef struct {
        GnomeVFSMimeApplication *application;
        char *url;
        GaleonEmbedHelperList *hl;
} ApplicationLaunchParameters;

static GObjectClass *parent_class = NULL;

GType 
galeon_embed_helper_list_get_type (void)
{
        static GType galeon_embed_helper_list_type = 0;

        if (galeon_embed_helper_list_type == 0)
        {
                static const GTypeInfo our_info =
                {
                        sizeof (GaleonEmbedHelperListClass),
                        NULL, /* base_init */
                        NULL, /* base_finalize */
                        (GClassInitFunc) galeon_embed_helper_list_class_init,
                        NULL,
                        NULL, /* class_data */
                        sizeof (GaleonEmbedHelperList),
                        0, /* n_preallocs */
                        (GInstanceInitFunc) galeon_embed_helper_list_init
                };

                galeon_embed_helper_list_type = g_type_register_static (G_TYPE_OBJECT,
                                                                          "GaleonEmbedHelperList",
                                                                          &our_info, 0);
        }

        return galeon_embed_helper_list_type;
}

static void
galeon_embed_helper_list_class_init (GaleonEmbedHelperListClass *klass)
{
        GObjectClass *object_class = G_OBJECT_CLASS (klass);

        parent_class = g_type_class_peek_parent (klass);

        object_class->finalize = galeon_embed_helper_list_finalize;
      object_class->set_property = galeon_embed_helper_list_set_property;
      object_class->get_property = galeon_embed_helper_list_get_property;
      
      g_object_class_install_property (object_class,
                               PROP_GALEON_EMBED,
                                         g_param_spec_object ("GaleonEmbed",
                                                              "GaleonEmbed",
                                                              "Galeon Embed",
                                                              G_TYPE_OBJECT,
                                                              G_PARAM_READWRITE));

      g_type_class_add_private (klass, sizeof (GaleonEmbedHelperListPrivate));
}

static void
galeon_embed_helper_list_init (GaleonEmbedHelperList *dialog)
{
        dialog->priv = GALEON_EMBED_HELPER_LIST_GET_PRIVATE (dialog);

      dialog->priv->embed = NULL;
      dialog->priv->uri = NULL;
}

static void
free_mime_types_list (GaleonEmbedHelperList *hl)
{
      g_list_foreach (hl->priv->mime_types, (GFunc) g_free, NULL);
      g_list_free (hl->priv->mime_types);
      hl->priv->mime_types = NULL;
}

static void
galeon_embed_helper_list_finalize (GObject *object)
{
        GaleonEmbedHelperList *dialog;

        g_return_if_fail (object != NULL);
        g_return_if_fail (GALEON_IS_EMBED_HELPER_LIST (object));

        dialog = GALEON_EMBED_HELPER_LIST (object);

        g_return_if_fail (dialog->priv != NULL);

      g_free (dialog->priv->uri);
      

        G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void
galeon_embed_helper_list_set_property (GObject *object,
                                           guint prop_id,
                                     const GValue *value,
                                     GParamSpec *pspec)
{
        GaleonEmbedHelperList *d = GALEON_EMBED_HELPER_LIST (object);

        switch (prop_id)
        {
                case PROP_GALEON_EMBED:
                        galeon_embed_helper_list_set_embed (d, g_value_get_object (value));
                        break;
        }
}

static void
galeon_embed_helper_list_get_property (GObject *object,
                                           guint prop_id,
                                     GValue *value,
                                     GParamSpec *pspec)
{
        GaleonEmbedHelperList *d = GALEON_EMBED_HELPER_LIST (object);

        switch (prop_id)
        {
                case PROP_GALEON_EMBED:
                        g_value_set_object (value, d->priv->embed);
                        break;
        }
}

GaleonEmbedHelperList *
galeon_embed_helper_list_new (void)
{
      return GALEON_EMBED_HELPER_LIST (g_object_new (GALEON_TYPE_EMBED_HELPER_LIST, 
                                           NULL));
}

void
galeon_embed_helper_list_set_embed (GaleonEmbedHelperList *hl,
                              GaleonEmbed *embed)
{
      hl->priv->embed = embed;
}

gboolean
galeon_embed_helper_list_set_uri (GaleonEmbedHelperList *hl,
                          const char *uri)
{
      char *mime = NULL;
      GnomeVFSURI *vfs_uri;
      
      if (hl->priv->uri) g_free (hl->priv->uri);
      hl->priv->uri = g_strdup (uri);

      free_mime_types_list (hl);

      vfs_uri = gnome_vfs_uri_new (uri);
      if (vfs_uri)
      {
            mime = g_strdup (gnome_vfs_get_mime_type_from_uri (vfs_uri));
            gnome_vfs_uri_unref (vfs_uri);
      }
      
      if (mime && strcmp (mime, "application/octet-stream") != 0)
      {
            galeon_embed_helper_list_add_mime_type (hl, mime);
      }
      else
      {
            g_free (mime);
            return FALSE;
      }

      return TRUE;
}

void
galeon_embed_helper_list_add_mime_type (GaleonEmbedHelperList *hl,
                              const char *mime_type)
{
      /* do not add duped mime types */
      if (g_list_find_custom (hl->priv->mime_types,
                                mime_type,
                                gul_strcasecmp_compare_func))
      {
            return;
      }

      hl->priv->mime_types = g_list_append (hl->priv->mime_types,
                                    g_strdup (mime_type));
}

static ApplicationLaunchParameters *
application_launch_parameters_new (GnomeVFSMimeApplication *application,
                           const char *url,
                           GaleonEmbedHelperList *hl)
{
        ApplicationLaunchParameters *result;

        result = g_new0 (ApplicationLaunchParameters, 1);
        result->application = gnome_vfs_mime_application_copy (application);
      result->hl = hl;
      g_object_ref (result->hl);
      result->url = url ? g_strdup (url) : NULL;

        return result;
}

static void
application_launch_parameters_free (ApplicationLaunchParameters *parameters)
{
      gnome_vfs_mime_application_free (parameters->application);
      g_free (parameters->url);
      g_object_unref (parameters->hl);
      g_free (parameters);
}         

static char *
generate_temp_file_name (const char *ext)
{
      char *base, *result;
      
      base = g_build_filename (g_get_tmp_dir (),
                         "galeon-openwith-XXXXXX", NULL);
      result = gul_general_tmp_filename (base, ext);
      g_free (base);
      
      return result;
}

static void
open_with_temp (GaleonEmbedHelperList *hl,
            const char *location,
            GnomeVFSMimeApplication *app)
{
      GaleonEmbedPersist *persist;
      const char *mime;
      GList *ext;
      char *final_filename;
      
      g_assert (hl->priv->mime_types != NULL);
      mime = (const char *)hl->priv->mime_types->data;

      ext = gnome_vfs_mime_get_extensions_list (mime);
      final_filename = generate_temp_file_name 
            (ext ? (char *)ext->data : NULL);
      gnome_vfs_mime_extensions_list_free (ext);
            
      persist = galeon_embed_persist_new (hl->priv->embed);
      galeon_embed_persist_set_source (persist, location);
      galeon_embed_persist_set_dest (persist, final_filename);
      galeon_embed_persist_set_handler (persist, app);
      galeon_embed_persist_set_user_time (persist, gtk_get_current_event_time());
      galeon_embed_persist_save (persist);
      g_object_unref (G_OBJECT (persist));

      g_free (final_filename);
}

static gboolean
application_supports_uri_scheme (GnomeVFSMimeApplication *application,
                                 const char *uri_scheme)
{
#ifdef HAVE_NEW_GNOME_VFS_MIME_API

      /* There is no way to get the supported schemes in the new API */
      return gnome_vfs_mime_application_supports_uris (application);
#else
      if (application->expects_uris != GNOME_VFS_MIME_APPLICATION_ARGUMENT_TYPE_URIS)
      {
            return FALSE;
      }

        /* The default supported uri scheme is "file" */
        if (application->supported_uri_schemes == NULL
            && g_ascii_strcasecmp (uri_scheme, "file") == 0) {
                return TRUE;
        }

        return g_list_find_custom (application->supported_uri_schemes,
                                   uri_scheme,
                                   gul_strcasecmp_compare_func) != NULL;
#endif
}

static gboolean
open_directly (const char *location,
             GnomeVFSMimeApplication *application)
{
      const char *scheme = NULL;
      GnomeVFSURI *uri;
      char *final_location;
      gboolean result = FALSE;
      
      uri = gnome_vfs_uri_new (location);
      if (uri)
      {
            scheme = gnome_vfs_uri_get_scheme (uri);
      }
      
      final_location = gnome_vfs_get_local_path_from_uri (location);
      if (!final_location)
      {
            final_location = g_strdup (location);
      }
      
      if (scheme && application_supports_uri_scheme (application, scheme))
      {
            /* FIXME: check return value */
            gul_general_launch_application (application, final_location,
                                    gtk_get_current_event_time());
            result = TRUE;
      }

      g_free (final_location);
      if (uri) gnome_vfs_uri_unref (uri);
            
      return result;
}

#ifdef ENABLE_NAUTILUS_VIEW
static void
bonobo_launch_application_callback (BonoboUIComponent *component, gpointer callback_data, const char *path)
{
        ApplicationLaunchParameters *launch_parameters; 
      
      launch_parameters = (ApplicationLaunchParameters *) callback_data;      
      
      if (!open_directly (launch_parameters->url, 
                      launch_parameters->application))
      {     
            open_with_temp (launch_parameters->hl,
                        launch_parameters->url,
                        launch_parameters->application);
      }
}       

static void
add_numbered_menu_item (BonoboUIComponent *ui,
                        const char *parent_path,
                        const char *label,
                        const char *tip,
                        int index,
                        GdkPixbuf *pixbuf,
                        gpointer callback,
                        gpointer callback_data,
                        GDestroyNotify destroy_notify)
{
        char *escaped_parent_path, *escaped_label, *verb_name, *item_path;
        
        escaped_parent_path = gul_string_double_underscores (parent_path);

        escaped_label = gul_string_double_underscores (label);
        gul_bonobo_add_numbered_menu_item 
                (ui, 
                 escaped_parent_path,
                 index,
                 escaped_label, 
                 pixbuf);
        g_free (escaped_label);
        item_path = gul_bonobo_get_numbered_menu_item_path
                (ui, escaped_parent_path, index);
        gul_bonobo_set_tip (ui, item_path, tip);
        g_free (item_path);

        verb_name = gul_bonobo_get_numbered_menu_item_command 
                (ui, escaped_parent_path, index);       
        bonobo_ui_component_add_verb_full (ui, verb_name,
                                           g_cclosure_new (callback, callback_data,
                                                           (GClosureNotify) destroy_notify));      
        g_free (verb_name);

        g_free (escaped_parent_path);
}

static void
add_application_to_bonobo_menu (GaleonEmbedHelperList *hl,
                        BonoboUIComponent *ui_component,
                                GnomeVFSMimeApplication *application, 
                        const char *path,
                        const char *url,
                        int index)
{
        ApplicationLaunchParameters *launch_parameters;
        char *tip;

        launch_parameters = application_launch_parameters_new 
                (application, url, hl);
        tip = g_strdup_printf (_("Use \"%s\" to open the selected item"), application->name);

        add_numbered_menu_item (ui_component, 
                                path,
                                application->name,
                                tip,
                                index,
                                NULL,
                                bonobo_launch_application_callback,
                                launch_parameters,
                                (GDestroyNotify) application_launch_parameters_free);
        g_free (tip);
}
#endif

static void
activate_cb (GtkMenuItem *mi, ApplicationLaunchParameters *launch_parameters)
{
      if (!open_directly (launch_parameters->url, 
                      launch_parameters->application))
      {     
            open_with_temp (launch_parameters->hl,
                        launch_parameters->url,
                        launch_parameters->application);
      }
}       

#ifdef HAVE_NEW_GNOME_VFS_MIME_API
static GtkWidget*
get_icon_from_application (GnomeVFSMimeApplication *application)
{
      GtkWidget *image = NULL;
      const char *icon;
      GtkIconTheme *theme;
      char *name = NULL;

      icon = gnome_vfs_mime_application_get_icon (application);
      if (!icon)
      {
            return NULL;
      }

      if (g_path_is_absolute (icon))
      {
            int width, height;
            GdkPixbuf *pixbuf;

            if (!gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height))
            {
                  width = height = 16;
            }

            pixbuf = gdk_pixbuf_new_from_file_at_size (icon, width, height, NULL);
            if (pixbuf)
            {
                  image = gtk_image_new_from_pixbuf (pixbuf);
                  g_object_unref (pixbuf);
            }
            
            return image;
      }

      theme = gtk_icon_theme_get_default ();

      if (gtk_icon_theme_has_icon (theme, icon))
      {
            name = g_strdup (icon);
      }
      else if (strrchr (icon, '.') != NULL)
      {
            /* If the image is foo.png then search for 'foo' in the icon theme
             * to allow themes to change the icon */
            name = g_strndup (icon, strlen (icon) - strlen (strrchr (icon, '.')));
            if (!gtk_icon_theme_has_icon (theme, name))
            {
                  g_free (name);
                  return NULL;
            }

      }

      if (name)
      {
            image = gtk_image_new_from_icon_name (name, GTK_ICON_SIZE_MENU);
            g_free (name);
      }

      return image;
}
#endif

static void
add_application_to_gtk_menu (GaleonEmbedHelperList *hl,
                       GtkMenuShell *ms,
                       GnomeVFSMimeApplication *application, 
                       const char *url)
{
      GtkWidget *mi;

      if (application != NULL)
      {
            ApplicationLaunchParameters *launch_parameters;

#ifdef HAVE_NEW_GNOME_VFS_MIME_API
            const char *name;
            GtkWidget *image;

            name = gnome_vfs_mime_application_get_name (application);

            mi = gtk_image_menu_item_new_with_label (name);

            image = get_icon_from_application (application);
            if (image)
            {
                  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (mi), image);
            }
#else
            mi = gtk_menu_item_new_with_label (application->name);
#endif

            launch_parameters = application_launch_parameters_new (application, url, hl);
            g_signal_connect_data (mi, "activate", 
                               G_CALLBACK (activate_cb), 
                               launch_parameters, (GClosureNotify) application_launch_parameters_free,
                               (GConnectFlags) 0);
      }
      else
      {
            mi = gtk_separator_menu_item_new ();
      }

      gtk_widget_show (mi);
      gtk_menu_shell_append (ms, mi);
}

static int
application_namecasecmp (gconstpointer ap, gconstpointer bp)
{
      const GnomeVFSMimeApplication *a = ap;
      const GnomeVFSMimeApplication *b = bp;
      char *a_name;
      char *b_name;
      int   ret;

      a_name = g_utf8_casefold (a->name, -1);
      b_name = g_utf8_casefold (b->name, -1);

      ret = g_utf8_collate (a_name, b_name);

      g_free (a_name);
      g_free (b_name);

      return ret;
}

static gboolean
app_in_application_list (GnomeVFSMimeApplication *app, GList *all_apps)
{
#ifdef HAVE_NEW_GNOME_VFS_MIME_API
      GList *l;

      for (l = all_apps ; l ; l = l->next)
      {
            if (gnome_vfs_mime_application_equal (app, l->data))
            {
                  return TRUE;
            }
      }

      return FALSE;

#else

      return gnome_vfs_mime_id_in_application_list (app->id, all_apps);
#endif
}

static GList *
get_all_applications (GList *mime_types)
{
      GnomeVFSMimeApplication *default_app;
      GList *all_apps = NULL;
      GList *lm;

      default_app = gnome_vfs_mime_get_default_application (mime_types->data);

      for (lm = mime_types; lm != NULL; lm = lm->next)
      {
            const char *mime_type = lm->data;
            GList      *apps;
            GList      *la;

            apps = gnome_vfs_mime_get_all_applications (mime_type);
            for (la = apps; la != NULL; la = la->next)
            {
                  GnomeVFSMimeApplication *app = la->data;
                  if (app_in_application_list (app, all_apps))
                  {
                        gnome_vfs_mime_application_free (app);
                  }
                  else if (default_app && strcmp (default_app->id, app->id))
                  {
                        all_apps = g_list_prepend (all_apps, app);
                  }
            }
            g_list_free (apps);
      }

      all_apps = g_list_sort (all_apps, application_namecasecmp);
      if (default_app != NULL)
      {
            all_apps = g_list_prepend (all_apps, NULL);
            all_apps = g_list_prepend (all_apps, default_app);
      }
      return all_apps;
}

#ifdef ENABLE_NAUTILUS_VIEW
static void
setup_openwith_list_bonoboui (GaleonEmbedHelperList *hl,
                        BonoboUIComponent *ui_component,
                        const char *path)
{
      int    index = 0;
      GList *apps;
      GList *l;
      
      apps = get_all_applications (hl->priv->mime_types);

      for (l = apps; l != NULL; l = l->next)
      {
            add_application_to_bonobo_menu 
                  (hl, ui_component, 
                   (GnomeVFSMimeApplication *)l->data,
                   path, hl->priv->uri, index);
            index ++;
      }
            
      gnome_vfs_mime_application_list_free (apps);
}
      
void
galeon_embed_helper_list_add_to_bonoboui_menu (GaleonEmbedHelperList *hl,
                                     BonoboUIComponent *ui_component,
                                     const char *path)
{
      setup_openwith_list_bonoboui (hl, ui_component, path);
}
#endif


void
galeon_embed_helper_list_add_to_gtk_menu (GaleonEmbedHelperList *hl,
                                GtkMenuShell *ms)
{
      GList *apps;
      GList *l;

      apps = get_all_applications (hl->priv->mime_types);

      for (l = apps; l != NULL; l = l->next)
      {
            add_application_to_gtk_menu (hl, ms, l->data, hl->priv->uri);
      }

      gnome_vfs_mime_application_list_free (apps);
}


Generated by  Doxygen 1.6.0   Back to index