3 * GtkImage is used to display an image; the image can be in a number of formats.
4 * Typically, you load an image into a GdkPixbuf, then display the pixbuf.
6 * This demo code shows some of the more obscure cases, in the simple
7 * case a call to gtk_image_new_from_file() is all you need.
9 * If you want to put image data in your program as a C variable,
10 * use the make-inline-pixbuf program that comes with GTK+.
11 * This way you won't need to depend on loading external files, your
12 * application binary can be self-contained.
16 #include <glib/gstdio.h>
19 #include "demo-common.h"
21 static GtkWidget *window = NULL;
22 static GdkPixbufLoader *pixbuf_loader = NULL;
23 static guint load_timeout = 0;
24 static FILE* image_stream = NULL;
27 progressive_prepared_callback (GdkPixbufLoader *loader,
33 image = GTK_WIDGET (data);
35 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
37 /* Avoid displaying random memory contents, since the pixbuf
38 * isn't filled in yet.
40 gdk_pixbuf_fill (pixbuf, 0xaaaaaaff);
42 gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
46 progressive_updated_callback (GdkPixbufLoader *loader,
55 image = GTK_WIDGET (data);
57 /* We know the pixbuf inside the GtkImage has changed, but the image
58 * itself doesn't know this; so queue a redraw. If we wanted to be
59 * really efficient, we could use a drawing area or something
60 * instead of a GtkImage, so we could control the exact position of
61 * the pixbuf on the display, then we could queue a draw for only
62 * the updated area of the image.
65 gtk_widget_queue_draw (image);
69 progressive_timeout (gpointer data)
73 image = GTK_WIDGET (data);
75 /* This shows off fully-paranoid error handling, so looks scary.
76 * You could factor out the error handling code into a nice separate
77 * function to make things nicer.
86 bytes_read = fread (buf, 1, 256, image_stream);
88 if (ferror (image_stream))
92 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
93 GTK_DIALOG_DESTROY_WITH_PARENT,
96 "Failure reading image file 'alphatest.png': %s",
99 g_signal_connect (dialog, "response",
100 G_CALLBACK (gtk_widget_destroy), NULL);
102 fclose (image_stream);
105 gtk_widget_show (dialog);
109 return FALSE; /* uninstall the timeout */
112 if (!gdk_pixbuf_loader_write (pixbuf_loader,
118 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
119 GTK_DIALOG_DESTROY_WITH_PARENT,
122 "Failed to load image: %s",
125 g_error_free (error);
127 g_signal_connect (dialog, "response",
128 G_CALLBACK (gtk_widget_destroy), NULL);
130 fclose (image_stream);
133 gtk_widget_show (dialog);
137 return FALSE; /* uninstall the timeout */
140 if (feof (image_stream))
142 fclose (image_stream);
145 /* Errors can happen on close, e.g. if the image
146 * file was truncated we'll know on close that
150 if (!gdk_pixbuf_loader_close (pixbuf_loader,
155 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
156 GTK_DIALOG_DESTROY_WITH_PARENT,
159 "Failed to load image: %s",
162 g_error_free (error);
164 g_signal_connect (dialog, "response",
165 G_CALLBACK (gtk_widget_destroy), NULL);
167 gtk_widget_show (dialog);
169 g_object_unref (pixbuf_loader);
170 pixbuf_loader = NULL;
174 return FALSE; /* uninstall the timeout */
177 g_object_unref (pixbuf_loader);
178 pixbuf_loader = NULL;
184 gchar *error_message = NULL;
185 GError *error = NULL;
187 /* demo_find_file() looks in the current directory first,
188 * so you can run gtk-demo without installing GTK, then looks
189 * in the location where the file is installed.
191 filename = demo_find_file ("alphatest.png", &error);
194 error_message = g_strdup (error->message);
195 g_error_free (error);
199 image_stream = g_fopen (filename, "rb");
203 error_message = g_strdup_printf ("Unable to open image file 'alphatest.png': %s",
207 if (image_stream == NULL)
211 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
212 GTK_DIALOG_DESTROY_WITH_PARENT,
215 "%s", error_message);
216 g_free (error_message);
218 g_signal_connect (dialog, "response",
219 G_CALLBACK (gtk_widget_destroy), NULL);
221 gtk_widget_show (dialog);
225 return FALSE; /* uninstall the timeout */
230 gdk_pixbuf_loader_close (pixbuf_loader, NULL);
231 g_object_unref (pixbuf_loader);
232 pixbuf_loader = NULL;
235 pixbuf_loader = gdk_pixbuf_loader_new ();
237 g_signal_connect (pixbuf_loader, "area-prepared",
238 G_CALLBACK (progressive_prepared_callback), image);
240 g_signal_connect (pixbuf_loader, "area-updated",
241 G_CALLBACK (progressive_updated_callback), image);
244 /* leave timeout installed */
249 start_progressive_loading (GtkWidget *image)
251 /* This is obviously totally contrived (we slow down loading
252 * on purpose to show how incremental loading works).
253 * The real purpose of incremental loading is the case where
254 * you are reading data from a slow source such as the network.
255 * The timeout simply simulates a slow data source by inserting
256 * pauses in the reading process.
258 load_timeout = gdk_threads_add_timeout (150,
264 cleanup_callback (GObject *object,
269 g_source_remove (load_timeout);
275 gdk_pixbuf_loader_close (pixbuf_loader, NULL);
276 g_object_unref (pixbuf_loader);
277 pixbuf_loader = NULL;
281 fclose (image_stream);
286 toggle_sensitivity_callback (GtkWidget *togglebutton,
289 GtkContainer *container = user_data;
293 list = gtk_container_get_children (container);
298 /* don't disable our toggle */
299 if (GTK_WIDGET (tmp->data) != togglebutton)
300 gtk_widget_set_sensitive (GTK_WIDGET (tmp->data),
301 !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (togglebutton)));
311 do_images (GtkWidget *do_widget)
321 GError *error = NULL;
326 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
327 gtk_window_set_screen (GTK_WINDOW (window),
328 gtk_widget_get_screen (do_widget));
329 gtk_window_set_title (GTK_WINDOW (window), "Images");
331 g_signal_connect (window, "destroy",
332 G_CALLBACK (gtk_widget_destroyed), &window);
333 g_signal_connect (window, "destroy",
334 G_CALLBACK (cleanup_callback), NULL);
336 gtk_container_set_border_width (GTK_CONTAINER (window), 8);
338 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, FALSE, 8);
339 gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
340 gtk_container_add (GTK_CONTAINER (window), vbox);
342 label = gtk_label_new (NULL);
343 gtk_label_set_markup (GTK_LABEL (label),
344 "<u>Image loaded from a file</u>");
345 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
347 frame = gtk_frame_new (NULL);
348 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
349 /* The alignment keeps the frame from growing when users resize
352 align = gtk_alignment_new (0.5, 0.5, 0, 0);
353 gtk_container_add (GTK_CONTAINER (align), frame);
354 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
356 /* demo_find_file() looks in the current directory first,
357 * so you can run gtk-demo without installing GTK, then looks
358 * in the location where the file is installed.
361 filename = demo_find_file ("gtk-logo-rgb.gif", &error);
364 pixbuf = gdk_pixbuf_new_from_file (filename, &error);
370 /* This code shows off error handling. You can just use
371 * gtk_image_new_from_file() instead if you don't want to report
372 * errors to the user. If the file doesn't load when using
373 * gtk_image_new_from_file(), a "missing image" icon will
374 * be displayed instead.
378 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
379 GTK_DIALOG_DESTROY_WITH_PARENT,
382 "Unable to open image file 'gtk-logo-rgb.gif': %s",
384 g_error_free (error);
386 g_signal_connect (dialog, "response",
387 G_CALLBACK (gtk_widget_destroy), NULL);
389 gtk_widget_show (dialog);
392 image = gtk_image_new_from_pixbuf (pixbuf);
394 gtk_container_add (GTK_CONTAINER (frame), image);
399 label = gtk_label_new (NULL);
400 gtk_label_set_markup (GTK_LABEL (label),
401 "<u>Animation loaded from a file</u>");
402 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
404 frame = gtk_frame_new (NULL);
405 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
406 /* The alignment keeps the frame from growing when users resize
409 align = gtk_alignment_new (0.5, 0.5, 0, 0);
410 gtk_container_add (GTK_CONTAINER (align), frame);
411 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
413 filename = demo_find_file ("floppybuddy.gif", NULL);
414 image = gtk_image_new_from_file (filename);
417 gtk_container_add (GTK_CONTAINER (frame), image);
421 label = gtk_label_new (NULL);
422 gtk_label_set_markup (GTK_LABEL (label),
423 "<u>Symbolic themed icon</u>");
424 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
426 frame = gtk_frame_new (NULL);
427 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
428 /* The alignment keeps the frame from growing when users resize
431 align = gtk_alignment_new (0.5, 0.5, 0, 0);
432 gtk_container_add (GTK_CONTAINER (align), frame);
433 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
435 gicon = g_themed_icon_new_with_default_fallbacks ("battery-critical-charging-symbolic");
436 image = gtk_image_new_from_gicon (gicon, GTK_ICON_SIZE_DIALOG);
438 gtk_container_add (GTK_CONTAINER (frame), image);
443 label = gtk_label_new (NULL);
444 gtk_label_set_markup (GTK_LABEL (label),
445 "<u>Progressive image loading</u>");
446 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
448 frame = gtk_frame_new (NULL);
449 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
450 /* The alignment keeps the frame from growing when users resize
453 align = gtk_alignment_new (0.5, 0.5, 0, 0);
454 gtk_container_add (GTK_CONTAINER (align), frame);
455 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
457 /* Create an empty image for now; the progressive loader
458 * will create the pixbuf and fill it in.
460 image = gtk_image_new_from_pixbuf (NULL);
461 gtk_container_add (GTK_CONTAINER (frame), image);
463 start_progressive_loading (image);
465 /* Sensitivity control */
466 button = gtk_toggle_button_new_with_mnemonic ("_Insensitive");
467 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
469 g_signal_connect (button, "toggled",
470 G_CALLBACK (toggle_sensitivity_callback),
474 if (!gtk_widget_get_visible (window))
476 gtk_widget_show_all (window);
480 gtk_widget_destroy (window);