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>
20 static GtkWidget *window = NULL;
21 static GdkPixbufLoader *pixbuf_loader = NULL;
22 static guint load_timeout = 0;
23 static GInputStream * 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 = g_input_stream_read (image_stream, buf, 256, NULL, &error);
91 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
92 GTK_DIALOG_DESTROY_WITH_PARENT,
95 "Failure reading image file 'alphatest.png': %s",
99 g_signal_connect (dialog, "response",
100 G_CALLBACK (gtk_widget_destroy), NULL);
102 g_object_unref (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 g_object_unref (image_stream);
133 gtk_widget_show (dialog);
137 return FALSE; /* uninstall the timeout */
142 /* Errors can happen on close, e.g. if the image
143 * file was truncated we'll know on close that
147 if (!g_input_stream_close (image_stream, NULL, &error))
151 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
152 GTK_DIALOG_DESTROY_WITH_PARENT,
155 "Failed to load image: %s",
158 g_error_free (error);
160 g_signal_connect (dialog, "response",
161 G_CALLBACK (gtk_widget_destroy), NULL);
163 gtk_widget_show (dialog);
165 g_object_unref (image_stream);
167 g_object_unref (pixbuf_loader);
168 pixbuf_loader = NULL;
172 return FALSE; /* uninstall the timeout */
175 g_object_unref (image_stream);
178 /* Errors can happen on close, e.g. if the image
179 * file was truncated we'll know on close that
183 if (!gdk_pixbuf_loader_close (pixbuf_loader,
188 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
189 GTK_DIALOG_DESTROY_WITH_PARENT,
192 "Failed to load image: %s",
195 g_error_free (error);
197 g_signal_connect (dialog, "response",
198 G_CALLBACK (gtk_widget_destroy), NULL);
200 gtk_widget_show (dialog);
202 g_object_unref (pixbuf_loader);
203 pixbuf_loader = NULL;
207 return FALSE; /* uninstall the timeout */
210 g_object_unref (pixbuf_loader);
211 pixbuf_loader = NULL;
216 GError *error = NULL;
218 image_stream = g_resources_open_stream ("/images/alphatest.png", 0, &error);
220 if (image_stream == NULL)
224 dialog = gtk_message_dialog_new (GTK_WINDOW (window),
225 GTK_DIALOG_DESTROY_WITH_PARENT,
228 "%s", error->message);
229 g_error_free (error);
231 g_signal_connect (dialog, "response",
232 G_CALLBACK (gtk_widget_destroy), NULL);
234 gtk_widget_show (dialog);
238 return FALSE; /* uninstall the timeout */
243 gdk_pixbuf_loader_close (pixbuf_loader, NULL);
244 g_object_unref (pixbuf_loader);
247 pixbuf_loader = gdk_pixbuf_loader_new ();
249 g_signal_connect (pixbuf_loader, "area-prepared",
250 G_CALLBACK (progressive_prepared_callback), image);
252 g_signal_connect (pixbuf_loader, "area-updated",
253 G_CALLBACK (progressive_updated_callback), image);
256 /* leave timeout installed */
261 start_progressive_loading (GtkWidget *image)
263 /* This is obviously totally contrived (we slow down loading
264 * on purpose to show how incremental loading works).
265 * The real purpose of incremental loading is the case where
266 * you are reading data from a slow source such as the network.
267 * The timeout simply simulates a slow data source by inserting
268 * pauses in the reading process.
270 load_timeout = gdk_threads_add_timeout (150,
276 cleanup_callback (GObject *object,
281 g_source_remove (load_timeout);
287 gdk_pixbuf_loader_close (pixbuf_loader, NULL);
288 g_object_unref (pixbuf_loader);
289 pixbuf_loader = NULL;
294 g_object_unref (image_stream);
300 toggle_sensitivity_callback (GtkWidget *togglebutton,
303 GtkContainer *container = user_data;
307 list = gtk_container_get_children (container);
312 /* don't disable our toggle */
313 if (GTK_WIDGET (tmp->data) != togglebutton)
314 gtk_widget_set_sensitive (GTK_WIDGET (tmp->data),
315 !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (togglebutton)));
325 do_images (GtkWidget *do_widget)
337 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
338 gtk_window_set_screen (GTK_WINDOW (window),
339 gtk_widget_get_screen (do_widget));
340 gtk_window_set_title (GTK_WINDOW (window), "Images");
342 g_signal_connect (window, "destroy",
343 G_CALLBACK (gtk_widget_destroyed), &window);
344 g_signal_connect (window, "destroy",
345 G_CALLBACK (cleanup_callback), NULL);
347 gtk_container_set_border_width (GTK_CONTAINER (window), 8);
349 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
350 gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
351 gtk_container_add (GTK_CONTAINER (window), vbox);
353 label = gtk_label_new (NULL);
354 gtk_label_set_markup (GTK_LABEL (label),
355 "<u>Image loaded from a file</u>");
356 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
358 frame = gtk_frame_new (NULL);
359 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
360 gtk_widget_set_halign (frame, GTK_ALIGN_CENTER);
361 gtk_widget_set_valign (frame, GTK_ALIGN_CENTER);
362 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
364 pixbuf = gdk_pixbuf_new_from_resource ("/images/gtk-logo-rgb.gif", NULL);
365 /* The image loading must work, we ensure that the resources are valid. */
368 image = gtk_image_new_from_pixbuf (pixbuf);
370 gtk_container_add (GTK_CONTAINER (frame), image);
375 label = gtk_label_new (NULL);
376 gtk_label_set_markup (GTK_LABEL (label),
377 "<u>Animation loaded from a file</u>");
378 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
380 frame = gtk_frame_new (NULL);
381 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
382 gtk_widget_set_halign (frame, GTK_ALIGN_CENTER);
383 gtk_widget_set_valign (frame, GTK_ALIGN_CENTER);
384 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
386 image = gtk_image_new_from_resource ("/images/floppybuddy.gif");
388 gtk_container_add (GTK_CONTAINER (frame), image);
392 label = gtk_label_new (NULL);
393 gtk_label_set_markup (GTK_LABEL (label),
394 "<u>Symbolic themed icon</u>");
395 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
397 frame = gtk_frame_new (NULL);
398 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
399 gtk_widget_set_halign (frame, GTK_ALIGN_CENTER);
400 gtk_widget_set_valign (frame, GTK_ALIGN_CENTER);
401 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
403 gicon = g_themed_icon_new_with_default_fallbacks ("battery-caution-charging-symbolic");
404 image = gtk_image_new_from_gicon (gicon, GTK_ICON_SIZE_DIALOG);
406 gtk_container_add (GTK_CONTAINER (frame), image);
411 label = gtk_label_new (NULL);
412 gtk_label_set_markup (GTK_LABEL (label),
413 "<u>Progressive image loading</u>");
414 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
416 frame = gtk_frame_new (NULL);
417 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
418 gtk_widget_set_halign (frame, GTK_ALIGN_CENTER);
419 gtk_widget_set_valign (frame, GTK_ALIGN_CENTER);
420 gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
422 /* Create an empty image for now; the progressive loader
423 * will create the pixbuf and fill it in.
425 image = gtk_image_new_from_pixbuf (NULL);
426 gtk_container_add (GTK_CONTAINER (frame), image);
428 start_progressive_loading (image);
430 /* Sensitivity control */
431 button = gtk_toggle_button_new_with_mnemonic ("_Insensitive");
432 gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
434 g_signal_connect (button, "toggled",
435 G_CALLBACK (toggle_sensitivity_callback),
439 if (!gtk_widget_get_visible (window))
441 gtk_widget_show_all (window);
445 gtk_widget_destroy (window);