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)
320 GError *error = NULL;
325 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
326 gtk_window_set_screen (GTK_WINDOW (window),
327 gtk_widget_get_screen (do_widget));
328 gtk_window_set_title (GTK_WINDOW (window), "Images");
330 g_signal_connect (window, "destroy",
331 G_CALLBACK (gtk_widget_destroyed), &window);
332 g_signal_connect (window, "destroy",
333 G_CALLBACK (cleanup_callback), NULL);
335 gtk_container_set_border_width (GTK_CONTAINER (window), 8);
337 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
338 gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
339 gtk_container_add (GTK_CONTAINER (window), vbox);
341 label = gtk_label_new (NULL);
342 gtk_label_set_markup (GTK_LABEL (label),
343 "<u>Image loaded from a file</u>");
344 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
346 frame = gtk_frame_new (NULL);
347 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
348 gtk_widget_set_halign (frame, GTK_ALIGN_CENTER);
349 gtk_widget_set_valign (frame, GTK_ALIGN_CENTER);
350 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
352 /* demo_find_file() looks in the current directory first,
353 * so you can run gtk-demo without installing GTK, then looks
354 * in the location where the file is installed.
357 filename = demo_find_file ("gtk-logo-rgb.gif", &error);
360 pixbuf = gdk_pixbuf_new_from_file (filename, &error);
366 /* This code shows off error handling. You can just use
367 * gtk_image_new_from_file() instead if you don't want to report
368 * errors to the user. If the file doesn't load when using
369 * gtk_image_new_from_file(), a "missing image" icon will
370 * be displayed instead.
374 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
375 GTK_DIALOG_DESTROY_WITH_PARENT,
378 "Unable to open image file 'gtk-logo-rgb.gif': %s",
380 g_error_free (error);
382 g_signal_connect (dialog, "response",
383 G_CALLBACK (gtk_widget_destroy), NULL);
385 gtk_widget_show (dialog);
388 image = gtk_image_new_from_pixbuf (pixbuf);
390 gtk_container_add (GTK_CONTAINER (frame), image);
395 label = gtk_label_new (NULL);
396 gtk_label_set_markup (GTK_LABEL (label),
397 "<u>Animation loaded from a file</u>");
398 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
400 frame = gtk_frame_new (NULL);
401 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
402 gtk_widget_set_halign (frame, GTK_ALIGN_CENTER);
403 gtk_widget_set_valign (frame, GTK_ALIGN_CENTER);
404 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
406 filename = demo_find_file ("floppybuddy.gif", NULL);
407 image = gtk_image_new_from_file (filename);
410 gtk_container_add (GTK_CONTAINER (frame), image);
414 label = gtk_label_new (NULL);
415 gtk_label_set_markup (GTK_LABEL (label),
416 "<u>Symbolic themed icon</u>");
417 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
419 frame = gtk_frame_new (NULL);
420 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
421 gtk_widget_set_halign (frame, GTK_ALIGN_CENTER);
422 gtk_widget_set_valign (frame, GTK_ALIGN_CENTER);
423 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
425 gicon = g_themed_icon_new_with_default_fallbacks ("battery-caution-charging-symbolic");
426 image = gtk_image_new_from_gicon (gicon, GTK_ICON_SIZE_DIALOG);
428 gtk_container_add (GTK_CONTAINER (frame), image);
433 label = gtk_label_new (NULL);
434 gtk_label_set_markup (GTK_LABEL (label),
435 "<u>Progressive image loading</u>");
436 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
438 frame = gtk_frame_new (NULL);
439 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
440 gtk_widget_set_halign (frame, GTK_ALIGN_CENTER);
441 gtk_widget_set_valign (frame, GTK_ALIGN_CENTER);
442 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
444 /* Create an empty image for now; the progressive loader
445 * will create the pixbuf and fill it in.
447 image = gtk_image_new_from_pixbuf (NULL);
448 gtk_container_add (GTK_CONTAINER (frame), image);
450 start_progressive_loading (image);
452 /* Sensitivity control */
453 button = gtk_toggle_button_new_with_mnemonic ("_Insensitive");
454 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
456 g_signal_connect (button, "toggled",
457 G_CALLBACK (toggle_sensitivity_callback),
461 if (!gtk_widget_get_visible (window))
463 gtk_widget_show_all (window);
467 gtk_widget_destroy (window);