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 = g_timeout_add (150,
264 cleanup_callback (GtkObject *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_vbox_new (FALSE, 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 /* The alignment keeps the frame from growing when users resize
351 align = gtk_alignment_new (0.5, 0.5, 0, 0);
352 gtk_container_add (GTK_CONTAINER (align), frame);
353 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
355 /* demo_find_file() looks in the current directory first,
356 * so you can run gtk-demo without installing GTK, then looks
357 * in the location where the file is installed.
360 filename = demo_find_file ("gtk-logo-rgb.gif", &error);
363 pixbuf = gdk_pixbuf_new_from_file (filename, &error);
369 /* This code shows off error handling. You can just use
370 * gtk_image_new_from_file() instead if you don't want to report
371 * errors to the user. If the file doesn't load when using
372 * gtk_image_new_from_file(), a "missing image" icon will
373 * be displayed instead.
377 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
378 GTK_DIALOG_DESTROY_WITH_PARENT,
381 "Unable to open image file 'gtk-logo-rgb.gif': %s",
383 g_error_free (error);
385 g_signal_connect (dialog, "response",
386 G_CALLBACK (gtk_widget_destroy), NULL);
388 gtk_widget_show (dialog);
391 image = gtk_image_new_from_pixbuf (pixbuf);
393 gtk_container_add (GTK_CONTAINER (frame), image);
398 label = gtk_label_new (NULL);
399 gtk_label_set_markup (GTK_LABEL (label),
400 "<u>Animation loaded from a file</u>");
401 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
403 frame = gtk_frame_new (NULL);
404 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
405 /* The alignment keeps the frame from growing when users resize
408 align = gtk_alignment_new (0.5, 0.5, 0, 0);
409 gtk_container_add (GTK_CONTAINER (align), frame);
410 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
412 filename = demo_find_file ("floppybuddy.gif", NULL);
413 image = gtk_image_new_from_file (filename);
416 gtk_container_add (GTK_CONTAINER (frame), image);
422 label = gtk_label_new (NULL);
423 gtk_label_set_markup (GTK_LABEL (label),
424 "<u>Progressive image loading</u>");
425 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
427 frame = gtk_frame_new (NULL);
428 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
429 /* The alignment keeps the frame from growing when users resize
432 align = gtk_alignment_new (0.5, 0.5, 0, 0);
433 gtk_container_add (GTK_CONTAINER (align), frame);
434 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
436 /* Create an empty image for now; the progressive loader
437 * will create the pixbuf and fill it in.
439 image = gtk_image_new_from_pixbuf (NULL);
440 gtk_container_add (GTK_CONTAINER (frame), image);
442 start_progressive_loading (image);
444 /* Sensitivity control */
445 button = gtk_toggle_button_new_with_mnemonic ("_Insensitive");
446 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
448 g_signal_connect (button, "toggled",
449 G_CALLBACK (toggle_sensitivity_callback),
453 if (!GTK_WIDGET_VISIBLE (window))
455 gtk_widget_show_all (window);
459 gtk_widget_destroy (window);