2004-09-20 [colin] 0.9.12cvs102.2
[claws.git] / src / plugins / image_viewer / viewer.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2003 Hiroyuki Yamamoto
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <glib.h>
25 #include <gtk/gtkscrolledwindow.h>
26 #include <gtk/gtkpixmap.h>
27
28 #if HAVE_GDK_PIXBUF
29 #  include <gdk-pixbuf/gdk-pixbuf.h>
30 #else
31 #if HAVE_GDK_IMLIB
32 #  include <gdk_imlib.h>
33 #endif
34 #endif /* HAVE_GDK_PIXBUF */
35
36 #include "intl.h"
37 #include "procmime.h"
38 #include "utils.h"
39 #include "mimeview.h"
40
41 #include "viewerprefs.h"
42
43 typedef struct _ImageViewer ImageViewer;
44
45 MimeViewerFactory image_viewer_factory;
46 static void image_viewer_get_resized_size(gint w, gint h, gint aw, gint ah,
47                                           gint * sw, gint * sh);
48 static void image_viewer_clear_viewer(MimeViewer *imageviewer);
49
50 struct _ImageViewer
51 {
52         MimeViewer mimeviewer;
53
54         gchar     *file;
55         MimeInfo  *mimeinfo;
56         gboolean   resize_img;
57
58         GtkWidget *scrolledwin;
59         GtkWidget *image;
60         GtkWidget *notebook;
61         GtkWidget *filename;
62         GtkWidget *filesize;
63         GtkWidget *content_type;
64 };
65
66 static GtkWidget *image_viewer_get_widget(MimeViewer *_mimeviewer)
67 {
68         ImageViewer *imageviewer = (ImageViewer *) _mimeviewer;
69
70         debug_print("image_viewer_get_widget\n");
71
72         return imageviewer->notebook;
73 }
74
75 #if HAVE_GDK_PIXBUF
76 static void image_viewer_load_file(ImageViewer *imageviewer, const gchar *imgfile)
77 {
78         GdkPixbuf *pixbuf;
79         GdkPixbuf *pixbuf_scaled;
80         GdkPixmap *pixmap;
81         GdkBitmap *mask;
82         gint avail_width;
83         gint avail_height;
84         gint new_width;
85         gint new_height;
86         GError *error = NULL;
87
88         debug_print("image_viewer_show_mimepart\n");
89
90         pixbuf = gdk_pixbuf_new_from_file(imgfile, &error);
91         if (error) {
92                 g_warning(error->message);
93                 g_error_free(error);
94         }
95         if (!pixbuf) {
96                 g_warning("Can't load the image.");     
97                 return;
98         }
99
100         if (imageviewer->resize_img) {
101                 avail_width = imageviewer->notebook->parent->allocation.width;
102                 avail_height = imageviewer->notebook->parent->allocation.height;
103                 if (avail_width > 8) avail_width -= 8;
104                 if (avail_height > 8) avail_height -= 8;
105
106                 image_viewer_get_resized_size(gdk_pixbuf_get_width(pixbuf),
107                                  gdk_pixbuf_get_height(pixbuf),
108                                  avail_width, avail_height,
109                                  &new_width, &new_height);
110
111                 pixbuf_scaled = gdk_pixbuf_scale_simple
112                         (pixbuf, new_width, new_height, GDK_INTERP_BILINEAR);
113                 g_object_unref(pixbuf);
114                 pixbuf = pixbuf_scaled;
115         }
116
117         gdk_pixbuf_render_pixmap_and_mask(pixbuf, &pixmap, &mask, 0);
118
119         if (!imageviewer->image) {
120                 imageviewer->image = gtk_pixmap_new(pixmap, mask);
121
122                 gtk_scrolled_window_add_with_viewport
123                         (GTK_SCROLLED_WINDOW(imageviewer->scrolledwin),
124                          imageviewer->image);
125         } else
126                 gtk_pixmap_set(imageviewer->image, pixmap, mask);
127
128         gtk_widget_show(imageviewer->image);
129
130         g_object_unref(pixbuf);
131 }
132 #endif /* HAVE_GDK_PIXBUF */
133
134 static void image_viewer_set_notebook_page(MimeViewer *_mimeviewer)
135 {
136         ImageViewer *imageviewer = (ImageViewer *) _mimeviewer;
137
138         if (!imageviewerprefs.display_img)
139                 gtk_notebook_set_page(GTK_NOTEBOOK(imageviewer->notebook), 0);
140         else
141                 gtk_notebook_set_page(GTK_NOTEBOOK(imageviewer->notebook), 1);
142 }
143
144 static void image_viewer_load_image(ImageViewer *imageviewer)
145 {
146         gchar *imgfile;
147
148         if (imageviewer->mimeinfo == NULL)
149                 return;
150
151         imgfile = procmime_get_tmp_file_name(imageviewer->mimeinfo);
152         if (procmime_get_part(imgfile, imageviewer->mimeinfo) < 0) {
153                 g_warning("Can't get mimepart file");   
154                 g_free(imgfile);
155                 return;
156         }
157         image_viewer_load_file(imageviewer, imgfile);
158         unlink(imgfile);
159         g_free(imgfile);
160 }
161
162 static void image_viewer_show_mimepart(MimeViewer *_mimeviewer, const gchar *file, MimeInfo *mimeinfo)
163 {
164         ImageViewer *imageviewer = (ImageViewer *) _mimeviewer;
165
166         image_viewer_clear_viewer(_mimeviewer);
167         g_free(imageviewer->file);
168         imageviewer->file = g_strdup(file);
169         imageviewer->mimeinfo = mimeinfo;
170
171         if (imageviewerprefs.display_img)
172                 image_viewer_load_image(imageviewer);
173         else {
174                 gtk_label_set_text(GTK_LABEL(imageviewer->filename),
175                                    procmime_mimeinfo_get_parameter(mimeinfo, "name"));
176                 gtk_label_set_text(GTK_LABEL(imageviewer->filesize), to_human_readable(mimeinfo->length));
177                 gtk_label_set_text(GTK_LABEL(imageviewer->content_type), mimeinfo->subtype);
178         }
179 }
180
181 static void image_viewer_clear_viewer(MimeViewer *_mimeviewer)
182 {
183         ImageViewer *imageviewer = (ImageViewer *) _mimeviewer;
184         GtkAdjustment *hadj, *vadj;
185
186         debug_print("image_viewer_clear_viewer\n");
187
188         image_viewer_set_notebook_page(_mimeviewer);
189
190         if (imageviewer->image != NULL)
191                 gtk_pixmap_set(GTK_PIXMAP(imageviewer->image), NULL, NULL);
192         hadj = gtk_scrolled_window_get_hadjustment
193                 (GTK_SCROLLED_WINDOW(imageviewer->scrolledwin));
194         gtk_adjustment_set_value(hadj, 0.0);
195         vadj = gtk_scrolled_window_get_vadjustment
196                 (GTK_SCROLLED_WINDOW(imageviewer->scrolledwin));
197         gtk_adjustment_set_value(vadj, 0.0);
198
199         g_free(imageviewer->file);
200         imageviewer->file = NULL;
201         imageviewer->mimeinfo = NULL;
202         imageviewer->resize_img = imageviewerprefs.resize_img;
203 }
204
205 static void image_viewer_destroy_viewer(MimeViewer *_mimeviewer)
206 {
207         ImageViewer *imageviewer = (ImageViewer *) _mimeviewer;
208
209         debug_print("image_viewer_destroy_viewer\n");
210
211         image_viewer_clear_viewer(_mimeviewer);
212         g_object_unref(imageviewer->notebook);
213         g_free(imageviewer);
214 }
215
216 static void image_viewer_get_resized_size(gint w, gint h, gint aw, gint ah,
217                              gint *sw, gint *sh)
218 {
219         gfloat wratio = 1.0;
220         gfloat hratio = 1.0;
221         gfloat ratio  = 1.0;
222
223         if (w > aw)
224                 wratio = (gfloat)aw / (gfloat)w;
225         if (h > ah)
226                 hratio = (gfloat)ah / (gfloat)h;
227
228         ratio = (wratio > hratio) ? hratio : wratio;
229
230         *sw = (gint)(w * ratio);
231         *sh = (gint)(h * ratio);
232
233         /* be paranoid */
234         if (*sw <= 0 || *sh <= 0) {
235                 *sw = w;
236                 *sh = h;
237         }
238 }
239
240 static void load_cb(GtkButton *button, ImageViewer *imageviewer)
241 {
242         gtk_notebook_set_page(GTK_NOTEBOOK(imageviewer->notebook), 1);
243         image_viewer_load_image(imageviewer);
244 }
245
246 static gboolean scrolledwin_button_cb(GtkWidget *scrolledwin, GdkEventButton *event,
247                                       ImageViewer *imageviewer)
248 {
249         if (event->button == 1 && imageviewer->image) {
250                 imageviewer->resize_img = !imageviewer->resize_img;
251                 image_viewer_load_image(imageviewer);
252                 return TRUE;
253         }
254         return FALSE;
255 }
256
257 static void scrolledwin_resize_cb(GtkWidget *scrolledwin, GtkAllocation *alloc,
258                                   ImageViewer *imageviewer)
259 {
260         if (imageviewer->resize_img)
261                 image_viewer_load_image(imageviewer);
262 }
263
264 MimeViewer *image_viewer_create(void)
265 {
266         ImageViewer *imageviewer;
267         /*
268          *  glade generated code (do not touch)
269          */
270         GtkWidget *notebook;
271         GtkWidget *table1;
272         GtkWidget *label3;
273         GtkWidget *label4;
274         GtkWidget *filename;
275         GtkWidget *filesize;
276         GtkWidget *load_button;
277         GtkWidget *label5;
278         GtkWidget *content_type;
279         GtkWidget *scrolledwin;
280
281         notebook = gtk_notebook_new();
282         gtk_widget_show(notebook);
283         GTK_WIDGET_UNSET_FLAGS(notebook, GTK_CAN_FOCUS);
284         gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
285         gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
286
287         table1 = gtk_table_new(4, 3, FALSE);
288         gtk_widget_show(table1);
289         gtk_container_add(GTK_CONTAINER(notebook), table1);
290         gtk_container_set_border_width(GTK_CONTAINER(table1), 8);
291         gtk_table_set_row_spacings(GTK_TABLE(table1), 4);
292         gtk_table_set_col_spacings(GTK_TABLE(table1), 4);
293
294         label3 = gtk_label_new(_("Filename:"));
295         gtk_widget_show(label3);
296         gtk_table_attach(GTK_TABLE(table1), label3, 0, 1, 0, 1,
297                          (GtkAttachOptions) (GTK_FILL),
298                          (GtkAttachOptions) (0), 0, 0);
299         gtk_misc_set_alignment(GTK_MISC(label3), 0, 0.5);
300
301         label4 = gtk_label_new(_("Filesize:"));
302         gtk_widget_show(label4);
303         gtk_table_attach(GTK_TABLE(table1), label4, 0, 1, 1, 2,
304                          (GtkAttachOptions) (GTK_FILL),
305                          (GtkAttachOptions) (0), 0, 0);
306         gtk_misc_set_alignment(GTK_MISC(label4), 0, 0.5);
307
308         filename = gtk_label_new("");
309         gtk_widget_show(filename);
310         gtk_table_attach(GTK_TABLE(table1), filename, 1, 3, 0, 1,
311                          (GtkAttachOptions) (GTK_FILL),
312                          (GtkAttachOptions) (0), 0, 0);
313         gtk_misc_set_alignment(GTK_MISC(filename), 0, 0.5);
314
315         filesize = gtk_label_new("");
316         gtk_widget_show(filesize);
317         gtk_table_attach(GTK_TABLE(table1), filesize, 1, 3, 1, 2,
318                          (GtkAttachOptions) (GTK_FILL),
319                          (GtkAttachOptions) (0), 0, 0);
320         gtk_misc_set_alignment(GTK_MISC(filesize), 0, 0.5);
321
322         load_button = gtk_button_new_with_label(_("Load Image"));
323         gtk_widget_show(load_button);
324         gtk_table_attach(GTK_TABLE(table1), load_button, 1, 2, 3, 4,
325                          (GtkAttachOptions) (GTK_FILL),
326                          (GtkAttachOptions) (0), 0, 0);
327
328         label5 = gtk_label_new(_("Content-Type:"));
329         gtk_widget_show(label5);
330         gtk_table_attach(GTK_TABLE(table1), label5, 0, 1, 2, 3,
331                          (GtkAttachOptions) (GTK_FILL),
332                          (GtkAttachOptions) (0), 0, 0);
333         gtk_misc_set_alignment(GTK_MISC(label5), 0, 0.5);
334
335         content_type = gtk_label_new("");
336         gtk_widget_show(content_type);
337         gtk_table_attach(GTK_TABLE(table1), content_type, 1, 3, 2, 3,
338                          (GtkAttachOptions) (GTK_FILL),
339                          (GtkAttachOptions) (0), 0, 0);
340         gtk_misc_set_alignment(GTK_MISC(content_type), 0, 0.5);
341
342         scrolledwin = gtk_scrolled_window_new(NULL, NULL);
343         gtk_widget_show(scrolledwin);
344         gtk_container_add(GTK_CONTAINER(notebook), scrolledwin);
345         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
346                                        GTK_POLICY_AUTOMATIC,
347                                        GTK_POLICY_AUTOMATIC);
348         /*
349          *  end of glade code
350          */
351
352         debug_print("Creating image view...\n");
353         imageviewer = g_new0(ImageViewer, 1);
354         imageviewer->mimeviewer.factory = &image_viewer_factory;
355
356         imageviewer->mimeviewer.get_widget = image_viewer_get_widget;
357         imageviewer->mimeviewer.show_mimepart = image_viewer_show_mimepart;
358         imageviewer->mimeviewer.clear_viewer = image_viewer_clear_viewer;
359         imageviewer->mimeviewer.destroy_viewer = image_viewer_destroy_viewer;
360
361         imageviewer->resize_img   = imageviewerprefs.resize_img;
362
363         imageviewer->scrolledwin  = scrolledwin;
364         imageviewer->image        = NULL;
365         imageviewer->notebook     = notebook;
366         imageviewer->filename     = filename;
367         imageviewer->filesize     = filesize;
368         imageviewer->content_type = content_type;
369
370         gtk_widget_ref(notebook);
371
372         g_signal_connect(G_OBJECT(load_button), "released",
373                          G_CALLBACK(load_cb), imageviewer);
374         g_signal_connect(G_OBJECT(scrolledwin), "button-press-event",
375                          G_CALLBACK(scrolledwin_button_cb), imageviewer);
376         g_signal_connect(G_OBJECT(scrolledwin), "size-allocate",
377                          G_CALLBACK(scrolledwin_resize_cb), imageviewer);
378
379         image_viewer_set_notebook_page((MimeViewer *)imageviewer);
380
381         return (MimeViewer *) imageviewer;
382 }
383
384 static gchar *content_types[] =
385         {"image/*", NULL};
386
387 MimeViewerFactory image_viewer_factory =
388 {
389         content_types,
390         0,
391         
392         image_viewer_create,
393 };
394
395 void image_viewer_init(void)
396 {
397 #if HAVE_GDK_IMLIB
398         gdk_imlib_init();
399         gtk_widget_push_visual(gdk_imlib_get_visual());
400         gtk_widget_push_colormap(gdk_imlib_get_colormap());
401 #endif
402
403         mimeview_register_viewer_factory(&image_viewer_factory);
404 }
405
406 void image_viewer_done(void)
407 {
408         mimeview_unregister_viewer_factory(&image_viewer_factory);
409 }