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.
18 #include "demo-common.h"
20 static GtkWidget *window = NULL;
21 static GdkPixbufLoader *pixbuf_loader = NULL;
22 static guint load_timeout = 0;
23 static FILE* image_stream = NULL;
26 progressive_prepared_callback (GdkPixbufLoader *loader,
32 image = GTK_WIDGET (data);
34 pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
36 /* Avoid displaying random memory contents, since the pixbuf
37 * isn't filled in yet.
39 gdk_pixbuf_fill (pixbuf, 0xaaaaaaff);
41 gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
45 progressive_updated_callback (GdkPixbufLoader *loader,
54 image = GTK_WIDGET (data);
56 /* We know the pixbuf inside the GtkImage has changed, but the image
57 * itself doesn't know this; so queue a redraw. If we wanted to be
58 * really efficient, we could use a drawing area or something
59 * instead of a GtkImage, so we could control the exact position of
60 * the pixbuf on the display, then we could queue a draw for only
61 * the updated area of the image.
64 gtk_widget_queue_draw (image);
68 progressive_timeout (gpointer data)
72 image = GTK_WIDGET (data);
74 /* This shows off fully-paranoid error handling, so looks scary.
75 * You could factor out the error handling code into a nice separate
76 * function to make things nicer.
85 bytes_read = fread (buf, 1, 256, image_stream);
87 if (ferror (image_stream))
91 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
92 GTK_DIALOG_DESTROY_WITH_PARENT,
95 "Failure reading image file 'alphatest.png': %s",
98 g_signal_connect (dialog, "response",
99 G_CALLBACK (gtk_widget_destroy), NULL);
101 fclose (image_stream);
104 gtk_widget_show (dialog);
108 return FALSE; /* uninstall the timeout */
111 if (!gdk_pixbuf_loader_write (pixbuf_loader,
117 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
118 GTK_DIALOG_DESTROY_WITH_PARENT,
121 "Failed to load image: %s",
124 g_error_free (error);
126 g_signal_connect (dialog, "response",
127 G_CALLBACK (gtk_widget_destroy), NULL);
129 fclose (image_stream);
132 gtk_widget_show (dialog);
136 return FALSE; /* uninstall the timeout */
139 if (feof (image_stream))
141 fclose (image_stream);
144 /* Errors can happen on close, e.g. if the image
145 * file was truncated we'll know on close that
149 if (!gdk_pixbuf_loader_close (pixbuf_loader,
154 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
155 GTK_DIALOG_DESTROY_WITH_PARENT,
158 "Failed to load image: %s",
161 g_error_free (error);
163 g_signal_connect (dialog, "response",
164 G_CALLBACK (gtk_widget_destroy), NULL);
166 gtk_widget_show (dialog);
168 g_object_unref (pixbuf_loader);
169 pixbuf_loader = NULL;
173 return FALSE; /* uninstall the timeout */
176 g_object_unref (pixbuf_loader);
177 pixbuf_loader = NULL;
183 gchar *error_message = NULL;
184 GError *error = NULL;
186 /* demo_find_file() looks in the the current directory first,
187 * so you can run gtk-demo without installing GTK, then looks
188 * in the location where the file is installed.
190 filename = demo_find_file ("alphatest.png", &error);
193 error_message = g_strdup (error->message);
194 g_error_free (error);
198 image_stream = fopen (filename, "r");
202 error_message = g_strdup_printf ("Unable to open image file 'alphatest.png': %s",
206 if (image_stream == NULL)
210 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
211 GTK_DIALOG_DESTROY_WITH_PARENT,
214 "%s", error_message);
215 g_free (error_message);
217 g_signal_connect (dialog, "response",
218 G_CALLBACK (gtk_widget_destroy), NULL);
220 gtk_widget_show (dialog);
224 return FALSE; /* uninstall the timeout */
229 gdk_pixbuf_loader_close (pixbuf_loader, NULL);
230 g_object_unref (pixbuf_loader);
231 pixbuf_loader = NULL;
234 pixbuf_loader = gdk_pixbuf_loader_new ();
236 g_signal_connect (pixbuf_loader, "area_prepared",
237 G_CALLBACK (progressive_prepared_callback), image);
239 g_signal_connect (pixbuf_loader, "area_updated",
240 G_CALLBACK (progressive_updated_callback), image);
243 /* leave timeout installed */
248 start_progressive_loading (GtkWidget *image)
250 /* This is obviously totally contrived (we slow down loading
251 * on purpose to show how incremental loading works).
252 * The real purpose of incremental loading is the case where
253 * you are reading data from a slow source such as the network.
254 * The timeout simply simulates a slow data source by inserting
255 * pauses in the reading process.
257 load_timeout = g_timeout_add (150,
263 cleanup_callback (GtkObject *object,
268 g_source_remove (load_timeout);
274 gdk_pixbuf_loader_close (pixbuf_loader, NULL);
275 g_object_unref (pixbuf_loader);
276 pixbuf_loader = NULL;
280 fclose (image_stream);
285 toggle_sensitivity_callback (GtkWidget *togglebutton,
288 GtkContainer *container = user_data;
292 list = gtk_container_get_children (container);
297 /* don't disable our toggle */
298 if (GTK_WIDGET (tmp->data) != togglebutton)
299 gtk_widget_set_sensitive (GTK_WIDGET (tmp->data),
300 !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (togglebutton)));
310 do_images (GtkWidget *do_widget)
319 GError *error = NULL;
324 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
325 gtk_window_set_screen (GTK_WINDOW (window),
326 gtk_widget_get_screen (do_widget));
327 gtk_window_set_title (GTK_WINDOW (window), "Images");
329 g_signal_connect (window, "destroy",
330 G_CALLBACK (gtk_widget_destroyed), &window);
331 g_signal_connect (window, "destroy",
332 G_CALLBACK (cleanup_callback), NULL);
334 gtk_container_set_border_width (GTK_CONTAINER (window), 8);
336 vbox = gtk_vbox_new (FALSE, 8);
337 gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
338 gtk_container_add (GTK_CONTAINER (window), vbox);
340 label = gtk_label_new (NULL);
341 gtk_label_set_markup (GTK_LABEL (label),
342 "<u>Image loaded from a file</u>");
343 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
345 frame = gtk_frame_new (NULL);
346 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
347 /* The alignment keeps the frame from growing when users resize
350 align = gtk_alignment_new (0.5, 0.5, 0, 0);
351 gtk_container_add (GTK_CONTAINER (align), frame);
352 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
354 /* demo_find_file() looks in the the current directory first,
355 * so you can run gtk-demo without installing GTK, then looks
356 * in the location where the file is installed.
359 filename = demo_find_file ("gtk-logo-rgb.gif", &error);
362 pixbuf = gdk_pixbuf_new_from_file (filename, &error);
368 /* This code shows off error handling. You can just use
369 * gtk_image_new_from_file() instead if you don't want to report
370 * errors to the user. If the file doesn't load when using
371 * gtk_image_new_from_file(), a "missing image" icon will
372 * be displayed instead.
376 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
377 GTK_DIALOG_DESTROY_WITH_PARENT,
380 "Unable to open image file 'gtk-logo-rgb.gif': %s",
382 g_error_free (error);
384 g_signal_connect (dialog, "response",
385 G_CALLBACK (gtk_widget_destroy), NULL);
387 gtk_widget_show (dialog);
390 image = gtk_image_new_from_pixbuf (pixbuf);
392 gtk_container_add (GTK_CONTAINER (frame), image);
397 label = gtk_label_new (NULL);
398 gtk_label_set_markup (GTK_LABEL (label),
399 "<u>Animation loaded from a file</u>");
400 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
402 frame = gtk_frame_new (NULL);
403 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
404 /* The alignment keeps the frame from growing when users resize
407 align = gtk_alignment_new (0.5, 0.5, 0, 0);
408 gtk_container_add (GTK_CONTAINER (align), frame);
409 gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
411 filename = demo_find_file ("floppybuddy.gif", NULL);
412 image = gtk_image_new_from_file (filename);
415 gtk_container_add (GTK_CONTAINER (frame), image);
421 label = gtk_label_new (NULL);
422 gtk_label_set_markup (GTK_LABEL (label),
423 "<u>Progressive image loading</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 /* Create an empty image for now; the progressive loader
436 * will create the pixbuf and fill it in.
438 image = gtk_image_new_from_pixbuf (NULL);
439 gtk_container_add (GTK_CONTAINER (frame), image);
441 start_progressive_loading (image);
443 /* Sensitivity control */
444 button = gtk_toggle_button_new_with_mnemonic ("_Insensitive");
445 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
447 g_signal_connect (button, "toggled",
448 G_CALLBACK (toggle_sensitivity_callback),
452 if (!GTK_WIDGET_VISIBLE (window))
454 gtk_widget_show_all (window);
458 gtk_widget_destroy (window);