]> www.fi.muni.cz Git - evince.git/blob - shell/ev-sidebar-attachments.c
Use always ev_tmp_dir instead of g_get_tmp_dir. Fix a race condition in
[evince.git] / shell / ev-sidebar-attachments.c
1 /* ev-sidebar-attachments.c
2  *  this file is part of evince, a gnome document viewer
3  *
4  * Copyright (C) 2006 Carlos Garcia Campos
5  *
6  * Author:
7  *   Carlos Garcia Campos <carlosgc@gnome.org>
8  *
9  * Evince is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Evince is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <glib/gi18n.h>
29 #include <glib/gstdio.h>
30 #include <gtk/gtk.h>
31 #include <string.h>
32 #include <libgnomeui/gnome-icon-lookup.h>
33
34 #include "ev-file-helpers.h"
35 #include "ev-sidebar-attachments.h"
36 #include "ev-sidebar-page.h"
37
38 enum {
39         COLUMN_ICON,
40         COLUMN_NAME,
41         COLUMN_DESCRIPTION,
42         COLUMN_ATTACHMENT,
43         N_COLS
44 };
45
46 enum {
47         PROP_0,
48         PROP_WIDGET,
49 };
50
51 enum {
52         SIGNAL_POPUP_MENU,
53         N_SIGNALS
54 };
55
56 static const GtkTargetEntry drag_targets[] = {
57         { "text/uri-list", 0, 0 }
58 };
59
60 static guint signals[N_SIGNALS];
61
62 struct _EvSidebarAttachmentsPrivate {
63         GtkWidget      *icon_view;
64         GtkListStore   *model;
65
66         /* Icons */
67         GtkIconTheme   *icon_theme;
68         GHashTable     *icon_cache;
69 };
70
71 static void ev_sidebar_attachments_page_iface_init (EvSidebarPageIface *iface);
72
73 G_DEFINE_TYPE_EXTENDED (EvSidebarAttachments,
74                         ev_sidebar_attachments,
75                         GTK_TYPE_VBOX,
76                         0, 
77                         G_IMPLEMENT_INTERFACE (EV_TYPE_SIDEBAR_PAGE, 
78                                                ev_sidebar_attachments_page_iface_init))
79
80 #define EV_SIDEBAR_ATTACHMENTS_GET_PRIVATE(object) \
81                 (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_SIDEBAR_ATTACHMENTS, EvSidebarAttachmentsPrivate))
82
83 /* Icon cache */
84 static void
85 ev_sidebar_attachments_icon_cache_add (EvSidebarAttachments *ev_attachbar,
86                                        const gchar          *mime_type,
87                                        const GdkPixbuf      *pixbuf)
88 {
89         g_assert (mime_type != NULL);
90         g_assert (GDK_IS_PIXBUF (pixbuf));
91
92         g_hash_table_insert (ev_attachbar->priv->icon_cache,
93                              (gpointer)g_strdup (mime_type),
94                              (gpointer)pixbuf);
95                              
96 }
97
98 static GdkPixbuf *
99 icon_theme_get_pixbuf_from_mime_type (GtkIconTheme *icon_theme,
100                                       const gchar  *mime_type)
101 {
102         GdkPixbuf *pixbuf = NULL;
103         gchar     *icon;
104
105         icon = gnome_icon_lookup (icon_theme,
106                                   NULL, NULL,
107                                   NULL, NULL,
108                                   mime_type,
109                                   GNOME_ICON_LOOKUP_FLAGS_NONE,
110                                   NULL);
111
112         pixbuf = gtk_icon_theme_load_icon (icon_theme,
113                                            icon, 48, 0, NULL);
114         g_free (icon);
115
116         return pixbuf;
117 }
118
119 static GdkPixbuf *
120 ev_sidebar_attachments_icon_cache_get (EvSidebarAttachments *ev_attachbar,
121                                        const gchar          *mime_type)
122 {
123         GdkPixbuf *pixbuf = NULL;
124         
125         g_assert (mime_type != NULL);
126
127         pixbuf = g_hash_table_lookup (ev_attachbar->priv->icon_cache,
128                                       mime_type);
129
130         if (GDK_IS_PIXBUF (pixbuf))
131                 return pixbuf;
132
133         pixbuf = icon_theme_get_pixbuf_from_mime_type (ev_attachbar->priv->icon_theme,
134                                                        mime_type);
135
136         if (GDK_IS_PIXBUF (pixbuf))
137                 ev_sidebar_attachments_icon_cache_add (ev_attachbar,
138                                                        mime_type,
139                                                        pixbuf);
140
141         return pixbuf;
142 }
143
144 static gboolean
145 icon_cache_update_icon (gchar                *key,
146                         GdkPixbuf            *value,
147                         EvSidebarAttachments *ev_attachbar)
148 {
149         GdkPixbuf *pixbuf = NULL;
150
151         pixbuf = icon_theme_get_pixbuf_from_mime_type (ev_attachbar->priv->icon_theme,
152                                                        key);
153
154         ev_sidebar_attachments_icon_cache_add (ev_attachbar,
155                                                key,
156                                                pixbuf);
157         
158         return FALSE;
159 }
160
161 static void
162 ev_sidebar_attachments_icon_cache_refresh (EvSidebarAttachments *ev_attachbar)
163 {
164         g_hash_table_foreach_remove (ev_attachbar->priv->icon_cache,
165                                      (GHRFunc) icon_cache_update_icon,
166                                      ev_attachbar);
167 }
168
169 static EvAttachment *
170 ev_sidebar_attachments_get_attachment_at_pos (EvSidebarAttachments *ev_attachbar,
171                                               gint                  x,
172                                               gint                  y)
173 {
174         GtkTreePath  *path = NULL;
175         GtkTreeIter   iter;
176         EvAttachment *attachment = NULL;
177
178         path = gtk_icon_view_get_path_at_pos (GTK_ICON_VIEW (ev_attachbar->priv->icon_view),
179                                               x, y);
180         if (!path) {
181                 return NULL;
182         }
183
184         gtk_tree_model_get_iter (GTK_TREE_MODEL (ev_attachbar->priv->model),
185                                  &iter, path);
186         gtk_tree_model_get (GTK_TREE_MODEL (ev_attachbar->priv->model), &iter,
187                             COLUMN_ATTACHMENT, &attachment,
188                             -1);
189
190         gtk_icon_view_select_path (GTK_ICON_VIEW (ev_attachbar->priv->icon_view),
191                                    path);
192         
193         gtk_tree_path_free (path);
194
195         return attachment;
196 }
197
198 static gboolean
199 ev_sidebar_attachments_popup_menu_show (EvSidebarAttachments *ev_attachbar,
200                                         gint                  x,
201                                         gint                  y)
202 {
203         GtkIconView *icon_view;
204         GtkTreePath *path;
205         GList       *selected = NULL, *l;
206         GList       *attach_list = NULL;
207
208         icon_view = GTK_ICON_VIEW (ev_attachbar->priv->icon_view);
209         
210         path = gtk_icon_view_get_path_at_pos (icon_view, x, y);
211         if (!path)
212                 return FALSE;
213
214         if (!gtk_icon_view_path_is_selected (icon_view, path)) {
215                 gtk_icon_view_unselect_all (icon_view);
216                 gtk_icon_view_select_path (icon_view, path);
217         }
218
219         gtk_tree_path_free (path);
220         
221         selected = gtk_icon_view_get_selected_items (icon_view);
222         if (!selected)
223                 return FALSE;
224
225         for (l = selected; l && l->data; l = g_list_next (l)) {
226                 GtkTreeIter   iter;
227                 EvAttachment *attachment = NULL;
228
229                 path = (GtkTreePath *) l->data;
230
231                 gtk_tree_model_get_iter (GTK_TREE_MODEL (ev_attachbar->priv->model),
232                                          &iter, path);
233                 gtk_tree_model_get (GTK_TREE_MODEL (ev_attachbar->priv->model), &iter,
234                                     COLUMN_ATTACHMENT, &attachment,
235                                     -1);
236
237                 if (attachment)
238                         attach_list = g_list_prepend (attach_list, attachment);
239
240                 gtk_tree_path_free (path);
241         }
242
243         g_list_free (selected);
244
245         if (!attach_list)
246                 return FALSE;
247
248         g_signal_emit (ev_attachbar, signals[SIGNAL_POPUP_MENU], 0, attach_list);
249
250         return TRUE;
251 }
252
253 static gboolean
254 ev_sidebar_attachments_popup_menu (GtkWidget *widget)
255 {
256         EvSidebarAttachments *ev_attachbar = EV_SIDEBAR_ATTACHMENTS (widget);
257         gint                  x, y;
258
259         gtk_widget_get_pointer (widget, &x, &y);
260
261         return ev_sidebar_attachments_popup_menu_show (ev_attachbar, x, y);
262 }
263
264 static gboolean
265 ev_sidebar_attachments_button_press (EvSidebarAttachments *ev_attachbar,
266                                      GdkEventButton       *event,
267                                      GtkWidget            *icon_view)
268 {
269         if (!GTK_WIDGET_HAS_FOCUS (icon_view)) {
270                 gtk_widget_grab_focus (icon_view);
271         }
272         
273         if (event->button == 2)
274                 return FALSE;
275
276         switch (event->button) {
277                 case 1:
278                         if (event->type == GDK_2BUTTON_PRESS) {
279                                 GError *error = NULL;
280                                 EvAttachment *attachment;
281                                 
282                                 attachment = ev_sidebar_attachments_get_attachment_at_pos (ev_attachbar,
283                                                                                            event->x,
284                                                                                            event->y);
285                                 if (!attachment)
286                                         return FALSE;
287                                 
288                                 ev_attachment_open (attachment, &error);
289                                 
290                                 if (error) {
291                                         g_warning (error->message);
292                                         g_error_free (error);
293                                 }
294                                 
295                                 g_object_unref (attachment);
296                                 
297                                 return TRUE;
298                         }
299                         break;
300                 case 3: 
301                         return ev_sidebar_attachments_popup_menu_show (ev_attachbar, event->x, event->y);
302         }
303
304         return FALSE;
305 }
306
307 static void
308 ev_sidebar_attachments_update_icons (EvSidebarAttachments *ev_attachbar,
309                                      gpointer              user_data)
310 {
311         GtkTreeIter iter;
312         gboolean    valid;
313
314         ev_sidebar_attachments_icon_cache_refresh (ev_attachbar);
315         
316         valid = gtk_tree_model_get_iter_first (
317                 GTK_TREE_MODEL (ev_attachbar->priv->model),
318                 &iter);
319
320         while (valid) {
321                 EvAttachment *attachment = NULL;
322                 GdkPixbuf    *pixbuf = NULL;
323                 const gchar  *mime_type;
324
325                 gtk_tree_model_get (GTK_TREE_MODEL (ev_attachbar->priv->model), &iter,
326                                     COLUMN_ATTACHMENT, &attachment,
327                                     -1);
328
329                 mime_type = ev_attachment_get_mime_type (attachment);
330
331                 if (attachment)
332                         g_object_unref (attachment);
333
334                 pixbuf = ev_sidebar_attachments_icon_cache_get (ev_attachbar,
335                                                                 mime_type);
336
337                 gtk_list_store_set (ev_attachbar->priv->model, &iter,
338                                     COLUMN_ICON, pixbuf,
339                                     -1);
340
341                 valid = gtk_tree_model_iter_next (
342                         GTK_TREE_MODEL (ev_attachbar->priv->model),
343                         &iter);
344         }
345 }
346
347 static void
348 ev_sidebar_attachments_screen_changed (GtkWidget *widget,
349                                        GdkScreen *old_screen)
350 {
351         EvSidebarAttachments *ev_attachbar = EV_SIDEBAR_ATTACHMENTS (widget);
352         GdkScreen            *screen;
353
354         if (!ev_attachbar->priv->icon_theme)
355                 return;
356         
357         screen = gtk_widget_get_screen (widget);
358         if (screen == old_screen)
359                 return;
360
361         if (old_screen) {
362                 g_signal_handlers_disconnect_by_func (
363                         gtk_icon_theme_get_for_screen (old_screen),
364                         G_CALLBACK (ev_sidebar_attachments_update_icons),
365                         ev_attachbar);
366         }
367
368         ev_attachbar->priv->icon_theme = gtk_icon_theme_get_for_screen (screen);
369         g_signal_connect_swapped (ev_attachbar->priv->icon_theme,
370                                   "changed",
371                                   G_CALLBACK (ev_sidebar_attachments_update_icons),
372                                   (gpointer) ev_attachbar);
373
374         if (GTK_WIDGET_CLASS (ev_sidebar_attachments_parent_class)->screen_changed) {
375                 GTK_WIDGET_CLASS (ev_sidebar_attachments_parent_class)->screen_changed (widget, old_screen);
376         }
377 }
378
379 static void
380 ev_sidebar_attachments_drag_data_get (GtkWidget        *widget,
381                                       GdkDragContext   *drag_context,
382                                       GtkSelectionData *data,
383                                       guint             info,
384                                       guint             time,
385                                       gpointer          user_data)
386 {
387         EvSidebarAttachments *ev_attachbar = EV_SIDEBAR_ATTACHMENTS (user_data);
388         GString              *uri_list;
389         gchar                *uris = NULL;
390         GList                *selected = NULL, *l;
391
392         selected = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (ev_attachbar->priv->icon_view));
393         if (!selected)
394                 return;
395
396         uri_list = g_string_new (NULL);
397         
398         for (l = selected; l && l->data; l = g_list_next (l)) {
399                 EvAttachment *attachment;
400                 GtkTreePath  *path;
401                 GtkTreeIter   iter;
402                 gchar        *uri, *filename;
403                 GError       *error = NULL;
404                 
405                 path = (GtkTreePath *) l->data;
406
407                 gtk_tree_model_get_iter (GTK_TREE_MODEL (ev_attachbar->priv->model),
408                                          &iter, path);
409                 gtk_tree_model_get (GTK_TREE_MODEL (ev_attachbar->priv->model), &iter,
410                                     COLUMN_ATTACHMENT, &attachment,
411                                     -1);
412
413                 filename = g_build_filename (ev_tmp_dir (),
414                                              ev_attachment_get_name (attachment),
415                                              NULL);
416                 
417                 uri = g_filename_to_uri (filename, NULL, NULL);
418
419                 if (ev_attachment_save (attachment, filename, &error)) {
420                         g_string_append (uri_list, uri);
421                         g_string_append_c (uri_list, '\n');
422                 }
423         
424                 if (error) {
425                         g_warning (error->message);
426                         g_error_free (error);
427                 }
428
429                 g_free (uri);
430                 gtk_tree_path_free (path);
431                 g_object_unref (attachment);
432         }
433
434         uris = g_string_free (uri_list, FALSE);
435
436         if (uris) {
437                 gtk_selection_data_set (data,
438                                         data->target,
439                                         8,
440                                         (guchar *)uris,
441                                         strlen (uris));
442         }
443
444         g_list_free (selected);
445 }
446
447 static void
448 ev_sidebar_attachments_get_property (GObject    *object,
449                                      guint       prop_id,
450                                      GValue     *value,
451                                      GParamSpec *pspec)
452 {
453         EvSidebarAttachments *ev_sidebar_attachments;
454   
455         ev_sidebar_attachments = EV_SIDEBAR_ATTACHMENTS (object);
456
457         switch (prop_id) {
458                 case PROP_WIDGET:
459                         g_value_set_object (value, ev_sidebar_attachments->priv->icon_view);
460                         break;
461                 default:
462                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
463                         break;
464         }
465 }
466
467 static void
468 ev_sidebar_attachments_destroy (GtkObject *object)
469 {
470         EvSidebarAttachments *ev_attachbar = EV_SIDEBAR_ATTACHMENTS (object);
471
472         if (ev_attachbar->priv->icon_theme) {
473                 g_signal_handlers_disconnect_by_func (
474                         ev_attachbar->priv->icon_theme, 
475                         G_CALLBACK (ev_sidebar_attachments_update_icons),
476                         ev_attachbar);
477                 ev_attachbar->priv->icon_theme = NULL;
478         }
479         
480         if (ev_attachbar->priv->model) {
481                 g_object_unref (ev_attachbar->priv->model);
482                 ev_attachbar->priv->model = NULL;
483         }
484
485         if (ev_attachbar->priv->icon_cache) {
486                 g_hash_table_destroy (ev_attachbar->priv->icon_cache);
487                 ev_attachbar->priv->icon_cache = NULL;
488         }
489
490         (* GTK_OBJECT_CLASS (ev_sidebar_attachments_parent_class)->destroy) (object);
491 }
492
493 static void
494 ev_sidebar_attachments_class_init (EvSidebarAttachmentsClass *ev_attachbar_class)
495 {
496         GObjectClass   *g_object_class;
497         GtkObjectClass *gtk_object_class;
498         GtkWidgetClass *gtk_widget_class;
499
500         g_object_class = G_OBJECT_CLASS (ev_attachbar_class);
501         gtk_object_class = GTK_OBJECT_CLASS (ev_attachbar_class);
502         gtk_widget_class = GTK_WIDGET_CLASS (ev_attachbar_class);
503
504         g_object_class->get_property = ev_sidebar_attachments_get_property;
505         gtk_object_class->destroy = ev_sidebar_attachments_destroy;
506         gtk_widget_class->popup_menu = ev_sidebar_attachments_popup_menu;
507         gtk_widget_class->screen_changed = ev_sidebar_attachments_screen_changed;
508
509         g_type_class_add_private (g_object_class, sizeof (EvSidebarAttachmentsPrivate));
510
511         /* Signals */
512         signals[SIGNAL_POPUP_MENU] =
513                 g_signal_new ("popup",
514                               G_TYPE_FROM_CLASS (g_object_class),
515                               G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
516                               G_STRUCT_OFFSET (EvSidebarAttachmentsClass, popup_menu),
517                               NULL, NULL,
518                               g_cclosure_marshal_VOID__POINTER,
519                               G_TYPE_NONE, 1,
520                               G_TYPE_POINTER);
521
522         g_object_class_override_property (g_object_class,
523                                           PROP_WIDGET,
524                                           "main-widget");
525 }
526
527 static void
528 ev_sidebar_attachments_init (EvSidebarAttachments *ev_attachbar)
529 {
530         GtkWidget *swindow;
531         
532         ev_attachbar->priv = EV_SIDEBAR_ATTACHMENTS_GET_PRIVATE (ev_attachbar);
533
534         swindow = gtk_scrolled_window_new (NULL, NULL);
535         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
536                                         GTK_POLICY_NEVER,
537                                         GTK_POLICY_AUTOMATIC);
538         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow),
539                                              GTK_SHADOW_IN);
540         /* Data Model */
541         ev_attachbar->priv->model = gtk_list_store_new (N_COLS,
542                                                         GDK_TYPE_PIXBUF, 
543                                                         G_TYPE_STRING,  
544                                                         G_TYPE_STRING,
545                                                         EV_TYPE_ATTACHMENT);
546
547         /* Icon View */
548         ev_attachbar->priv->icon_view =
549                 gtk_icon_view_new_with_model (GTK_TREE_MODEL (ev_attachbar->priv->model));
550         gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (ev_attachbar->priv->icon_view),
551                                           GTK_SELECTION_MULTIPLE);
552         gtk_icon_view_set_columns (GTK_ICON_VIEW (ev_attachbar->priv->icon_view), -1);
553         g_object_set (G_OBJECT (ev_attachbar->priv->icon_view),
554                       "text-column", COLUMN_NAME,
555                       "pixbuf-column", COLUMN_ICON,
556                       NULL);
557         g_signal_connect_swapped (G_OBJECT (ev_attachbar->priv->icon_view),
558                                   "button-press-event",
559                                   G_CALLBACK (ev_sidebar_attachments_button_press),
560                                   (gpointer) ev_attachbar);
561
562         gtk_container_add (GTK_CONTAINER (swindow),
563                            ev_attachbar->priv->icon_view);
564
565         gtk_container_add (GTK_CONTAINER (ev_attachbar),
566                            swindow);
567         gtk_widget_show_all (GTK_WIDGET (ev_attachbar));
568
569         /* Icon Theme */
570         ev_attachbar->priv->icon_theme = NULL;
571
572         /* Icon Cache */
573         ev_attachbar->priv->icon_cache = g_hash_table_new_full (g_str_hash,
574                                                                 g_str_equal,
575                                                                 g_free,
576                                                                 g_object_unref);
577
578         /* Drag and Drop */
579         gtk_icon_view_enable_model_drag_source (
580                 GTK_ICON_VIEW (ev_attachbar->priv->icon_view),
581                 GDK_BUTTON1_MASK,
582                 drag_targets,
583                 G_N_ELEMENTS (drag_targets),
584                 GDK_ACTION_COPY);
585
586         g_signal_connect (G_OBJECT (ev_attachbar->priv->icon_view),
587                           "drag-data-get",
588                           G_CALLBACK (ev_sidebar_attachments_drag_data_get),
589                           (gpointer) ev_attachbar);     
590 }
591
592 GtkWidget *
593 ev_sidebar_attachments_new (void)
594 {
595         GtkWidget *ev_attachbar;
596
597         ev_attachbar = g_object_new (EV_TYPE_SIDEBAR_ATTACHMENTS, NULL);
598
599         return ev_attachbar;
600 }
601
602 static void
603 ev_sidebar_attachments_set_document (EvSidebarPage   *page,
604                                      EvDocument      *document)
605 {
606         EvSidebarAttachments *ev_attachbar = EV_SIDEBAR_ATTACHMENTS (page);
607         GList *attachments = NULL;
608         GList *l;
609         
610         if (!ev_document_has_attachments (document))
611                 return;
612
613         if (!ev_attachbar->priv->icon_theme) {
614                 GdkScreen *screen;
615
616                 screen = gtk_widget_get_screen (GTK_WIDGET (ev_attachbar));
617                 ev_attachbar->priv->icon_theme = gtk_icon_theme_get_for_screen (screen);
618                 g_signal_connect_swapped (G_OBJECT (ev_attachbar->priv->icon_theme),
619                                           "changed",
620                                           G_CALLBACK (ev_sidebar_attachments_update_icons),
621                                           (gpointer) ev_attachbar);
622         }
623                 
624         attachments = ev_document_get_attachments (document);
625
626         gtk_list_store_clear (ev_attachbar->priv->model);
627                                            
628         for (l = attachments; l && l->data; l = g_list_next (l)) {
629                 EvAttachment *attachment;
630                 GtkTreeIter   iter;
631                 GdkPixbuf    *pixbuf = NULL;
632                 const gchar  *mime_type;
633
634                 attachment = EV_ATTACHMENT (l->data);
635
636                 mime_type = ev_attachment_get_mime_type (attachment);
637                 pixbuf = ev_sidebar_attachments_icon_cache_get (ev_attachbar,
638                                                                 mime_type);
639
640                 gtk_list_store_append (ev_attachbar->priv->model, &iter);
641                 gtk_list_store_set (ev_attachbar->priv->model, &iter,
642                                     COLUMN_NAME, ev_attachment_get_name (attachment),
643                                     COLUMN_ICON, pixbuf,
644                                     COLUMN_ATTACHMENT, attachment, 
645                                     -1);
646
647                 g_object_unref (attachment);
648         }
649
650         g_list_free (attachments);
651 }
652
653 static gboolean
654 ev_sidebar_attachments_support_document (EvSidebarPage   *sidebar_page,
655                                          EvDocument      *document)
656 {
657         return ev_document_has_attachments (document);
658 }
659
660 static const gchar*
661 ev_sidebar_attachments_get_label (EvSidebarPage *sidebar_page)
662 {
663         return _("Attachments");
664 }
665
666 static void
667 ev_sidebar_attachments_page_iface_init (EvSidebarPageIface *iface)
668 {
669         iface->support_document = ev_sidebar_attachments_support_document;
670         iface->set_document = ev_sidebar_attachments_set_document;
671         iface->get_label = ev_sidebar_attachments_get_label;
672 }
673