2 /* testpixbuf -- test program for gdk-pixbuf code
3 * Copyright (C) 1999 Mark Crichton, Larry Ewing
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
29 typedef struct _LoadContext LoadContext
;
35 GdkPixbufLoader
*pixbuf_loader
;
41 destroy_context (gpointer data
)
43 LoadContext
*lc
= data
;
45 g_free (lc
->filename
);
48 g_source_remove (lc
->load_timeout
);
51 fclose (lc
->image_stream
);
53 if (lc
->pixbuf_loader
)
55 gdk_pixbuf_loader_close (lc
->pixbuf_loader
, NULL
);
56 g_object_unref (lc
->pixbuf_loader
);
63 get_load_context (GtkWidget
*image
)
67 lc
= g_object_get_data (G_OBJECT (image
), "lc");
71 lc
= g_new0 (LoadContext
, 1);
73 g_object_set_data_full (G_OBJECT (image
),
83 progressive_prepared_callback (GdkPixbufLoader
* loader
,
89 image
= GTK_WIDGET (data
);
91 pixbuf
= gdk_pixbuf_loader_get_pixbuf (loader
);
93 /* Avoid displaying random memory contents, since the pixbuf
94 * isn't filled in yet.
96 gdk_pixbuf_fill (pixbuf
, 0xaaaaaaff);
98 /* Could set the pixbuf instead, if we only wanted to display
101 gtk_image_set_from_animation (GTK_IMAGE (image
),
102 gdk_pixbuf_loader_get_animation (loader
));
106 progressive_updated_callback (GdkPixbufLoader
* loader
,
107 gint x
, gint y
, gint width
, gint height
,
112 image
= GTK_WIDGET (data
);
114 /* We know the pixbuf inside the GtkImage has changed, but the image
115 * itself doesn't know this; so queue a redraw. If we wanted to be
116 * really efficient, we could use a drawing area or something
117 * instead of a GtkImage, so we could control the exact position of
118 * the pixbuf on the display, then we could queue a draw for only
119 * the updated area of the image.
122 /* We only really need to redraw if the image's animation iterator
123 * is gdk_pixbuf_animation_iter_on_currently_loading_frame(), but
127 gtk_widget_queue_draw (image
);
131 progressive_timeout (gpointer data
)
136 image
= GTK_WIDGET (data
);
137 lc
= get_load_context (image
);
139 /* This shows off fully-paranoid error handling, so looks scary.
140 * You could factor out the error handling code into a nice separate
141 * function to make things nicer.
144 if (lc
->image_stream
)
148 GError
*error
= NULL
;
150 bytes_read
= fread (buf
, 1, 256, lc
->image_stream
);
152 if (ferror (lc
->image_stream
))
156 dialog
= gtk_message_dialog_new (GTK_WINDOW (lc
->window
),
157 GTK_DIALOG_DESTROY_WITH_PARENT
,
160 "Failure reading image file 'alphatest.png': %s",
163 g_signal_connect (dialog
, "response",
164 G_CALLBACK (gtk_widget_destroy
), NULL
);
166 fclose (lc
->image_stream
);
167 lc
->image_stream
= NULL
;
169 gtk_widget_show (dialog
);
171 lc
->load_timeout
= 0;
173 return FALSE
; /* uninstall the timeout */
176 if (!gdk_pixbuf_loader_write (lc
->pixbuf_loader
,
182 dialog
= gtk_message_dialog_new (GTK_WINDOW (lc
->window
),
183 GTK_DIALOG_DESTROY_WITH_PARENT
,
186 "Failed to load image: %s",
189 g_error_free (error
);
191 g_signal_connect (dialog
, "response",
192 G_CALLBACK (gtk_widget_destroy
), NULL
);
194 fclose (lc
->image_stream
);
195 lc
->image_stream
= NULL
;
197 gtk_widget_show (dialog
);
199 lc
->load_timeout
= 0;
201 return FALSE
; /* uninstall the timeout */
204 if (feof (lc
->image_stream
))
206 fclose (lc
->image_stream
);
207 lc
->image_stream
= NULL
;
209 /* Errors can happen on close, e.g. if the image
210 * file was truncated we'll know on close that
214 if (!gdk_pixbuf_loader_close (lc
->pixbuf_loader
,
219 dialog
= gtk_message_dialog_new (GTK_WINDOW (lc
->window
),
220 GTK_DIALOG_DESTROY_WITH_PARENT
,
223 "Failed to load image: %s",
226 g_error_free (error
);
228 g_signal_connect (dialog
, "response",
229 G_CALLBACK (gtk_widget_destroy
), NULL
);
231 gtk_widget_show (dialog
);
233 g_object_unref (lc
->pixbuf_loader
);
234 lc
->pixbuf_loader
= NULL
;
236 lc
->load_timeout
= 0;
238 return FALSE
; /* uninstall the timeout */
241 g_object_unref (lc
->pixbuf_loader
);
242 lc
->pixbuf_loader
= NULL
;
247 lc
->image_stream
= fopen (lc
->filename
, "r");
249 if (lc
->image_stream
== NULL
)
253 dialog
= gtk_message_dialog_new (GTK_WINDOW (lc
->window
),
254 GTK_DIALOG_DESTROY_WITH_PARENT
,
257 "Unable to open image file '%s': %s",
261 g_signal_connect (dialog
, "response",
262 G_CALLBACK (gtk_widget_destroy
), NULL
);
264 gtk_widget_show (dialog
);
266 lc
->load_timeout
= 0;
268 return FALSE
; /* uninstall the timeout */
271 if (lc
->pixbuf_loader
)
273 gdk_pixbuf_loader_close (lc
->pixbuf_loader
, NULL
);
274 g_object_unref (lc
->pixbuf_loader
);
275 lc
->pixbuf_loader
= NULL
;
278 lc
->pixbuf_loader
= gdk_pixbuf_loader_new ();
280 g_signal_connect (lc
->pixbuf_loader
, "area_prepared",
281 G_CALLBACK (progressive_prepared_callback
), image
);
282 g_signal_connect (lc
->pixbuf_loader
, "area_updated",
283 G_CALLBACK (progressive_updated_callback
), image
);
286 /* leave timeout installed */
291 start_progressive_loading (GtkWidget
*image
)
295 lc
= get_load_context (image
);
297 /* This is obviously totally contrived (we slow down loading
298 * on purpose to show how incremental loading works).
299 * The real purpose of incremental loading is the case where
300 * you are reading data from a slow source such as the network.
301 * The timeout simply simulates a slow data source by inserting
302 * pauses in the reading process.
304 lc
->load_timeout
= gdk_threads_add_timeout (100,
310 do_image (const char *filename
)
318 gchar
*str
, *escaped
;
321 window
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
322 gtk_window_set_title (GTK_WINDOW (window
), "Image Loading");
324 gtk_container_set_border_width (GTK_CONTAINER (window
), 8);
326 vbox
= gtk_vbox_new (FALSE
, 8);
327 gtk_container_set_border_width (GTK_CONTAINER (vbox
), 8);
328 gtk_container_add (GTK_CONTAINER (window
), vbox
);
330 label
= gtk_label_new (NULL
);
331 gtk_label_set_line_wrap (GTK_LABEL (label
), TRUE
);
332 escaped
= g_markup_escape_text (filename
, -1);
333 str
= g_strdup_printf ("Progressively loading: <b>%s</b>", escaped
);
334 gtk_label_set_markup (GTK_LABEL (label
),
339 gtk_box_pack_start (GTK_BOX (vbox
), label
, FALSE
, FALSE
, 0);
341 frame
= gtk_frame_new (NULL
);
342 gtk_frame_set_shadow_type (GTK_FRAME (frame
), GTK_SHADOW_IN
);
343 /* The alignment keeps the frame from growing when users resize
346 align
= gtk_alignment_new (0.5, 0.5, 0, 0);
347 gtk_container_add (GTK_CONTAINER (align
), frame
);
348 gtk_box_pack_start (GTK_BOX (vbox
), align
, FALSE
, FALSE
, 0);
350 image
= gtk_image_new_from_pixbuf (NULL
);
351 gtk_container_add (GTK_CONTAINER (frame
), image
);
353 lc
= get_load_context (image
);
356 lc
->filename
= g_strdup (filename
);
358 start_progressive_loading (image
);
360 g_signal_connect (window
, "destroy",
361 G_CALLBACK (gtk_main_quit
), NULL
);
363 g_signal_connect (window
, "delete_event",
364 G_CALLBACK (gtk_main_quit
), NULL
);
366 gtk_widget_show_all (window
);
372 do_nonprogressive (const gchar
*filename
)
380 gchar
*str
, *escaped
;
382 window
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
383 gtk_window_set_title (GTK_WINDOW (window
), "Animation");
385 gtk_container_set_border_width (GTK_CONTAINER (window
), 8);
387 vbox
= gtk_vbox_new (FALSE
, 8);
388 gtk_container_set_border_width (GTK_CONTAINER (vbox
), 8);
389 gtk_container_add (GTK_CONTAINER (window
), vbox
);
391 label
= gtk_label_new (NULL
);
392 gtk_label_set_line_wrap (GTK_LABEL (label
), TRUE
);
393 escaped
= g_markup_escape_text (filename
, -1);
394 str
= g_strdup_printf ("Loaded from file: <b>%s</b>", escaped
);
395 gtk_label_set_markup (GTK_LABEL (label
),
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 image
= gtk_image_new_from_file (filename
);
412 gtk_container_add (GTK_CONTAINER (frame
), image
);
414 g_signal_connect (window
, "destroy",
415 G_CALLBACK (gtk_main_quit
), NULL
);
417 g_signal_connect (window
, "delete_event",
418 G_CALLBACK (gtk_main_quit
), NULL
);
420 gtk_widget_show_all (window
);
429 gtk_init (&argc
, &argv
);
435 do_nonprogressive (argv
[i
]);