sync 098claws
[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                 gdk_pixbuf_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(GTK_PIXMAP(imageviewer->image), pixmap, mask);
127
128         gtk_widget_show(imageviewer->image);
129
130         gdk_pixbuf_unref(pixbuf);
131 }
132 #else
133 #if HAVE_GDK_IMLIB
134 static void image_viewer_load_file(ImageViewer *imageviewer, const gchar *imgfile)
135 {
136         GdkImlibImage *im;
137         gint avail_width;
138         gint avail_height;
139         gint new_width;
140         gint new_height;
141
142         debug_print("image_viewer_show_mimepart\n");
143
144         im = gdk_imlib_load_image(imgfile);
145         if (!im) {
146                 g_warning("Can't load the image.");     
147                 return;
148         }
149
150         if (imageviewer->resize_img) {
151                 avail_width = imageviewer->notebook->parent->allocation.width;
152                 avail_height = imageviewer->notebook->parent->allocation.height;
153                 if (avail_width > 8) avail_width -= 8;
154                 if (avail_height > 8) avail_height -= 8;
155
156                 image_viewer_get_resized_size(im->rgb_width, im->rgb_height,
157                                  avail_width, avail_height,
158                                  &new_width, &new_height);
159         } else {
160                 new_width = im->rgb_width;
161                 new_height = im->rgb_height;
162         }
163
164         gdk_imlib_render(im, new_width, new_height);
165
166         if (!imageviewer->image) {
167                 imageviewer->image = gtk_pixmap_new(gdk_imlib_move_image(im),
168                                                     gdk_imlib_move_mask(im));
169
170                 gtk_scrolled_window_add_with_viewport
171                         (GTK_SCROLLED_WINDOW(imageviewer->scrolledwin),
172                          imageviewer->image);
173         } else
174                 gtk_pixmap_set(GTK_PIXMAP(imageviewer->image),
175                                gdk_imlib_move_image(im),
176                                gdk_imlib_move_mask(im));      
177
178         gtk_widget_show(imageviewer->image);
179
180         gdk_imlib_destroy_image(im);
181 }
182 #endif /* HAVE_GDK_IMLIB */
183 #endif /* HAVE_GDK_PIXBUF */
184
185 static void image_viewer_set_notebook_page(MimeViewer *_mimeviewer)
186 {
187         ImageViewer *imageviewer = (ImageViewer *) _mimeviewer;
188
189         if (!imageviewerprefs.display_img)
190                 gtk_notebook_set_page(GTK_NOTEBOOK(imageviewer->notebook), 0);
191         else
192                 gtk_notebook_set_page(GTK_NOTEBOOK(imageviewer->notebook), 1);
193 }
194
195 static void image_viewer_load_image(ImageViewer *imageviewer)
196 {
197         gchar *imgfile;
198
199         imgfile = procmime_get_tmp_file_name(imageviewer->mimeinfo);
200         if (procmime_get_part(imgfile, imageviewer->mimeinfo) < 0) {
201                 g_warning("Can't get mimepart file");   
202                 g_free(imgfile);
203                 return;
204         }
205         image_viewer_load_file(imageviewer, imgfile);
206         unlink(imgfile);
207         g_free(imgfile);
208 }
209
210 static void image_viewer_show_mimepart(MimeViewer *_mimeviewer, const gchar *file, MimeInfo *mimeinfo)
211 {
212         ImageViewer *imageviewer = (ImageViewer *) _mimeviewer;
213
214         image_viewer_clear_viewer(_mimeviewer);
215         g_free(imageviewer->file);
216         imageviewer->file = g_strdup(file);
217         imageviewer->mimeinfo = mimeinfo;
218
219         if (imageviewerprefs.display_img)
220                 image_viewer_load_image(imageviewer);
221         else {
222                 gtk_label_set_text(GTK_LABEL(imageviewer->filename),
223                                    procmime_mimeinfo_get_parameter(mimeinfo, "name"));
224                 gtk_label_set_text(GTK_LABEL(imageviewer->filesize), to_human_readable(mimeinfo->length));
225                 gtk_label_set_text(GTK_LABEL(imageviewer->content_type), mimeinfo->subtype);
226         }
227 }
228
229 static void image_viewer_clear_viewer(MimeViewer *_mimeviewer)
230 {
231         ImageViewer *imageviewer = (ImageViewer *) _mimeviewer;
232         GtkAdjustment *hadj, *vadj;
233
234         debug_print("image_viewer_clear_viewer\n");
235
236         image_viewer_set_notebook_page(_mimeviewer);
237
238         if (imageviewer->image != NULL)
239                 gtk_pixmap_set(GTK_PIXMAP(imageviewer->image), NULL, NULL);
240         hadj = gtk_scrolled_window_get_hadjustment
241                 (GTK_SCROLLED_WINDOW(imageviewer->scrolledwin));
242         gtk_adjustment_set_value(hadj, 0.0);
243         vadj = gtk_scrolled_window_get_vadjustment
244                 (GTK_SCROLLED_WINDOW(imageviewer->scrolledwin));
245         gtk_adjustment_set_value(vadj, 0.0);
246
247         g_free(imageviewer->file);
248         imageviewer->file = NULL;
249         imageviewer->mimeinfo = NULL;
250         imageviewer->resize_img   = imageviewerprefs.resize_img;
251 }
252
253 static void image_viewer_destroy_viewer(MimeViewer *_mimeviewer)
254 {
255         ImageViewer *imageviewer = (ImageViewer *) _mimeviewer;
256
257         debug_print("image_viewer_destroy_viewer\n");
258
259         image_viewer_clear_viewer(_mimeviewer);
260         gtk_widget_unref(imageviewer->notebook);
261         g_free(imageviewer);
262 }
263
264 static void image_viewer_get_resized_size(gint w, gint h, gint aw, gint ah,
265                              gint *sw, gint *sh)
266 {
267         gfloat wratio = 1.0;
268         gfloat hratio = 1.0;
269         gfloat ratio  = 1.0;
270
271         if (w > aw)
272                 wratio = (gfloat)aw / (gfloat)w;
273         if (h > ah)
274                 hratio = (gfloat)ah / (gfloat)h;
275
276         ratio = (wratio > hratio) ? hratio : wratio;
277
278         *sw = (gint)(w * ratio);
279         *sh = (gint)(h * ratio);
280
281         /* be paranoid */
282         if (*sw <= 0 || *sh <= 0) {
283                 *sw = w;
284                 *sh = h;
285         }
286 }
287
288 static void load_cb(GtkButton *button, ImageViewer *imageviewer)
289 {
290         gtk_notebook_set_page(GTK_NOTEBOOK(imageviewer->notebook), 1);
291         image_viewer_load_image(imageviewer);
292 }
293
294 static gboolean scrolledwin_button_cb(GtkWidget *scrolledwin, GdkEventButton *event,
295                                       ImageViewer *imageviewer)
296 {
297         if (event->button == 1 && imageviewer->image) {
298                 imageviewer->resize_img = !imageviewer->resize_img;
299                 image_viewer_load_image(imageviewer);
300                 return TRUE;
301         }
302         return FALSE;
303 }
304
305 static void scrolledwin_resize_cb(GtkWidget *scrolledwin, GtkAllocation *alloc,
306                                   ImageViewer *imageviewer)
307 {
308         if (imageviewer->resize_img)
309                 image_viewer_load_image(imageviewer);
310 }
311
312 MimeViewer *image_viewer_create(void)
313 {
314         ImageViewer *imageviewer;
315         /*
316          *  glade generated code (do not touch)
317          */
318         GtkWidget *notebook;
319         GtkWidget *table1;
320         GtkWidget *label3;
321         GtkWidget *label4;
322         GtkWidget *filename;
323         GtkWidget *filesize;
324         GtkWidget *load_button;
325         GtkWidget *label5;
326         GtkWidget *content_type;
327         GtkWidget *scrolledwin;
328
329         notebook = gtk_notebook_new();
330         gtk_widget_show(notebook);
331         GTK_WIDGET_UNSET_FLAGS(notebook, GTK_CAN_FOCUS);
332         gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
333         gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
334
335         table1 = gtk_table_new(4, 3, FALSE);
336         gtk_widget_show(table1);
337         gtk_container_add(GTK_CONTAINER(notebook), table1);
338         gtk_container_set_border_width(GTK_CONTAINER(table1), 8);
339         gtk_table_set_row_spacings(GTK_TABLE(table1), 4);
340         gtk_table_set_col_spacings(GTK_TABLE(table1), 4);
341
342         label3 = gtk_label_new(_("Filename:"));
343         gtk_widget_show(label3);
344         gtk_table_attach(GTK_TABLE(table1), label3, 0, 1, 0, 1,
345                          (GtkAttachOptions) (GTK_FILL),
346                          (GtkAttachOptions) (0), 0, 0);
347         gtk_misc_set_alignment(GTK_MISC(label3), 0, 0.5);
348
349         label4 = gtk_label_new(_("Filesize:"));
350         gtk_widget_show(label4);
351         gtk_table_attach(GTK_TABLE(table1), label4, 0, 1, 1, 2,
352                          (GtkAttachOptions) (GTK_FILL),
353                          (GtkAttachOptions) (0), 0, 0);
354         gtk_misc_set_alignment(GTK_MISC(label4), 0, 0.5);
355
356         filename = gtk_label_new("");
357         gtk_widget_show(filename);
358         gtk_table_attach(GTK_TABLE(table1), filename, 1, 3, 0, 1,
359                          (GtkAttachOptions) (GTK_FILL),
360                          (GtkAttachOptions) (0), 0, 0);
361         gtk_misc_set_alignment(GTK_MISC(filename), 0, 0.5);
362
363         filesize = gtk_label_new("");
364         gtk_widget_show(filesize);
365         gtk_table_attach(GTK_TABLE(table1), filesize, 1, 3, 1, 2,
366                          (GtkAttachOptions) (GTK_FILL),
367                          (GtkAttachOptions) (0), 0, 0);
368         gtk_misc_set_alignment(GTK_MISC(filesize), 0, 0.5);
369
370         load_button = gtk_button_new_with_label(_("Load Image"));
371         gtk_widget_show(load_button);
372         gtk_table_attach(GTK_TABLE(table1), load_button, 1, 2, 3, 4,
373                          (GtkAttachOptions) (GTK_FILL),
374                          (GtkAttachOptions) (0), 0, 0);
375
376         label5 = gtk_label_new(_("Content-Type:"));
377         gtk_widget_show(label5);
378         gtk_table_attach(GTK_TABLE(table1), label5, 0, 1, 2, 3,
379                          (GtkAttachOptions) (GTK_FILL),
380                          (GtkAttachOptions) (0), 0, 0);
381         gtk_misc_set_alignment(GTK_MISC(label5), 0, 0.5);
382
383         content_type = gtk_label_new("");
384         gtk_widget_show(content_type);
385         gtk_table_attach(GTK_TABLE(table1), content_type, 1, 3, 2, 3,
386                          (GtkAttachOptions) (GTK_FILL),
387                          (GtkAttachOptions) (0), 0, 0);
388         gtk_misc_set_alignment(GTK_MISC(content_type), 0, 0.5);
389
390         scrolledwin = gtk_scrolled_window_new(NULL, NULL);
391         gtk_widget_show(scrolledwin);
392         gtk_container_add(GTK_CONTAINER(notebook), scrolledwin);
393         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
394                                        GTK_POLICY_AUTOMATIC,
395                                        GTK_POLICY_AUTOMATIC);
396         /*
397          *  end of glade code
398          */
399
400         debug_print("Creating image view...\n");
401         imageviewer = g_new0(ImageViewer, 1);
402         imageviewer->mimeviewer.factory = &image_viewer_factory;
403
404         imageviewer->mimeviewer.get_widget = image_viewer_get_widget;
405         imageviewer->mimeviewer.show_mimepart = image_viewer_show_mimepart;
406         imageviewer->mimeviewer.clear_viewer = image_viewer_clear_viewer;
407         imageviewer->mimeviewer.destroy_viewer = image_viewer_destroy_viewer;
408
409         imageviewer->resize_img   = imageviewerprefs.resize_img;
410
411         imageviewer->scrolledwin  = scrolledwin;
412         imageviewer->image        = NULL;
413         imageviewer->notebook     = notebook;
414         imageviewer->filename     = filename;
415         imageviewer->filesize     = filesize;
416         imageviewer->content_type = content_type;
417
418         gtk_widget_ref(notebook);
419
420         gtk_signal_connect(GTK_OBJECT(load_button), "released",
421                            GTK_SIGNAL_FUNC(load_cb), imageviewer);
422         gtk_signal_connect(GTK_OBJECT(scrolledwin), "button-press-event",
423                            GTK_SIGNAL_FUNC(scrolledwin_button_cb), imageviewer);
424         gtk_signal_connect(GTK_OBJECT(scrolledwin), "size-allocate",
425                            GTK_SIGNAL_FUNC(scrolledwin_resize_cb), imageviewer);
426
427         image_viewer_set_notebook_page((MimeViewer *)imageviewer);
428
429         return (MimeViewer *) imageviewer;
430 }
431
432 static gchar *content_types[] =
433         {"image/*", NULL};
434
435 MimeViewerFactory image_viewer_factory =
436 {
437         content_types,
438         0,
439         
440         image_viewer_create,
441 };
442
443 void image_viewer_init(void)
444 {
445 #if HAVE_GDK_IMLIB
446         gdk_imlib_init();
447         gtk_widget_push_visual(gdk_imlib_get_visual());
448         gtk_widget_push_colormap(gdk_imlib_get_colormap());
449 #endif
450
451         mimeview_register_viewer_factory(&image_viewer_factory);
452 }
453
454 void image_viewer_done(void)
455 {
456         mimeview_unregister_viewer_factory(&image_viewer_factory);
457 }