2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2023 the Claws Mail team and Hiroyuki Yamamoto
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 3 of the License, or
8 * (at your option) any later version.
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.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "claws-features.h"
25 #include <glib/gi18n.h>
29 #include "file-utils.h"
33 #include "prefs_common.h"
35 typedef struct _ImageViewer ImageViewer
;
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 static void scrolledwin_resize_cb(GtkWidget
*scrolledwin
, GtkAllocation
*alloc
,
42 ImageViewer
*imageviewer
);
45 MimeViewer mimeviewer
;
50 gboolean fit_img_height
;
52 GtkWidget
*scrolledwin
;
59 GtkWidget
*content_type
;
60 GtkWidget
*load_button
;
63 static GtkWidget
*image_viewer_get_widget(MimeViewer
*_mimeviewer
)
65 ImageViewer
*imageviewer
= (ImageViewer
*) _mimeviewer
;
67 debug_print("image_viewer_get_widget\n");
69 return imageviewer
->notebook
;
72 static void image_viewer_load_image(ImageViewer
*imageviewer
)
74 GtkAllocation allocation
;
75 GdkPixbufAnimation
*animation
= NULL
;
76 GdkPixbuf
*pixbuf
= NULL
;
80 cm_return_if_fail(imageviewer
!= NULL
);
82 if (imageviewer
->mimeinfo
== NULL
)
85 stream
= procmime_get_part_as_inputstream(imageviewer
->mimeinfo
);
87 g_warning("couldn't get image MIME part");
91 #if GDK_PIXBUF_MINOR >= 28
92 animation
= gdk_pixbuf_animation_new_from_stream(stream
, NULL
, &error
);
94 pixbuf
= gdk_pixbuf_new_from_stream(stream
, NULL
, &error
);
96 g_object_unref(stream
);
99 g_warning("couldn't load image: %s", error
->message
);
100 gtk_label_set_text(GTK_LABEL(imageviewer
->error_lbl
), _("Error:"));
101 gtk_label_set_text(GTK_LABEL(imageviewer
->error_msg
), error
->message
);
102 gtk_notebook_set_current_page(GTK_NOTEBOOK(imageviewer
->notebook
), 0);
103 gtk_widget_hide(imageviewer
->load_button
);
108 #if GDK_PIXBUF_MINOR >= 28
109 if ((animation
&& gdk_pixbuf_animation_is_static_image(animation
)) ||
110 imageviewer
->resize_img
|| imageviewer
->fit_img_height
) {
111 pixbuf
= gdk_pixbuf_animation_get_static_image(animation
);
112 g_object_ref(pixbuf
);
113 g_object_unref(animation
);
116 if (imageviewer
->resize_img
|| imageviewer
->fit_img_height
) {
118 if (imageviewer
->resize_img
) {
119 gtk_widget_get_allocation(imageviewer
->scrolledwin
, &allocation
);
120 pixbuf
= claws_load_pixbuf_fitting(pixbuf
, FALSE
,
121 imageviewer
->fit_img_height
,
125 pixbuf
= claws_load_pixbuf_fitting(pixbuf
, FALSE
,
126 imageviewer
->fit_img_height
,
130 if (!pixbuf
&& !animation
) {
131 g_warning("couldn't load the image");
135 g_signal_handlers_block_by_func(G_OBJECT(imageviewer
->scrolledwin
),
136 G_CALLBACK(scrolledwin_resize_cb
), imageviewer
);
139 gtk_image_set_from_animation(GTK_IMAGE(imageviewer
->image
), animation
);
141 gtk_image_set_from_pixbuf(GTK_IMAGE(imageviewer
->image
), pixbuf
);
143 gtk_widget_get_allocation(imageviewer
->scrolledwin
, &allocation
);
144 gtk_widget_size_allocate(imageviewer
->scrolledwin
, &allocation
);
146 gtk_widget_show(imageviewer
->image
);
148 g_signal_handlers_unblock_by_func(G_OBJECT(imageviewer
->scrolledwin
),
149 G_CALLBACK(scrolledwin_resize_cb
), imageviewer
);
152 g_object_unref(pixbuf
);
154 g_object_unref(animation
);
157 static void image_viewer_set_notebook_page(MimeViewer
*_mimeviewer
)
159 ImageViewer
*imageviewer
= (ImageViewer
*) _mimeviewer
;
161 if (!prefs_common
.display_img
)
162 gtk_notebook_set_current_page(GTK_NOTEBOOK(imageviewer
->notebook
), 0);
164 gtk_notebook_set_current_page(GTK_NOTEBOOK(imageviewer
->notebook
), 1);
167 static void image_viewer_show_mimepart(MimeViewer
*_mimeviewer
, const gchar
*file
, MimeInfo
*mimeinfo
)
169 ImageViewer
*imageviewer
= (ImageViewer
*) _mimeviewer
;
171 debug_print("image_viewer_show_mimepart\n");
173 image_viewer_clear_viewer(_mimeviewer
);
174 g_free(imageviewer
->file
);
175 imageviewer
->file
= g_strdup(file
);
176 imageviewer
->mimeinfo
= mimeinfo
;
178 gtk_label_set_text(GTK_LABEL(imageviewer
->filename
),
179 (procmime_mimeinfo_get_parameter(mimeinfo
, "name") != NULL
)?
180 procmime_mimeinfo_get_parameter(mimeinfo
, "name") :
181 procmime_mimeinfo_get_parameter(mimeinfo
, "filename"));
182 gtk_label_set_text(GTK_LABEL(imageviewer
->filesize
), to_human_readable((goffset
)mimeinfo
->length
));
183 gtk_label_set_text(GTK_LABEL(imageviewer
->content_type
), mimeinfo
->subtype
);
184 gtk_label_set_text(GTK_LABEL(imageviewer
->error_lbl
), "");
185 gtk_label_set_text(GTK_LABEL(imageviewer
->error_msg
), "");
187 if (prefs_common
.display_img
)
188 image_viewer_load_image(imageviewer
);
191 static void image_viewer_clear_viewer(MimeViewer
*_mimeviewer
)
193 ImageViewer
*imageviewer
= (ImageViewer
*) _mimeviewer
;
194 GtkAdjustment
*hadj
, *vadj
;
196 debug_print("image_viewer_clear_viewer\n");
198 image_viewer_set_notebook_page(_mimeviewer
);
200 if (imageviewer
->scrolledwin
) {
201 hadj
= gtk_scrolled_window_get_hadjustment
202 (GTK_SCROLLED_WINDOW(imageviewer
->scrolledwin
));
204 gtk_adjustment_set_value(hadj
, 0.0);
206 vadj
= gtk_scrolled_window_get_vadjustment
207 (GTK_SCROLLED_WINDOW(imageviewer
->scrolledwin
));
209 gtk_adjustment_set_value(vadj
, 0.0);
212 g_free(imageviewer
->file
);
213 imageviewer
->file
= NULL
;
214 imageviewer
->mimeinfo
= NULL
;
215 imageviewer
->resize_img
= prefs_common
.resize_img
;
216 imageviewer
->fit_img_height
= prefs_common
.fit_img_height
;
219 static void image_viewer_destroy_viewer(MimeViewer
*_mimeviewer
)
221 ImageViewer
*imageviewer
= (ImageViewer
*) _mimeviewer
;
223 debug_print("image_viewer_destroy_viewer\n");
225 image_viewer_clear_viewer(_mimeviewer
);
226 g_object_unref(imageviewer
->notebook
);
230 void image_viewer_get_resized_size(gint w
, gint h
, gint aw
, gint ah
,
238 wratio
= (gfloat
)aw
/ (gfloat
)w
;
240 hratio
= (gfloat
)ah
/ (gfloat
)h
;
242 ratio
= (wratio
> hratio
) ? hratio
: wratio
;
244 *sw
= (gint
)(w
* ratio
);
245 *sh
= (gint
)(h
* ratio
);
248 if (*sw
<= 0 || *sh
<= 0) {
254 static void load_cb(GtkButton
*button
, ImageViewer
*imageviewer
)
256 gtk_notebook_set_current_page(GTK_NOTEBOOK(imageviewer
->notebook
), 1);
257 image_viewer_load_image(imageviewer
);
260 static gboolean
image_button_cb(GtkWidget
*scrolledwin
, GdkEventButton
*event
,
261 ImageViewer
*imageviewer
)
263 if (event
->button
== 1 && imageviewer
->image
) {
264 imageviewer
->resize_img
= !imageviewer
->resize_img
;
265 image_viewer_load_image(imageviewer
);
267 } else if (event
->button
== 3 && imageviewer
->image
) {
268 imageviewer
->fit_img_height
= !imageviewer
->fit_img_height
;
269 image_viewer_load_image(imageviewer
);
275 static void scrolledwin_resize_cb(GtkWidget
*scrolledwin
, GtkAllocation
*alloc
,
276 ImageViewer
*imageviewer
)
278 if (imageviewer
->resize_img
)
279 image_viewer_load_image(imageviewer
);
282 static MimeViewer
*image_viewer_create(void)
284 ImageViewer
*imageviewer
;
291 GtkWidget
*load_button
;
293 GtkWidget
*content_type
;
294 GtkWidget
*scrolledwin
;
297 GtkWidget
*error_lbl
;
298 GtkWidget
*error_msg
;
300 notebook
= gtk_notebook_new();
301 gtk_widget_set_name(GTK_WIDGET(notebook
), "image_viewer");
302 gtk_widget_show(notebook
);
303 gtk_widget_set_can_focus(notebook
, FALSE
);
304 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook
), FALSE
);
305 gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook
), FALSE
);
307 table1
= gtk_grid_new();
308 gtk_widget_show(table1
);
309 gtk_container_add(GTK_CONTAINER(notebook
), table1
);
310 gtk_container_set_border_width(GTK_CONTAINER(table1
), 8);
311 gtk_grid_set_row_spacing(GTK_GRID(table1
), 4);
312 gtk_grid_set_column_spacing(GTK_GRID(table1
), 4);
314 label3
= gtk_label_new(_("Filename:"));
315 gtk_widget_show(label3
);
316 gtk_label_set_xalign(GTK_LABEL(label3
), 0.0);
317 gtk_grid_attach(GTK_GRID(table1
), label3
, 0, 0, 2, 1);
319 filename
= gtk_label_new("");
320 gtk_widget_show(filename
);
321 gtk_label_set_xalign(GTK_LABEL(filename
), 0.0);
322 gtk_grid_attach(GTK_GRID(table1
), filename
, 1, 0, 2, 1);
323 gtk_widget_set_hexpand(filename
, TRUE
);
324 gtk_widget_set_halign(filename
, GTK_ALIGN_FILL
);
326 label4
= gtk_label_new(_("Filesize:"));
327 gtk_widget_show(label4
);
328 gtk_label_set_xalign(GTK_LABEL(label4
), 0.0);
329 gtk_grid_attach(GTK_GRID(table1
), label4
, 0, 1, 2, 1);
331 filesize
= gtk_label_new("");
332 gtk_widget_show(filesize
);
333 gtk_label_set_xalign(GTK_LABEL(filesize
), 0.0);
334 gtk_grid_attach(GTK_GRID(table1
), filesize
, 1, 1, 2, 1);
335 gtk_widget_set_hexpand(filesize
, TRUE
);
336 gtk_widget_set_halign(filesize
, GTK_ALIGN_FILL
);
338 label5
= gtk_label_new(_("Content-Type:"));
339 gtk_widget_show(label5
);
340 gtk_label_set_xalign(GTK_LABEL(label5
), 0.0);
341 gtk_grid_attach(GTK_GRID(table1
), label5
, 0, 2, 2, 1);
342 gtk_widget_set_hexpand(label5
, TRUE
);
343 gtk_widget_set_halign(label5
, GTK_ALIGN_FILL
);
345 content_type
= gtk_label_new("");
346 gtk_widget_show(content_type
);
347 gtk_label_set_xalign(GTK_LABEL(content_type
), 0.0);
348 gtk_grid_attach(GTK_GRID(table1
), content_type
, 1, 2, 2, 1);
349 gtk_widget_set_hexpand(content_type
, TRUE
);
350 gtk_widget_set_halign(content_type
, GTK_ALIGN_FILL
);
352 error_lbl
= gtk_label_new("");
353 gtk_widget_show(error_lbl
);
354 gtk_label_set_xalign(GTK_LABEL(error_lbl
), 0.0);
355 gtk_grid_attach(GTK_GRID(table1
), error_lbl
, 0, 3, 2, 1);
356 gtk_widget_set_hexpand(error_lbl
, TRUE
);
357 gtk_widget_set_halign(error_lbl
, GTK_ALIGN_FILL
);
359 error_msg
= gtk_label_new("");
360 gtk_widget_show(error_msg
);
361 gtk_label_set_xalign(GTK_LABEL(error_msg
), 0.0);
362 gtk_grid_attach(GTK_GRID(table1
), error_msg
, 1, 3, 2, 1);
363 gtk_widget_set_hexpand(error_msg
, TRUE
);
364 gtk_widget_set_halign(error_msg
, GTK_ALIGN_FILL
);
366 load_button
= gtk_button_new_with_label(_("Load Image"));
367 gtk_widget_show(load_button
);
368 gtk_widget_set_size_request(GTK_WIDGET(load_button
), 6, -1);
369 gtk_grid_attach(GTK_GRID(table1
), load_button
, 0, 4, 1, 1);
370 gtk_widget_set_hexpand(load_button
, TRUE
);
371 gtk_widget_set_halign(load_button
, GTK_ALIGN_START
);
373 scrolledwin
= gtk_scrolled_window_new(NULL
, NULL
);
374 gtk_widget_show(scrolledwin
);
375 gtk_container_add(GTK_CONTAINER(notebook
), scrolledwin
);
376 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin
),
377 GTK_POLICY_AUTOMATIC
,
378 GTK_POLICY_AUTOMATIC
);
379 gtk_scrolled_window_set_propagate_natural_height(GTK_SCROLLED_WINDOW(scrolledwin
), TRUE
);
381 eventbox
= gtk_event_box_new();
382 gtk_widget_show(eventbox
);
383 gtk_container_add(GTK_CONTAINER(scrolledwin
), eventbox
);
385 image
= gtk_image_new();
386 gtk_container_add( GTK_CONTAINER(eventbox
), image
);
388 debug_print("Creating image view...\n");
389 imageviewer
= g_new0(ImageViewer
, 1);
390 imageviewer
->mimeviewer
.factory
= &image_viewer_factory
;
392 imageviewer
->mimeviewer
.get_widget
= image_viewer_get_widget
;
393 imageviewer
->mimeviewer
.show_mimepart
= image_viewer_show_mimepart
;
394 imageviewer
->mimeviewer
.clear_viewer
= image_viewer_clear_viewer
;
395 imageviewer
->mimeviewer
.destroy_viewer
= image_viewer_destroy_viewer
;
396 imageviewer
->mimeviewer
.get_selection
= NULL
;
398 imageviewer
->resize_img
= prefs_common
.resize_img
;
399 imageviewer
->fit_img_height
= prefs_common
.fit_img_height
;
401 imageviewer
->scrolledwin
= scrolledwin
;
402 imageviewer
->image
= image
;
403 imageviewer
->notebook
= notebook
;
404 imageviewer
->filename
= filename
;
405 imageviewer
->filesize
= filesize
;
406 imageviewer
->content_type
= content_type
;
407 imageviewer
->error_msg
= error_msg
;
408 imageviewer
->error_lbl
= error_lbl
;
409 imageviewer
->load_button
= load_button
;
411 g_object_ref(notebook
);
413 g_signal_connect(G_OBJECT(load_button
), "clicked",
414 G_CALLBACK(load_cb
), imageviewer
);
415 g_signal_connect(G_OBJECT(eventbox
), "button-press-event",
416 G_CALLBACK(image_button_cb
), imageviewer
);
417 g_signal_connect(G_OBJECT(scrolledwin
), "size-allocate",
418 G_CALLBACK(scrolledwin_resize_cb
), imageviewer
);
420 image_viewer_set_notebook_page((MimeViewer
*)imageviewer
);
422 return (MimeViewer
*) imageviewer
;
425 static gchar
*content_types
[] =
428 MimeViewerFactory image_viewer_factory
=
436 void image_viewer_init(void)
438 mimeview_register_viewer_factory(&image_viewer_factory
);
441 void image_viewer_done(void)
443 mimeview_unregister_viewer_factory(&image_viewer_factory
);