]> www.fi.muni.cz Git - evince.git/blobdiff - shell/ev-sidebar-attachments.c
[dualscreen] fix crash on ctrl+w and fix control window closing
[evince.git] / shell / ev-sidebar-attachments.c
index aac63cf7a5158fd3f67d73ad9b2f4a1ac79cd770..5b717896ac1a913732a58c6dcaaa8d3040ca4e81 100644 (file)
  *
  * 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.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
+#include <string.h>
+
 #include <glib/gi18n.h>
 #include <glib/gstdio.h>
 #include <gtk/gtk.h>
-#include <string.h>
-#include <libgnomeui/gnome-icon-lookup.h>
 
+#include "ev-document-attachments.h"
+#include "ev-jobs.h"
+#include "ev-job-scheduler.h"
+#include "ev-file-helpers.h"
 #include "ev-sidebar-attachments.h"
 #include "ev-sidebar-page.h"
 
@@ -42,7 +46,6 @@ enum {
        N_COLS
 };
 
-
 enum {
        PROP_0,
        PROP_WIDGET,
@@ -53,10 +56,6 @@ enum {
        N_SIGNALS
 };
 
-static const GtkTargetEntry drag_targets[] = {
-       { "text/uri-list", 0, 0 }
-};
-
 static guint signals[N_SIGNALS];
 
 struct _EvSidebarAttachmentsPrivate {
@@ -68,7 +67,7 @@ struct _EvSidebarAttachmentsPrivate {
        GHashTable     *icon_cache;
 };
 
-static void ev_sidebar_attachments_page_iface_init (EvSidebarPageIface *iface);
+static void ev_sidebar_attachments_page_iface_init (EvSidebarPageInterface *iface);
 
 G_DEFINE_TYPE_EXTENDED (EvSidebarAttachments,
                         ev_sidebar_attachments,
@@ -83,8 +82,8 @@ G_DEFINE_TYPE_EXTENDED (EvSidebarAttachments,
 /* Icon cache */
 static void
 ev_sidebar_attachments_icon_cache_add (EvSidebarAttachments *ev_attachbar,
-                                 const gchar     *mime_type,
-                                 const GdkPixbuf *pixbuf)
+                                      const gchar          *mime_type,
+                                      const GdkPixbuf      *pixbuf)
 {
        g_assert (mime_type != NULL);
        g_assert (GDK_IS_PIXBUF (pixbuf));
@@ -99,26 +98,34 @@ static GdkPixbuf *
 icon_theme_get_pixbuf_from_mime_type (GtkIconTheme *icon_theme,
                                      const gchar  *mime_type)
 {
-       GdkPixbuf *pixbuf = NULL;
-       gchar     *icon;
-
-       icon = gnome_icon_lookup (icon_theme,
-                                 NULL, NULL,
-                                 NULL, NULL,
-                                 mime_type,
-                                 GNOME_ICON_LOOKUP_FLAGS_NONE,
-                                 NULL);
-
-       pixbuf = gtk_icon_theme_load_icon (icon_theme,
-                                          icon, 48, 0, NULL);
-       g_free (icon);
-
+       const char *separator;
+       GString *icon_name;
+       GdkPixbuf *pixbuf;
+
+       separator = strchr (mime_type, '/');
+       if (!separator)
+               return NULL; /* maybe we should return a GError with "invalid MIME-type" */
+
+       icon_name = g_string_new ("gnome-mime-");
+       g_string_append_len (icon_name, mime_type, separator - mime_type);
+       g_string_append_c (icon_name, '-');
+       g_string_append (icon_name, separator + 1);
+       pixbuf = gtk_icon_theme_load_icon (icon_theme, icon_name->str, 48, 0, NULL);
+       g_string_free (icon_name, TRUE);
+       if (pixbuf)
+               return pixbuf;
+       
+       icon_name = g_string_new ("gnome-mime-");
+       g_string_append_len (icon_name, mime_type, separator - mime_type);
+       pixbuf = gtk_icon_theme_load_icon (icon_theme, icon_name->str, 48, 0, NULL);
+       g_string_free (icon_name, TRUE);
+       
        return pixbuf;
 }
 
 static GdkPixbuf *
 ev_sidebar_attachments_icon_cache_get (EvSidebarAttachments *ev_attachbar,
-                                 const gchar     *mime_type)
+                                      const gchar          *mime_type)
 {
        GdkPixbuf *pixbuf = NULL;
        
@@ -135,15 +142,15 @@ ev_sidebar_attachments_icon_cache_get (EvSidebarAttachments *ev_attachbar,
 
        if (GDK_IS_PIXBUF (pixbuf))
                ev_sidebar_attachments_icon_cache_add (ev_attachbar,
-                                                 mime_type,
-                                                 pixbuf);
+                                                      mime_type,
+                                                      pixbuf);
 
        return pixbuf;
 }
 
 static gboolean
-icon_cache_update_icon (gchar           *key,
-                       GdkPixbuf       *value,
+icon_cache_update_icon (gchar                *key,
+                       GdkPixbuf            *value,
                        EvSidebarAttachments *ev_attachbar)
 {
        GdkPixbuf *pixbuf = NULL;
@@ -152,8 +159,8 @@ icon_cache_update_icon (gchar           *key,
                                                       key);
 
        ev_sidebar_attachments_icon_cache_add (ev_attachbar,
-                                         key,
-                                         pixbuf);
+                                              key,
+                                              pixbuf);
        
        return FALSE;
 }
@@ -168,8 +175,8 @@ ev_sidebar_attachments_icon_cache_refresh (EvSidebarAttachments *ev_attachbar)
 
 static EvAttachment *
 ev_sidebar_attachments_get_attachment_at_pos (EvSidebarAttachments *ev_attachbar,
-                                        gint             x,
-                                        gint             y)
+                                             gint                  x,
+                                             gint                  y)
 {
        GtkTreePath  *path = NULL;
        GtkTreeIter   iter;
@@ -197,8 +204,8 @@ ev_sidebar_attachments_get_attachment_at_pos (EvSidebarAttachments *ev_attachbar
 
 static gboolean
 ev_sidebar_attachments_popup_menu_show (EvSidebarAttachments *ev_attachbar,
-                                  gint             x,
-                                  gint             y)
+                                       gint                  x,
+                                       gint                  y)
 {
        GtkIconView *icon_view;
        GtkTreePath *path;
@@ -254,7 +261,7 @@ static gboolean
 ev_sidebar_attachments_popup_menu (GtkWidget *widget)
 {
        EvSidebarAttachments *ev_attachbar = EV_SIDEBAR_ATTACHMENTS (widget);
-       gint             x, y;
+       gint                  x, y;
 
        gtk_widget_get_pointer (widget, &x, &y);
 
@@ -263,10 +270,10 @@ ev_sidebar_attachments_popup_menu (GtkWidget *widget)
 
 static gboolean
 ev_sidebar_attachments_button_press (EvSidebarAttachments *ev_attachbar,
-                               GdkEventButton  *event,
-                               GtkWidget       *icon_view)
+                                    GdkEventButton       *event,
+                                    GtkWidget            *icon_view)
 {
-       if (!GTK_WIDGET_HAS_FOCUS (icon_view)) {
+       if (!gtk_widget_has_focus (icon_view)) {
                gtk_widget_grab_focus (icon_view);
        }
        
@@ -274,31 +281,34 @@ ev_sidebar_attachments_button_press (EvSidebarAttachments *ev_attachbar,
                return FALSE;
 
        switch (event->button) {
-       case 1:
-               if (event->type == GDK_2BUTTON_PRESS) {
-                       GError *error = NULL;
-                       EvAttachment *attachment;
-
-                       attachment = ev_sidebar_attachments_get_attachment_at_pos (ev_attachbar,
-                                                                             event->x,
-                                                                             event->y);
-                       if (!attachment)
-                               return FALSE;
-                       
-                       ev_attachment_open (attachment, &error);
-
-                       if (error) {
-                               g_warning (error->message);
-                               g_error_free (error);
+               case 1:
+                       if (event->type == GDK_2BUTTON_PRESS) {
+                               GError *error = NULL;
+                               EvAttachment *attachment;
+                               
+                               attachment = ev_sidebar_attachments_get_attachment_at_pos (ev_attachbar,
+                                                                                          event->x,
+                                                                                          event->y);
+                               if (!attachment)
+                                       return FALSE;
+                               
+                               ev_attachment_open (attachment,
+                                                   gtk_widget_get_screen (GTK_WIDGET (ev_attachbar)),
+                                                   event->time,
+                                                   &error);
+                               
+                               if (error) {
+                                       g_warning ("%s", error->message);
+                                       g_error_free (error);
+                               }
+                               
+                               g_object_unref (attachment);
+                               
+                               return TRUE;
                        }
-
-                       g_object_unref (attachment);
-                                           
-                       return TRUE;
-               }
-               break;
-       case 3: 
-               return ev_sidebar_attachments_popup_menu_show (ev_attachbar, event->x, event->y);
+                       break;
+               case 3: 
+                       return ev_sidebar_attachments_popup_menu_show (ev_attachbar, event->x, event->y);
        }
 
        return FALSE;
@@ -306,7 +316,7 @@ ev_sidebar_attachments_button_press (EvSidebarAttachments *ev_attachbar,
 
 static void
 ev_sidebar_attachments_update_icons (EvSidebarAttachments *ev_attachbar,
-                               gpointer         user_data)
+                                    gpointer              user_data)
 {
        GtkTreeIter iter;
        gboolean    valid;
@@ -332,7 +342,7 @@ ev_sidebar_attachments_update_icons (EvSidebarAttachments *ev_attachbar,
                        g_object_unref (attachment);
 
                pixbuf = ev_sidebar_attachments_icon_cache_get (ev_attachbar,
-                                                          mime_type);
+                                                               mime_type);
 
                gtk_list_store_set (ev_attachbar->priv->model, &iter,
                                    COLUMN_ICON, pixbuf,
@@ -344,30 +354,63 @@ ev_sidebar_attachments_update_icons (EvSidebarAttachments *ev_attachbar,
        }
 }
 
+static void
+ev_sidebar_attachments_screen_changed (GtkWidget *widget,
+                                      GdkScreen *old_screen)
+{
+       EvSidebarAttachments *ev_attachbar = EV_SIDEBAR_ATTACHMENTS (widget);
+       GdkScreen            *screen;
+
+       if (!ev_attachbar->priv->icon_theme)
+               return;
+       
+       screen = gtk_widget_get_screen (widget);
+       if (screen == old_screen)
+               return;
+
+       if (old_screen) {
+               g_signal_handlers_disconnect_by_func (
+                       gtk_icon_theme_get_for_screen (old_screen),
+                       G_CALLBACK (ev_sidebar_attachments_update_icons),
+                       ev_attachbar);
+       }
+
+       ev_attachbar->priv->icon_theme = gtk_icon_theme_get_for_screen (screen);
+       g_signal_connect_swapped (ev_attachbar->priv->icon_theme,
+                                 "changed",
+                                 G_CALLBACK (ev_sidebar_attachments_update_icons),
+                                 (gpointer) ev_attachbar);
+
+       if (GTK_WIDGET_CLASS (ev_sidebar_attachments_parent_class)->screen_changed) {
+               GTK_WIDGET_CLASS (ev_sidebar_attachments_parent_class)->screen_changed (widget, old_screen);
+       }
+}
+
 static void
 ev_sidebar_attachments_drag_data_get (GtkWidget        *widget,
-                                GdkDragContext   *drag_context,
-                                GtkSelectionData *data,
-                                guint             info,
-                                guint             time,
-                                gpointer          user_data)
+                                     GdkDragContext   *drag_context,
+                                     GtkSelectionData *data,
+                                     guint             info,
+                                     guint             time,
+                                     gpointer          user_data)
 {
        EvSidebarAttachments *ev_attachbar = EV_SIDEBAR_ATTACHMENTS (user_data);
-       GString         *uri_list;
-       gchar           *uris = NULL;
-       GList           *selected = NULL, *l;
+       GList                *selected = NULL, *l;
+        GPtrArray            *uris;
+        char                **uri_list;
 
        selected = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (ev_attachbar->priv->icon_view));
        if (!selected)
                return;
 
-       uri_list = g_string_new (NULL);
+        uris = g_ptr_array_new ();
        
        for (l = selected; l && l->data; l = g_list_next (l)) {
                EvAttachment *attachment;
                GtkTreePath  *path;
                GtkTreeIter   iter;
-               gchar        *uri, *filename;
+               GFile        *file;
+               gchar        *template;
                GError       *error = NULL;
                
                path = (GtkTreePath *) l->data;
@@ -378,36 +421,32 @@ ev_sidebar_attachments_drag_data_get (GtkWidget        *widget,
                                    COLUMN_ATTACHMENT, &attachment,
                                    -1);
 
-               filename = g_build_filename (g_get_tmp_dir (),
-                                            ev_attachment_get_name (attachment),
-                                            NULL);
+                /* FIXMEchpe: convert to filename encoding first! */
+                template = g_strdup_printf ("%s.XXXXXX", ev_attachment_get_name (attachment));
+                file = ev_mkstemp_file (template, &error);
+                g_free (template);
                
-               uri = g_filename_to_uri (filename, NULL, NULL);
+               if (file != NULL && ev_attachment_save (attachment, file, &error)) {
+                       gchar *uri;
 
-               if (ev_attachment_save (attachment, filename, &error)) {
-                       g_string_append (uri_list, uri);
-                       g_string_append_c (uri_list, '\n');
+                       uri = g_file_get_uri (file);
+                        g_ptr_array_add (uris, uri);
                }
        
                if (error) {
-                       g_warning (error->message);
+                       g_warning ("%s", error->message);
                        g_error_free (error);
                }
 
-               g_free (uri);
                gtk_tree_path_free (path);
+               g_object_unref (file);
                g_object_unref (attachment);
        }
 
-       uris = g_string_free (uri_list, FALSE);
-
-       if (uris) {
-               gtk_selection_data_set (data,
-                                       data->target,
-                                       8,
-                                       (guchar *)uris,
-                                       strlen (uris));
-       }
+        g_ptr_array_add (uris, NULL); /* NULL-terminate */
+        uri_list = (char **) g_ptr_array_free (uris, FALSE);
+        gtk_selection_data_set_uris (data, uri_list);
+        g_strfreev (uri_list);
 
        g_list_free (selected);
 }
@@ -422,22 +461,29 @@ ev_sidebar_attachments_get_property (GObject    *object,
   
        ev_sidebar_attachments = EV_SIDEBAR_ATTACHMENTS (object);
 
-       switch (prop_id)
-       {
-       case PROP_WIDGET:
-               g_value_set_object (value, ev_sidebar_attachments->priv->icon_view);
-               break;
-       default:
-               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-               break;
+       switch (prop_id) {
+               case PROP_WIDGET:
+                       g_value_set_object (value, ev_sidebar_attachments->priv->icon_view);
+                       break;
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                       break;
        }
 }
 
 static void
-ev_sidebar_attachments_destroy (GtkObject *object)
+ev_sidebar_attachments_dispose (GObject *object)
 {
        EvSidebarAttachments *ev_attachbar = EV_SIDEBAR_ATTACHMENTS (object);
 
+       if (ev_attachbar->priv->icon_theme) {
+               g_signal_handlers_disconnect_by_func (
+                       ev_attachbar->priv->icon_theme, 
+                       G_CALLBACK (ev_sidebar_attachments_update_icons),
+                       ev_attachbar);
+               ev_attachbar->priv->icon_theme = NULL;
+       }
+       
        if (ev_attachbar->priv->model) {
                g_object_unref (ev_attachbar->priv->model);
                ev_attachbar->priv->model = NULL;
@@ -448,23 +494,22 @@ ev_sidebar_attachments_destroy (GtkObject *object)
                ev_attachbar->priv->icon_cache = NULL;
        }
 
-       (* GTK_OBJECT_CLASS (ev_sidebar_attachments_parent_class)->destroy) (object);
+       G_OBJECT_CLASS (ev_sidebar_attachments_parent_class)->dispose (object);
 }
 
 static void
 ev_sidebar_attachments_class_init (EvSidebarAttachmentsClass *ev_attachbar_class)
 {
        GObjectClass   *g_object_class;
-       GtkObjectClass *gtk_object_class;
        GtkWidgetClass *gtk_widget_class;
 
        g_object_class = G_OBJECT_CLASS (ev_attachbar_class);
-       gtk_object_class = GTK_OBJECT_CLASS (ev_attachbar_class);
        gtk_widget_class = GTK_WIDGET_CLASS (ev_attachbar_class);
 
        g_object_class->get_property = ev_sidebar_attachments_get_property;
-       gtk_object_class->destroy = ev_sidebar_attachments_destroy;
+       g_object_class->dispose = ev_sidebar_attachments_dispose;
        gtk_widget_class->popup_menu = ev_sidebar_attachments_popup_menu;
+       gtk_widget_class->screen_changed = ev_sidebar_attachments_screen_changed;
 
        g_type_class_add_private (g_object_class, sizeof (EvSidebarAttachmentsPrivate));
 
@@ -514,25 +559,20 @@ ev_sidebar_attachments_init (EvSidebarAttachments *ev_attachbar)
                      "text-column", COLUMN_NAME,
                      "pixbuf-column", COLUMN_ICON,
                      NULL);
-       g_signal_connect_swapped (G_OBJECT (ev_attachbar->priv->icon_view),
+       g_signal_connect_swapped (ev_attachbar->priv->icon_view,
                                  "button-press-event",
                                  G_CALLBACK (ev_sidebar_attachments_button_press),
                                  (gpointer) ev_attachbar);
 
        gtk_container_add (GTK_CONTAINER (swindow),
                           ev_attachbar->priv->icon_view);
-       gtk_widget_show (ev_attachbar->priv->icon_view);
 
        gtk_container_add (GTK_CONTAINER (ev_attachbar),
                           swindow);
-       gtk_widget_show (swindow);
+       gtk_widget_show_all (GTK_WIDGET (ev_attachbar));
 
        /* Icon Theme */
-       ev_attachbar->priv->icon_theme = gtk_icon_theme_get_default ();
-       g_signal_connect_swapped (G_OBJECT (ev_attachbar->priv->icon_theme),
-                                 "changed",
-                                 G_CALLBACK (ev_sidebar_attachments_update_icons),
-                                 (gpointer) ev_attachbar);
+       ev_attachbar->priv->icon_theme = NULL;
 
        /* Icon Cache */
        ev_attachbar->priv->icon_cache = g_hash_table_new_full (g_str_hash,
@@ -541,15 +581,14 @@ ev_sidebar_attachments_init (EvSidebarAttachments *ev_attachbar)
                                                                g_object_unref);
 
        /* Drag and Drop */
-#ifdef HAVE_GTK_ICON_VIEW_ENABLE_MODEL_DRAG_SOURCE
        gtk_icon_view_enable_model_drag_source (
                GTK_ICON_VIEW (ev_attachbar->priv->icon_view),
-                              GDK_BUTTON1_MASK,
-                              drag_targets,
-                              G_N_ELEMENTS (drag_targets),
-                              GDK_ACTION_COPY);
-#endif
-       g_signal_connect (G_OBJECT (ev_attachbar->priv->icon_view),
+               GDK_BUTTON1_MASK,
+               NULL, 0,
+               GDK_ACTION_COPY);
+        gtk_drag_source_add_uri_targets (ev_attachbar->priv->icon_view);
+
+       g_signal_connect (ev_attachbar->priv->icon_view,
                          "drag-data-get",
                          G_CALLBACK (ev_sidebar_attachments_drag_data_get),
                          (gpointer) ev_attachbar);     
@@ -566,21 +605,12 @@ ev_sidebar_attachments_new (void)
 }
 
 static void
-ev_sidebar_attachments_set_document (EvSidebarPage   *page,
-                                    EvDocument      *document)
+job_finished_callback (EvJobAttachments     *job,
+                      EvSidebarAttachments *ev_attachbar)
 {
-       EvSidebarAttachments *ev_attachbar = EV_SIDEBAR_ATTACHMENTS (page);
-       GList *attachments = NULL;
        GList *l;
        
-       if (!ev_document_has_attachments (document))
-               return;
-
-       attachments = ev_document_get_attachments (document);
-
-       gtk_list_store_clear (ev_attachbar->priv->model);
-                                          
-       for (l = attachments; l && l->data; l = g_list_next (l)) {
+       for (l = job->attachments; l && l->data; l = g_list_next (l)) {
                EvAttachment *attachment;
                GtkTreeIter   iter;
                GdkPixbuf    *pixbuf = NULL;
@@ -590,7 +620,7 @@ ev_sidebar_attachments_set_document (EvSidebarPage   *page,
 
                mime_type = ev_attachment_get_mime_type (attachment);
                pixbuf = ev_sidebar_attachments_icon_cache_get (ev_attachbar,
-                                                          mime_type);
+                                                               mime_type);
 
                gtk_list_store_append (ev_attachbar->priv->model, &iter);
                gtk_list_store_set (ev_attachbar->priv->model, &iter,
@@ -598,31 +628,78 @@ ev_sidebar_attachments_set_document (EvSidebarPage   *page,
                                    COLUMN_ICON, pixbuf,
                                    COLUMN_ATTACHMENT, attachment, 
                                    -1);
+       }
 
-               g_object_unref (attachment);
+       g_object_unref (job);
+}
+
+
+static void
+ev_sidebar_attachments_document_changed_cb (EvDocumentModel      *model,
+                                           GParamSpec           *pspec,
+                                           EvSidebarAttachments *ev_attachbar)
+{
+       EvDocument *document = ev_document_model_get_document (model);
+       EvJob *job;
+
+       if (!EV_IS_DOCUMENT_ATTACHMENTS (document))
+               return;
+
+       if (!ev_document_attachments_has_attachments (EV_DOCUMENT_ATTACHMENTS (document)))
+               return;
+
+       if (!ev_attachbar->priv->icon_theme) {
+               GdkScreen *screen;
+
+               screen = gtk_widget_get_screen (GTK_WIDGET (ev_attachbar));
+               ev_attachbar->priv->icon_theme = gtk_icon_theme_get_for_screen (screen);
+               g_signal_connect_swapped (ev_attachbar->priv->icon_theme,
+                                         "changed",
+                                         G_CALLBACK (ev_sidebar_attachments_update_icons),
+                                         (gpointer) ev_attachbar);
        }
+               
+       gtk_list_store_clear (ev_attachbar->priv->model);
 
-       g_list_free (attachments);
+       job = ev_job_attachments_new (document);
+       g_signal_connect (job, "finished",
+                         G_CALLBACK (job_finished_callback),
+                         ev_attachbar);
+       g_signal_connect (job, "cancelled",
+                         G_CALLBACK (g_object_unref),
+                         NULL);
+       /* The priority doesn't matter for this job */
+       ev_job_scheduler_push_job (job, EV_JOB_PRIORITY_NONE);
+}
+
+static void
+ev_sidebar_attachments_set_model (EvSidebarPage   *page,
+                                 EvDocumentModel *model)
+{
+       g_signal_connect (model, "notify::document",
+                         G_CALLBACK (ev_sidebar_attachments_document_changed_cb),
+                         page);
 }
 
 static gboolean
 ev_sidebar_attachments_support_document (EvSidebarPage   *sidebar_page,
-                                       EvDocument *document)
+                                        EvDocument      *document)
 {
-       return ev_document_has_attachments (document);
+       return (EV_IS_DOCUMENT_ATTACHMENTS (document) &&
+               ev_document_attachments_has_attachments (EV_DOCUMENT_ATTACHMENTS (document)));
 }
 
 static const gchar*
 ev_sidebar_attachments_get_label (EvSidebarPage *sidebar_page)
 {
-    return _("Attachments");
+       return _("Attachments");
 }
 
 static void
-ev_sidebar_attachments_page_iface_init (EvSidebarPageIface *iface)
+ev_sidebar_attachments_page_iface_init (EvSidebarPageInterface *iface)
 {
        iface->support_document = ev_sidebar_attachments_support_document;
-       iface->set_document = ev_sidebar_attachments_set_document;
+       iface->set_model = ev_sidebar_attachments_set_model;
        iface->get_label = ev_sidebar_attachments_get_label;
 }