2005-09-19 [colin] 1.9.14cvs43
[claws.git] / src / image_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 <glib/gi18n.h>
26 #include <gtk/gtkscrolledwindow.h>
27 #include <gtk/gtkpixmap.h>
28
29 #include "procmime.h"
30 #include "utils.h"
31 #include "mimeview.h"
32
33 #include "prefs_common.h"
34
35 typedef struct _ImageViewer ImageViewer;
36
37 MimeViewerFactory image_viewer_factory;
38 void image_viewer_get_resized_size(gint w, gint h, gint aw, gint ah,
39                                           gint * sw, gint * sh);
40 static void image_viewer_clear_viewer(MimeViewer *imageviewer);
41
42 struct _ImageViewer
43 {
44         MimeViewer mimeviewer;
45
46         gchar     *file;
47         MimeInfo  *mimeinfo;
48         gboolean   resize_img;
49
50         GtkWidget *scrolledwin;
51         GtkWidget *image;
52         GtkWidget *notebook;
53         GtkWidget *filename;
54         GtkWidget *filesize;
55         GtkWidget *content_type;
56 };
57
58 static GtkWidget *image_viewer_get_widget(MimeViewer *_mimeviewer)
59 {
60         ImageViewer *imageviewer = (ImageViewer *) _mimeviewer;
61
62         debug_print("image_viewer_get_widget\n");
63
64         return imageviewer->notebook;
65 }
66
67 static void image_viewer_load_file(ImageViewer *imageviewer, const gchar *imgfile)
68 {
69         GdkPixbuf *pixbuf;
70         GdkPixbuf *pixbuf_scaled;
71         GdkPixmap *pixmap;
72         GdkBitmap *mask;
73         gint avail_width;
74         gint avail_height;
75         gint new_width;
76         gint new_height;
77         GError *error = NULL;
78
79         debug_print("image_viewer_show_mimepart\n");
80
81         pixbuf = gdk_pixbuf_new_from_file(imgfile, &error);
82         if (error) {
83                 g_warning(error->message);
84                 g_error_free(error);
85         }
86         if (!pixbuf) {
87                 g_warning("Can't load the image.");     
88                 return;
89         }
90
91         if (imageviewer->resize_img) {
92                 avail_width = imageviewer->notebook->parent->allocation.width;
93                 avail_height = imageviewer->notebook->parent->allocation.height;
94                 if (avail_width > 8) avail_width -= 8;
95                 if (avail_height > 8) avail_height -= 8;
96
97                 image_viewer_get_resized_size(gdk_pixbuf_get_width(pixbuf),
98                                  gdk_pixbuf_get_height(pixbuf),
99                                  avail_width, avail_height,
100                                  &new_width, &new_height);
101
102                 pixbuf_scaled = gdk_pixbuf_scale_simple
103                         (pixbuf, new_width, new_height, GDK_INTERP_BILINEAR);
104                 g_object_unref(pixbuf);
105                 pixbuf = pixbuf_scaled;
106         }
107
108         gdk_pixbuf_render_pixmap_and_mask(pixbuf, &pixmap, &mask, 0);
109
110         if (!imageviewer->image) {
111                 imageviewer->image = gtk_pixmap_new(pixmap, mask);
112
113                 gtk_scrolled_window_add_with_viewport
114                         (GTK_SCROLLED_WINDOW(imageviewer->scrolledwin),
115                          imageviewer->image);
116         } else
117                 gtk_pixmap_set(GTK_PIXMAP(imageviewer->image), pixmap, mask);
118
119         gtk_widget_show(imageviewer->image);
120
121         g_object_unref(pixbuf);
122 }
123
124 static void image_viewer_set_notebook_page(MimeViewer *_mimeviewer)
125 {
126         ImageViewer *imageviewer = (ImageViewer *) _mimeviewer;
127
128         if (!prefs_common.display_img)
129                 gtk_notebook_set_current_page(GTK_NOTEBOOK(imageviewer->notebook), 0);
130         else
131                 gtk_notebook_set_current_page(GTK_NOTEBOOK(imageviewer->notebook), 1);
132 }
133
134 static void image_viewer_load_image(ImageViewer *imageviewer)
135 {
136         gchar *imgfile;
137
138         if (imageviewer->mimeinfo == NULL)
139                 return;
140
141         imgfile = procmime_get_tmp_file_name(imageviewer->mimeinfo);
142         if (procmime_get_part(imgfile, imageviewer->mimeinfo) < 0) {
143                 g_warning("Can't get mimepart file");   
144                 g_free(imgfile);
145                 return;
146         }
147         image_viewer_load_file(imageviewer, imgfile);
148         g_unlink(imgfile);
149         g_free(imgfile);
150 }
151
152 static void image_viewer_show_mimepart(MimeViewer *_mimeviewer, const gchar *file, MimeInfo *mimeinfo)
153 {
154         ImageViewer *imageviewer = (ImageViewer *) _mimeviewer;
155
156         image_viewer_clear_viewer(_mimeviewer);
157         g_free(imageviewer->file);
158         imageviewer->file = g_strdup(file);
159         imageviewer->mimeinfo = mimeinfo;
160
161         if (prefs_common.display_img)
162                 image_viewer_load_image(imageviewer);
163         else {
164                 gtk_label_set_text(GTK_LABEL(imageviewer->filename),
165                                    procmime_mimeinfo_get_parameter(mimeinfo, "name"));
166                 gtk_label_set_text(GTK_LABEL(imageviewer->filesize), to_human_readable(mimeinfo->length));
167                 gtk_label_set_text(GTK_LABEL(imageviewer->content_type), mimeinfo->subtype);
168         }
169 }
170
171 static void image_viewer_clear_viewer(MimeViewer *_mimeviewer)
172 {
173         ImageViewer *imageviewer = (ImageViewer *) _mimeviewer;
174         GtkAdjustment *hadj, *vadj;
175
176         debug_print("image_viewer_clear_viewer\n");
177
178         image_viewer_set_notebook_page(_mimeviewer);
179
180         if (imageviewer->image != NULL)
181                 gtk_pixmap_set(GTK_PIXMAP(imageviewer->image), NULL, NULL);
182
183         if (imageviewer->scrolledwin) {
184                 hadj = gtk_scrolled_window_get_hadjustment
185                         (GTK_SCROLLED_WINDOW(imageviewer->scrolledwin));
186                 if (hadj)
187                         gtk_adjustment_set_value(hadj, 0.0);
188                 vadj = gtk_scrolled_window_get_vadjustment
189                         (GTK_SCROLLED_WINDOW(imageviewer->scrolledwin));
190                 if (vadj)
191                         gtk_adjustment_set_value(vadj, 0.0);
192         }
193         g_free(imageviewer->file);
194         imageviewer->file = NULL;
195         imageviewer->mimeinfo = NULL;
196         imageviewer->resize_img = prefs_common.resize_img;
197 }
198
199 static void image_viewer_destroy_viewer(MimeViewer *_mimeviewer)
200 {
201         ImageViewer *imageviewer = (ImageViewer *) _mimeviewer;
202
203         debug_print("image_viewer_destroy_viewer\n");
204
205         image_viewer_clear_viewer(_mimeviewer);
206         g_object_unref(imageviewer->notebook);
207         g_free(imageviewer);
208 }
209
210 void image_viewer_get_resized_size(gint w, gint h, gint aw, gint ah,
211                              gint *sw, gint *sh)
212 {
213         gfloat wratio = 1.0;
214         gfloat hratio = 1.0;
215         gfloat ratio  = 1.0;
216
217         if (w > aw)
218                 wratio = (gfloat)aw / (gfloat)w;
219         if (h > ah)
220                 hratio = (gfloat)ah / (gfloat)h;
221
222         ratio = (wratio > hratio) ? hratio : wratio;
223
224         *sw = (gint)(w * ratio);
225         *sh = (gint)(h * ratio);
226
227         /* be paranoid */
228         if (*sw <= 0 || *sh <= 0) {
229                 *sw = w;
230                 *sh = h;
231         }
232 }
233
234 static void load_cb(GtkButton *button, ImageViewer *imageviewer)
235 {
236         gtk_notebook_set_current_page(GTK_NOTEBOOK(imageviewer->notebook), 1);
237         image_viewer_load_image(imageviewer);
238 }
239
240 static gboolean scrolledwin_button_cb(GtkWidget *scrolledwin, GdkEventButton *event,
241                                       ImageViewer *imageviewer)
242 {
243         if (event->button == 1 && imageviewer->image) {
244                 imageviewer->resize_img = !imageviewer->resize_img;
245                 image_viewer_load_image(imageviewer);
246                 return TRUE;
247         }
248         return FALSE;
249 }
250
251 static void scrolledwin_resize_cb(GtkWidget *scrolledwin, GtkAllocation *alloc,
252                                   ImageViewer *imageviewer)
253 {
254         if (imageviewer->resize_img)
255                 image_viewer_load_image(imageviewer);
256 }
257
258 MimeViewer *image_viewer_create(void)
259 {
260         ImageViewer *imageviewer;
261         /*
262          *  glade generated code (do not touch)
263          */
264         GtkWidget *notebook;
265         GtkWidget *table1;
266         GtkWidget *label3;
267         GtkWidget *label4;
268         GtkWidget *filename;
269         GtkWidget *filesize;
270         GtkWidget *load_button;
271         GtkWidget *label5;
272         GtkWidget *content_type;
273         GtkWidget *scrolledwin;
274
275         notebook = gtk_notebook_new();
276         gtk_widget_show(notebook);
277         GTK_WIDGET_UNSET_FLAGS(notebook, GTK_CAN_FOCUS);
278         gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
279         gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE);
280
281         table1 = gtk_table_new(4, 3, FALSE);
282         gtk_widget_show(table1);
283         gtk_container_add(GTK_CONTAINER(notebook), table1);
284         gtk_container_set_border_width(GTK_CONTAINER(table1), 8);
285         gtk_table_set_row_spacings(GTK_TABLE(table1), 4);
286         gtk_table_set_col_spacings(GTK_TABLE(table1), 4);
287
288         label3 = gtk_label_new(_("Filename:"));
289         gtk_widget_show(label3);
290         gtk_table_attach(GTK_TABLE(table1), label3, 0, 1, 0, 1,
291                          (GtkAttachOptions) (GTK_FILL),
292                          (GtkAttachOptions) (0), 0, 0);
293         gtk_misc_set_alignment(GTK_MISC(label3), 0, 0.5);
294
295         label4 = gtk_label_new(_("Filesize:"));
296         gtk_widget_show(label4);
297         gtk_table_attach(GTK_TABLE(table1), label4, 0, 1, 1, 2,
298                          (GtkAttachOptions) (GTK_FILL),
299                          (GtkAttachOptions) (0), 0, 0);
300         gtk_misc_set_alignment(GTK_MISC(label4), 0, 0.5);
301
302         filename = gtk_label_new("");
303         gtk_widget_show(filename);
304         gtk_table_attach(GTK_TABLE(table1), filename, 1, 3, 0, 1,
305                          (GtkAttachOptions) (GTK_FILL),
306                          (GtkAttachOptions) (0), 0, 0);
307         gtk_misc_set_alignment(GTK_MISC(filename), 0, 0.5);
308
309         filesize = gtk_label_new("");
310         gtk_widget_show(filesize);
311         gtk_table_attach(GTK_TABLE(table1), filesize, 1, 3, 1, 2,
312                          (GtkAttachOptions) (GTK_FILL),
313                          (GtkAttachOptions) (0), 0, 0);
314         gtk_misc_set_alignment(GTK_MISC(filesize), 0, 0.5);
315
316         load_button = gtk_button_new_with_label(_("Load Image"));
317         gtk_widget_show(load_button);
318         gtk_table_attach(GTK_TABLE(table1), load_button, 1, 2, 3, 4,
319                          (GtkAttachOptions) (GTK_FILL),
320                          (GtkAttachOptions) (0), 0, 0);
321
322         label5 = gtk_label_new(_("Content-Type:"));
323         gtk_widget_show(label5);
324         gtk_table_attach(GTK_TABLE(table1), label5, 0, 1, 2, 3,
325                          (GtkAttachOptions) (GTK_FILL),
326                          (GtkAttachOptions) (0), 0, 0);
327         gtk_misc_set_alignment(GTK_MISC(label5), 0, 0.5);
328
329         content_type = gtk_label_new("");
330         gtk_widget_show(content_type);
331         gtk_table_attach(GTK_TABLE(table1), content_type, 1, 3, 2, 3,
332                          (GtkAttachOptions) (GTK_FILL),
333                          (GtkAttachOptions) (0), 0, 0);
334         gtk_misc_set_alignment(GTK_MISC(content_type), 0, 0.5);
335
336         scrolledwin = gtk_scrolled_window_new(NULL, NULL);
337         gtk_widget_show(scrolledwin);
338         gtk_container_add(GTK_CONTAINER(notebook), scrolledwin);
339         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
340                                        GTK_POLICY_AUTOMATIC,
341                                        GTK_POLICY_AUTOMATIC);
342         /*
343          *  end of glade code
344          */
345
346         debug_print("Creating image view...\n");
347         imageviewer = g_new0(ImageViewer, 1);
348         imageviewer->mimeviewer.factory = &image_viewer_factory;
349
350         imageviewer->mimeviewer.get_widget = image_viewer_get_widget;
351         imageviewer->mimeviewer.show_mimepart = image_viewer_show_mimepart;
352         imageviewer->mimeviewer.clear_viewer = image_viewer_clear_viewer;
353         imageviewer->mimeviewer.destroy_viewer = image_viewer_destroy_viewer;
354
355         imageviewer->resize_img   = prefs_common.resize_img;
356
357         imageviewer->scrolledwin  = scrolledwin;
358         imageviewer->image        = NULL;
359         imageviewer->notebook     = notebook;
360         imageviewer->filename     = filename;
361         imageviewer->filesize     = filesize;
362         imageviewer->content_type = content_type;
363
364         gtk_widget_ref(notebook);
365
366         g_signal_connect(G_OBJECT(load_button), "released",
367                          G_CALLBACK(load_cb), imageviewer);
368         g_signal_connect(G_OBJECT(scrolledwin), "button-press-event",
369                          G_CALLBACK(scrolledwin_button_cb), imageviewer);
370         g_signal_connect(G_OBJECT(scrolledwin), "size-allocate",
371                          G_CALLBACK(scrolledwin_resize_cb), imageviewer);
372
373         image_viewer_set_notebook_page((MimeViewer *)imageviewer);
374
375         return (MimeViewer *) imageviewer;
376 }
377
378 static gchar *content_types[] =
379         {"image/*", NULL};
380
381 MimeViewerFactory image_viewer_factory =
382 {
383         content_types,
384         0,
385         
386         image_viewer_create,
387 };
388
389 void image_viewer_init(void)
390 {
391         mimeview_register_viewer_factory(&image_viewer_factory);
392 }
393
394 void image_viewer_done(void)
395 {
396         mimeview_unregister_viewer_factory(&image_viewer_factory);
397 }