forked from AuroraMiddleware/gtk
fix some shell typos
2001-05-04 Havoc Pennington <hp@redhat.com> * configure.in: fix some shell typos * gtk/gtkcolorsel.c (gtk_color_selection_destroy): warning fix * gtk/gtkimage.c: handle animations * gtk/gtkcheckbutton.c (gtk_check_button_size_request): request border_width * 2, not just border_width * gtk/gtkscale.c: add "format_value" signal to allow people to override the way values are drawn. (gtk_scale_get_value_size): fix width/height mistake, and compute size from actual displayed text, not from made-up text. * gtk/gtktexttag.c (gtk_text_tag_class_init): fix return type in signal registration * tests/testtext.c: Add "Remove all tags" menu item for testing * gtk/gtktextbuffer.c (gtk_text_buffer_remove_all_tags): implement * demos/gtk-demo/main.c (main): add hack so we can find modules without installing gtk * demos/gtk-demo/textview.c (insert_text): demo font scaling * gtk/gtkcellrenderertext.c: Add "scale" property (font scaling factor) (gtk_cell_renderer_text_set_property): remove some bogus g_object_notify * gtk/gtktexttag.c: add "scale" property which is a font scaling factor * gtk/gtktextlayout.c (add_text_attrs): add font scale attribute to layout * gtk/gtktextiter.c (gtk_text_iter_is_start): rename from gtk_text_iter_is_first 2001-05-04 Havoc Pennington <hp@redhat.com> * pixops/pixops.c (pixops_process): merge fix from stable: Patch from hoshem@mel.comcen.com.au to fix nonzero X offsets. Fixes bug #50371. * gdk-pixbuf/pixops/pixops.c (pixops_composite_nearest): merge from stable: Patch from OKADA Mitsuru <m-okada@fjb.co.jp> to fix confusion of using "src" instead of "p". (pixops_composite_color_nearest): Use a more accurate (and correct, to begin with) compositing method. This cures checks showing through on images with no alpha. * gdk-pixbuf.c (gdk_pixbuf_fill): fix bug that left some trailing bytes unfilled. * gdk-pixbuf-io.h: fix UpdatedNotifyFunc to use signed ints * gdk-pixbuf-loader.h (struct _GdkPixbufLoaderClass): Change area_updated signal to use signed ints. Removed animation-related signals. * io-gif.c, io-gif-animation.h, io-gif-animation.c: Massive rewrite action * gdk-pixbuf-animation.c: Add GdkPixbufAnimationIter to abstract all the pesky details. Remove old frame-based API. Make GdkPixbufAnimation an abstract base class, derived by the loaders.
This commit is contained in:
parent
607ac1e1b3
commit
b4e4a0ed9d
43
ChangeLog
43
ChangeLog
@ -1,3 +1,46 @@
|
||||
2001-05-04 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* configure.in: fix some shell typos
|
||||
|
||||
* gtk/gtkcolorsel.c (gtk_color_selection_destroy): warning fix
|
||||
|
||||
* gtk/gtkimage.c: handle animations
|
||||
|
||||
* gtk/gtkcheckbutton.c (gtk_check_button_size_request): request
|
||||
border_width * 2, not just border_width
|
||||
|
||||
* gtk/gtkscale.c: add "format_value" signal to allow people
|
||||
to override the way values are drawn.
|
||||
(gtk_scale_get_value_size): fix width/height mistake,
|
||||
and compute size from actual displayed text, not
|
||||
from made-up text.
|
||||
|
||||
* gtk/gtktexttag.c (gtk_text_tag_class_init): fix return type in
|
||||
signal registration
|
||||
|
||||
* tests/testtext.c: Add "Remove all tags" menu item for testing
|
||||
|
||||
* gtk/gtktextbuffer.c (gtk_text_buffer_remove_all_tags): implement
|
||||
|
||||
* demos/gtk-demo/main.c (main): add hack so we can find modules
|
||||
without installing gtk
|
||||
|
||||
* demos/gtk-demo/textview.c (insert_text): demo font scaling
|
||||
|
||||
* gtk/gtkcellrenderertext.c: Add "scale" property (font scaling
|
||||
factor)
|
||||
(gtk_cell_renderer_text_set_property): remove some bogus
|
||||
g_object_notify
|
||||
|
||||
* gtk/gtktexttag.c: add "scale" property which is a font scaling
|
||||
factor
|
||||
|
||||
* gtk/gtktextlayout.c (add_text_attrs): add font scale attribute
|
||||
to layout
|
||||
|
||||
* gtk/gtktextiter.c (gtk_text_iter_is_start): rename from
|
||||
gtk_text_iter_is_first
|
||||
|
||||
2001-01-06 Hans Breuer <hans@breuer.org>
|
||||
|
||||
* gdk/gdk.def : updated exports
|
||||
|
@ -1,3 +1,46 @@
|
||||
2001-05-04 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* configure.in: fix some shell typos
|
||||
|
||||
* gtk/gtkcolorsel.c (gtk_color_selection_destroy): warning fix
|
||||
|
||||
* gtk/gtkimage.c: handle animations
|
||||
|
||||
* gtk/gtkcheckbutton.c (gtk_check_button_size_request): request
|
||||
border_width * 2, not just border_width
|
||||
|
||||
* gtk/gtkscale.c: add "format_value" signal to allow people
|
||||
to override the way values are drawn.
|
||||
(gtk_scale_get_value_size): fix width/height mistake,
|
||||
and compute size from actual displayed text, not
|
||||
from made-up text.
|
||||
|
||||
* gtk/gtktexttag.c (gtk_text_tag_class_init): fix return type in
|
||||
signal registration
|
||||
|
||||
* tests/testtext.c: Add "Remove all tags" menu item for testing
|
||||
|
||||
* gtk/gtktextbuffer.c (gtk_text_buffer_remove_all_tags): implement
|
||||
|
||||
* demos/gtk-demo/main.c (main): add hack so we can find modules
|
||||
without installing gtk
|
||||
|
||||
* demos/gtk-demo/textview.c (insert_text): demo font scaling
|
||||
|
||||
* gtk/gtkcellrenderertext.c: Add "scale" property (font scaling
|
||||
factor)
|
||||
(gtk_cell_renderer_text_set_property): remove some bogus
|
||||
g_object_notify
|
||||
|
||||
* gtk/gtktexttag.c: add "scale" property which is a font scaling
|
||||
factor
|
||||
|
||||
* gtk/gtktextlayout.c (add_text_attrs): add font scale attribute
|
||||
to layout
|
||||
|
||||
* gtk/gtktextiter.c (gtk_text_iter_is_start): rename from
|
||||
gtk_text_iter_is_first
|
||||
|
||||
2001-01-06 Hans Breuer <hans@breuer.org>
|
||||
|
||||
* gdk/gdk.def : updated exports
|
||||
|
@ -1,3 +1,46 @@
|
||||
2001-05-04 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* configure.in: fix some shell typos
|
||||
|
||||
* gtk/gtkcolorsel.c (gtk_color_selection_destroy): warning fix
|
||||
|
||||
* gtk/gtkimage.c: handle animations
|
||||
|
||||
* gtk/gtkcheckbutton.c (gtk_check_button_size_request): request
|
||||
border_width * 2, not just border_width
|
||||
|
||||
* gtk/gtkscale.c: add "format_value" signal to allow people
|
||||
to override the way values are drawn.
|
||||
(gtk_scale_get_value_size): fix width/height mistake,
|
||||
and compute size from actual displayed text, not
|
||||
from made-up text.
|
||||
|
||||
* gtk/gtktexttag.c (gtk_text_tag_class_init): fix return type in
|
||||
signal registration
|
||||
|
||||
* tests/testtext.c: Add "Remove all tags" menu item for testing
|
||||
|
||||
* gtk/gtktextbuffer.c (gtk_text_buffer_remove_all_tags): implement
|
||||
|
||||
* demos/gtk-demo/main.c (main): add hack so we can find modules
|
||||
without installing gtk
|
||||
|
||||
* demos/gtk-demo/textview.c (insert_text): demo font scaling
|
||||
|
||||
* gtk/gtkcellrenderertext.c: Add "scale" property (font scaling
|
||||
factor)
|
||||
(gtk_cell_renderer_text_set_property): remove some bogus
|
||||
g_object_notify
|
||||
|
||||
* gtk/gtktexttag.c: add "scale" property which is a font scaling
|
||||
factor
|
||||
|
||||
* gtk/gtktextlayout.c (add_text_attrs): add font scale attribute
|
||||
to layout
|
||||
|
||||
* gtk/gtktextiter.c (gtk_text_iter_is_start): rename from
|
||||
gtk_text_iter_is_first
|
||||
|
||||
2001-01-06 Hans Breuer <hans@breuer.org>
|
||||
|
||||
* gdk/gdk.def : updated exports
|
||||
|
@ -1,3 +1,46 @@
|
||||
2001-05-04 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* configure.in: fix some shell typos
|
||||
|
||||
* gtk/gtkcolorsel.c (gtk_color_selection_destroy): warning fix
|
||||
|
||||
* gtk/gtkimage.c: handle animations
|
||||
|
||||
* gtk/gtkcheckbutton.c (gtk_check_button_size_request): request
|
||||
border_width * 2, not just border_width
|
||||
|
||||
* gtk/gtkscale.c: add "format_value" signal to allow people
|
||||
to override the way values are drawn.
|
||||
(gtk_scale_get_value_size): fix width/height mistake,
|
||||
and compute size from actual displayed text, not
|
||||
from made-up text.
|
||||
|
||||
* gtk/gtktexttag.c (gtk_text_tag_class_init): fix return type in
|
||||
signal registration
|
||||
|
||||
* tests/testtext.c: Add "Remove all tags" menu item for testing
|
||||
|
||||
* gtk/gtktextbuffer.c (gtk_text_buffer_remove_all_tags): implement
|
||||
|
||||
* demos/gtk-demo/main.c (main): add hack so we can find modules
|
||||
without installing gtk
|
||||
|
||||
* demos/gtk-demo/textview.c (insert_text): demo font scaling
|
||||
|
||||
* gtk/gtkcellrenderertext.c: Add "scale" property (font scaling
|
||||
factor)
|
||||
(gtk_cell_renderer_text_set_property): remove some bogus
|
||||
g_object_notify
|
||||
|
||||
* gtk/gtktexttag.c: add "scale" property which is a font scaling
|
||||
factor
|
||||
|
||||
* gtk/gtktextlayout.c (add_text_attrs): add font scale attribute
|
||||
to layout
|
||||
|
||||
* gtk/gtktextiter.c (gtk_text_iter_is_start): rename from
|
||||
gtk_text_iter_is_first
|
||||
|
||||
2001-01-06 Hans Breuer <hans@breuer.org>
|
||||
|
||||
* gdk/gdk.def : updated exports
|
||||
|
@ -1,3 +1,46 @@
|
||||
2001-05-04 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* configure.in: fix some shell typos
|
||||
|
||||
* gtk/gtkcolorsel.c (gtk_color_selection_destroy): warning fix
|
||||
|
||||
* gtk/gtkimage.c: handle animations
|
||||
|
||||
* gtk/gtkcheckbutton.c (gtk_check_button_size_request): request
|
||||
border_width * 2, not just border_width
|
||||
|
||||
* gtk/gtkscale.c: add "format_value" signal to allow people
|
||||
to override the way values are drawn.
|
||||
(gtk_scale_get_value_size): fix width/height mistake,
|
||||
and compute size from actual displayed text, not
|
||||
from made-up text.
|
||||
|
||||
* gtk/gtktexttag.c (gtk_text_tag_class_init): fix return type in
|
||||
signal registration
|
||||
|
||||
* tests/testtext.c: Add "Remove all tags" menu item for testing
|
||||
|
||||
* gtk/gtktextbuffer.c (gtk_text_buffer_remove_all_tags): implement
|
||||
|
||||
* demos/gtk-demo/main.c (main): add hack so we can find modules
|
||||
without installing gtk
|
||||
|
||||
* demos/gtk-demo/textview.c (insert_text): demo font scaling
|
||||
|
||||
* gtk/gtkcellrenderertext.c: Add "scale" property (font scaling
|
||||
factor)
|
||||
(gtk_cell_renderer_text_set_property): remove some bogus
|
||||
g_object_notify
|
||||
|
||||
* gtk/gtktexttag.c: add "scale" property which is a font scaling
|
||||
factor
|
||||
|
||||
* gtk/gtktextlayout.c (add_text_attrs): add font scale attribute
|
||||
to layout
|
||||
|
||||
* gtk/gtktextiter.c (gtk_text_iter_is_start): rename from
|
||||
gtk_text_iter_is_first
|
||||
|
||||
2001-01-06 Hans Breuer <hans@breuer.org>
|
||||
|
||||
* gdk/gdk.def : updated exports
|
||||
|
@ -1,3 +1,46 @@
|
||||
2001-05-04 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* configure.in: fix some shell typos
|
||||
|
||||
* gtk/gtkcolorsel.c (gtk_color_selection_destroy): warning fix
|
||||
|
||||
* gtk/gtkimage.c: handle animations
|
||||
|
||||
* gtk/gtkcheckbutton.c (gtk_check_button_size_request): request
|
||||
border_width * 2, not just border_width
|
||||
|
||||
* gtk/gtkscale.c: add "format_value" signal to allow people
|
||||
to override the way values are drawn.
|
||||
(gtk_scale_get_value_size): fix width/height mistake,
|
||||
and compute size from actual displayed text, not
|
||||
from made-up text.
|
||||
|
||||
* gtk/gtktexttag.c (gtk_text_tag_class_init): fix return type in
|
||||
signal registration
|
||||
|
||||
* tests/testtext.c: Add "Remove all tags" menu item for testing
|
||||
|
||||
* gtk/gtktextbuffer.c (gtk_text_buffer_remove_all_tags): implement
|
||||
|
||||
* demos/gtk-demo/main.c (main): add hack so we can find modules
|
||||
without installing gtk
|
||||
|
||||
* demos/gtk-demo/textview.c (insert_text): demo font scaling
|
||||
|
||||
* gtk/gtkcellrenderertext.c: Add "scale" property (font scaling
|
||||
factor)
|
||||
(gtk_cell_renderer_text_set_property): remove some bogus
|
||||
g_object_notify
|
||||
|
||||
* gtk/gtktexttag.c: add "scale" property which is a font scaling
|
||||
factor
|
||||
|
||||
* gtk/gtktextlayout.c (add_text_attrs): add font scale attribute
|
||||
to layout
|
||||
|
||||
* gtk/gtktextiter.c (gtk_text_iter_is_start): rename from
|
||||
gtk_text_iter_is_first
|
||||
|
||||
2001-01-06 Hans Breuer <hans@breuer.org>
|
||||
|
||||
* gdk/gdk.def : updated exports
|
||||
|
@ -1,3 +1,46 @@
|
||||
2001-05-04 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* configure.in: fix some shell typos
|
||||
|
||||
* gtk/gtkcolorsel.c (gtk_color_selection_destroy): warning fix
|
||||
|
||||
* gtk/gtkimage.c: handle animations
|
||||
|
||||
* gtk/gtkcheckbutton.c (gtk_check_button_size_request): request
|
||||
border_width * 2, not just border_width
|
||||
|
||||
* gtk/gtkscale.c: add "format_value" signal to allow people
|
||||
to override the way values are drawn.
|
||||
(gtk_scale_get_value_size): fix width/height mistake,
|
||||
and compute size from actual displayed text, not
|
||||
from made-up text.
|
||||
|
||||
* gtk/gtktexttag.c (gtk_text_tag_class_init): fix return type in
|
||||
signal registration
|
||||
|
||||
* tests/testtext.c: Add "Remove all tags" menu item for testing
|
||||
|
||||
* gtk/gtktextbuffer.c (gtk_text_buffer_remove_all_tags): implement
|
||||
|
||||
* demos/gtk-demo/main.c (main): add hack so we can find modules
|
||||
without installing gtk
|
||||
|
||||
* demos/gtk-demo/textview.c (insert_text): demo font scaling
|
||||
|
||||
* gtk/gtkcellrenderertext.c: Add "scale" property (font scaling
|
||||
factor)
|
||||
(gtk_cell_renderer_text_set_property): remove some bogus
|
||||
g_object_notify
|
||||
|
||||
* gtk/gtktexttag.c: add "scale" property which is a font scaling
|
||||
factor
|
||||
|
||||
* gtk/gtktextlayout.c (add_text_attrs): add font scale attribute
|
||||
to layout
|
||||
|
||||
* gtk/gtktextiter.c (gtk_text_iter_is_start): rename from
|
||||
gtk_text_iter_is_first
|
||||
|
||||
2001-01-06 Hans Breuer <hans@breuer.org>
|
||||
|
||||
* gdk/gdk.def : updated exports
|
||||
|
@ -563,18 +563,18 @@ AM_CONDITIONAL(HAVE_TIFF, test "x$LIBTIFF" != x)
|
||||
AM_CONDITIONAL(HAVE_PNG, test "x$LIBPNG" != x)
|
||||
AM_CONDITIONAL(HAVE_JPEG, test "x$LIBJPEG" != x)
|
||||
|
||||
if test $dynworks = no ; then
|
||||
if $dynworks ; then
|
||||
STATIC_LIB_DEPS="$LIBTIFF $LIBJPEG $LIBPNG"
|
||||
else
|
||||
STATIC_LIB_DEPS=
|
||||
if echo "$included_loaders" | grep "\(^\|\,\)tiff\(\$\|\,\)" > /dev/null; then
|
||||
STATIC_LIB_DEPS="STATIC_LIB_DEPS $LIBTIFF"
|
||||
STATIC_LIB_DEPS="$STATIC_LIB_DEPS $LIBTIFF"
|
||||
fi
|
||||
if echo "$included_loaders" | grep "\(^\|\,\)jpeg\(\$\|\,\)" > /dev/null; then
|
||||
STATIC_LIB_DEPS="STATIC_LIB_DEPS $LIBJPEG"
|
||||
STATIC_LIB_DEPS="$STATIC_LIB_DEPS $LIBJPEG"
|
||||
fi
|
||||
if echo "$included_loaders" | grep "\(^\|\,\)png\(\$\|\,\)" > /dev/null; then
|
||||
STATIC_LIB_DEPS="STATIC_LIB_DEPS $LIBPNG"
|
||||
STATIC_LIB_DEPS="$STATIC_LIB_DEPS $LIBPNG"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
@ -59,8 +59,10 @@ gtk_demo_SOURCES = \
|
||||
gtk_demo_DEPENDENCIES = $(DEPS)
|
||||
gtk_demo_LDADD = $(LDADDS)
|
||||
|
||||
IMAGEFILES= apple-red.png \
|
||||
IMAGEFILES= alphatest.png \
|
||||
apple-red.png \
|
||||
background.jpg \
|
||||
floppybuddy.gif \
|
||||
gnome-applets.png \
|
||||
gnome-calendar.png \
|
||||
gnome-foot.png \
|
||||
|
BIN
demos/gtk-demo/alphatest.png
Normal file
BIN
demos/gtk-demo/alphatest.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
BIN
demos/gtk-demo/floppybuddy.gif
Normal file
BIN
demos/gtk-demo/floppybuddy.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.1 KiB |
@ -8,6 +8,8 @@
|
||||
*
|
||||
* If you want to put image data in your program as a C variable,
|
||||
* use the make-inline-pixbuf program that comes with GTK+.
|
||||
* This way you won't need to depend on loading external files, your
|
||||
* application binary can be self-contained.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
@ -39,14 +41,14 @@ progressive_prepared_callback (GdkPixbufLoader* loader, gpointer data)
|
||||
|
||||
static void
|
||||
progressive_updated_callback (GdkPixbufLoader* loader,
|
||||
guint x, guint y, guint width, guint height,
|
||||
gint x, gint y, gint width, gint height,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget* image;
|
||||
|
||||
image = GTK_WIDGET (data);
|
||||
|
||||
/* We know the pixbuf inside the image has changed, but the image
|
||||
/* We know the pixbuf inside the GtkImage has changed, but the image
|
||||
* itself doesn't know this; so queue a redraw. If we wanted to be
|
||||
* really efficient, we could use a drawing area or something
|
||||
* instead of a GtkImage, so we could control the exact position of
|
||||
@ -85,7 +87,7 @@ progressive_timeout (gpointer data)
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
"Failure reading image file 'gtk-logo-rgb.gif': %s",
|
||||
"Failure reading image file 'alphatest.png': %s",
|
||||
g_strerror (errno));
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (dialog),
|
||||
@ -180,10 +182,10 @@ progressive_timeout (gpointer data)
|
||||
{
|
||||
const gchar *filename;
|
||||
|
||||
if (g_file_test ("./gtk-logo-rgb.gif", G_FILE_TEST_EXISTS))
|
||||
filename = "./gtk-logo-rgb.gif";
|
||||
if (g_file_test ("./alphatest.png", G_FILE_TEST_EXISTS))
|
||||
filename = "./alphatest.png";
|
||||
else
|
||||
filename = DEMOCODEDIR"/gtk-logo-rgb.gif";
|
||||
filename = DEMOCODEDIR"/alphatest.png";
|
||||
|
||||
image_stream = fopen (filename, "r");
|
||||
|
||||
@ -195,7 +197,7 @@ progressive_timeout (gpointer data)
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
"Unable to open image file 'gtk-logo-rgb.gif': %s",
|
||||
"Unable to open image file 'alphatest.png': %s",
|
||||
g_strerror (errno));
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (dialog),
|
||||
@ -246,7 +248,7 @@ start_progressive_loading (GtkWidget *image)
|
||||
* The timeout simply simulates a slow data source by inserting
|
||||
* pauses in the reading process.
|
||||
*/
|
||||
load_timeout = g_timeout_add (300,
|
||||
load_timeout = g_timeout_add (150,
|
||||
progressive_timeout,
|
||||
image);
|
||||
}
|
||||
@ -359,6 +361,37 @@ do_images (void)
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (frame), image);
|
||||
|
||||
|
||||
/* Animation */
|
||||
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_markup (GTK_LABEL (label),
|
||||
"<u>Animation loaded from a file</u>");
|
||||
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
||||
|
||||
frame = gtk_frame_new (NULL);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
|
||||
/* The alignment keeps the frame from growing when users resize
|
||||
* the window
|
||||
*/
|
||||
align = gtk_alignment_new (0.5, 0.5, 0, 0);
|
||||
gtk_container_add (GTK_CONTAINER (align), frame);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
|
||||
|
||||
/* We look for the image in the current directory first,
|
||||
* so you can run gtk-demo without installing GTK
|
||||
*/
|
||||
if (g_file_test ("./floppybuddy.gif", G_FILE_TEST_EXISTS))
|
||||
image = gtk_image_new_from_file ("./floppybuddy.gif");
|
||||
else
|
||||
image = gtk_image_new_from_file (DEMOCODEDIR"/floppybuddy.gif");
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (frame), image);
|
||||
|
||||
|
||||
/* Progressive */
|
||||
|
||||
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_markup (GTK_LABEL (label),
|
||||
"<u>Progressive image loading</u>");
|
||||
|
@ -465,6 +465,18 @@ main (int argc, char **argv)
|
||||
GtkWidget *tree;
|
||||
GtkTextTag *tag;
|
||||
|
||||
/* Most code in gtk-demo is intended to be exemplary, but not
|
||||
* these few lines, which are just a hack so gtk-demo will work
|
||||
* in the GTK tree without installing it.
|
||||
*/
|
||||
if (g_file_test ("../../gdk-pixbuf/.libs/libpixbufloader-pnm.so",
|
||||
G_FILE_TEST_EXISTS))
|
||||
{
|
||||
putenv ("GDK_PIXBUF_MODULEDIR=../../gdk-pixbuf/.libs");
|
||||
putenv ("GTK_IM_MODULE_FILE=../../modules/input/gtk.immodules");
|
||||
}
|
||||
/* -- End of hack -- */
|
||||
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
|
@ -84,6 +84,12 @@ create_tags (GtkTextBuffer *buffer)
|
||||
/* points times the PANGO_SCALE factor */
|
||||
"size", 30 * PANGO_SCALE, NULL);
|
||||
|
||||
gtk_text_buffer_create_tag (buffer, "xx-small",
|
||||
"scale", PANGO_SCALE_XX_SMALL, NULL);
|
||||
|
||||
gtk_text_buffer_create_tag (buffer, "x-large",
|
||||
"scale", PANGO_SCALE_X_LARGE, NULL);
|
||||
|
||||
gtk_text_buffer_create_tag (buffer, "monospace",
|
||||
"family", "monospace", NULL);
|
||||
|
||||
@ -199,7 +205,16 @@ insert_text (GtkTextBuffer *buffer)
|
||||
gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
|
||||
"big", -1,
|
||||
"big", NULL);
|
||||
gtk_text_buffer_insert (buffer, &iter, " text.\n\n", -1);
|
||||
gtk_text_buffer_insert (buffer, &iter, " text. ", -1);
|
||||
gtk_text_buffer_insert (buffer, &iter, "It's best not to hardcode specific text sizes; you can use relative sizes as with CSS, such as ", -1);
|
||||
gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
|
||||
"xx-small", -1,
|
||||
"xx-small", NULL);
|
||||
gtk_text_buffer_insert (buffer, &iter, " or ", -1);
|
||||
gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
|
||||
"x-large", -1,
|
||||
"x-large", NULL);
|
||||
gtk_text_buffer_insert (buffer, &iter, " to ensure that your program properly adapts if the user changes the default font size.\n\n", -1);
|
||||
|
||||
gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Colors. ", -1,
|
||||
"heading", NULL);
|
||||
|
@ -23,466 +23,426 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf-loader.h>
|
||||
|
||||
typedef struct {
|
||||
FILE *imagefile;
|
||||
GdkPixbufLoader *loader;
|
||||
GtkWidget **rgbwin;
|
||||
guchar *buf;
|
||||
guint timeout;
|
||||
guint readlen;
|
||||
typedef struct _LoadContext LoadContext;
|
||||
|
||||
} ProgressFileStatus;
|
||||
|
||||
|
||||
#define DEFAULT_WIDTH 24
|
||||
#define DEFAULT_HEIGHT 24
|
||||
|
||||
static const unsigned char default_image[] = {
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xae, 0xb3, 0xb3, 0xc6, 0xc9, 0xcd, 0xd7, 0xd4, 0xdf,
|
||||
0xec, 0xde, 0xf3, 0xe7, 0xcb, 0xe9, 0xd9, 0xb5, 0xd3, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xb1, 0xb7, 0xa5,
|
||||
0xb0, 0xb8, 0xad, 0xb3, 0xb9, 0xb6, 0xc1, 0xc6, 0xc8, 0xd5, 0xd3, 0xdc,
|
||||
0xec, 0xde, 0xf3, 0xe5, 0xca, 0xe6, 0xe0, 0xbb, 0xd7, 0xe1, 0xad, 0xc2,
|
||||
0xe3, 0xac, 0xa3, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xca, 0xc1, 0xa4, 0xc5, 0xc7, 0xac,
|
||||
0xb7, 0xbe, 0xaf, 0xad, 0xb4, 0xaf, 0xbd, 0xc2, 0xc3, 0xd1, 0xd0, 0xd8,
|
||||
0xec, 0xde, 0xf3, 0xe5, 0xc7, 0xe4, 0xe0, 0xb6, 0xd1, 0xe7, 0xa9, 0xb4,
|
||||
0xed, 0xcd, 0xb6, 0xd6, 0xcf, 0xae, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0x00, 0x00, 0x00, 0xdf, 0xa7, 0x9f, 0xdd, 0xbf, 0xaa, 0xcf, 0xc5, 0xa9,
|
||||
0xc1, 0xc4, 0xac, 0xb2, 0xba, 0xaf, 0xb6, 0xbb, 0xbb, 0xcd, 0xce, 0xd4,
|
||||
0xec, 0xde, 0xf3, 0xe4, 0xc4, 0xe1, 0xe0, 0xaf, 0xc7, 0xea, 0xbc, 0xae,
|
||||
0xe1, 0xd6, 0xb6, 0xc7, 0xcc, 0xae, 0xa2, 0xab, 0x9a, 0x00, 0x00, 0x00,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0x00, 0x00, 0x00, 0xe3, 0xab, 0xc0, 0xe6, 0xa3, 0xa7, 0xdf, 0xba, 0xa8,
|
||||
0xcf, 0xc5, 0xa9, 0xbd, 0xc2, 0xae, 0xad, 0xb4, 0xaf, 0xc6, 0xc9, 0xcd,
|
||||
0xec, 0xde, 0xf3, 0xe2, 0xbf, 0xdc, 0xe7, 0xa9, 0xb4, 0xe7, 0xd6, 0xb8,
|
||||
0xc7, 0xcc, 0xae, 0xac, 0xb6, 0xa6, 0x9d, 0xa8, 0x9f, 0x00, 0x00, 0x00,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
|
||||
0xd9, 0xaf, 0xcf, 0xe1, 0xb4, 0xd2, 0xe2, 0xb0, 0xcb, 0xe4, 0xa9, 0xbb,
|
||||
0xe2, 0xb2, 0xa6, 0xcf, 0xc5, 0xa9, 0x6a, 0x6a, 0x6a, 0x0d, 0x0d, 0x0d,
|
||||
0x0d, 0x0d, 0x0d, 0x6a, 0x6a, 0x6a, 0xed, 0xcd, 0xb6, 0xc7, 0xcc, 0xae,
|
||||
0xa6, 0xb1, 0xa3, 0x98, 0xa2, 0x9c, 0x8f, 0x97, 0x96, 0x7e, 0x84, 0x85,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
|
||||
0xe8, 0xc6, 0xe7, 0xe5, 0xc2, 0xe3, 0xe3, 0xbd, 0xdd, 0xe1, 0xb6, 0xd5,
|
||||
0xe2, 0xb0, 0xcb, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x6a, 0x6a, 0x6a, 0x9d, 0xa8, 0x9f,
|
||||
0x8f, 0x97, 0x96, 0x8b, 0x90, 0x92, 0x97, 0x9e, 0xa2, 0xa0, 0xa7, 0xae,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
|
||||
0xe7, 0xd3, 0xed, 0xe8, 0xd1, 0xed, 0xe8, 0xce, 0xec, 0xe9, 0xcc, 0xeb,
|
||||
0xe8, 0xc6, 0xe7, 0x0d, 0x0d, 0x0d, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x0d, 0x0d, 0x0d, 0x97, 0x9e, 0xa2,
|
||||
0xa7, 0xae, 0xb7, 0xb2, 0xb6, 0xc5, 0xba, 0xbc, 0xce, 0xbf, 0xbe, 0xd3,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
|
||||
0xe9, 0xdf, 0xf0, 0xe9, 0xdf, 0xf0, 0xe9, 0xdf, 0xf0, 0xe9, 0xdf, 0xf0,
|
||||
0xe9, 0xdf, 0xf0, 0x0d, 0x0d, 0x0d, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x0d, 0x0d, 0x0d, 0xe1, 0xd2, 0xf7,
|
||||
0xe1, 0xd2, 0xf7, 0xe1, 0xd2, 0xf7, 0xe1, 0xd2, 0xf7, 0xe1, 0xd2, 0xf7,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
|
||||
0xca, 0xc7, 0xd2, 0xc5, 0xc4, 0xcd, 0xbf, 0xbf, 0xc7, 0xb8, 0xb9, 0xc0,
|
||||
0xae, 0xaf, 0xb6, 0x6a, 0x6a, 0x6a, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x6a, 0x6a, 0x6a, 0xd5, 0xa8, 0xe1,
|
||||
0xd8, 0xb2, 0xe9, 0xd9, 0xb8, 0xed, 0xdb, 0xbd, 0xf0, 0xdc, 0xbf, 0xf1,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
|
||||
0xa4, 0xa6, 0xac, 0xa8, 0xaa, 0xaf, 0xa0, 0xa6, 0xa8, 0x98, 0x9e, 0x9c,
|
||||
0xa1, 0xa8, 0x9e, 0xb1, 0xb6, 0xa1, 0x6a, 0x6a, 0x6a, 0x0d, 0x0d, 0x0d,
|
||||
0x0d, 0x0d, 0x0d, 0x6a, 0x6a, 0x6a, 0xc0, 0x8c, 0xad, 0xcc, 0x90, 0xb5,
|
||||
0xd3, 0x94, 0xca, 0xd6, 0xa2, 0xdb, 0xd5, 0xa8, 0xe1, 0xcf, 0xa7, 0xdf,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0x00, 0x00, 0x00, 0x98, 0x9f, 0x9b, 0xa1, 0xa8, 0x9e, 0xac, 0xb3, 0xa0,
|
||||
0xb9, 0xb9, 0xa4, 0xd0, 0xb8, 0xa8, 0xc5, 0xb5, 0xb8, 0xb6, 0xbb, 0xad,
|
||||
0xe3, 0xd7, 0xb5, 0xdd, 0xb4, 0xa9, 0xcb, 0x89, 0xac, 0xc0, 0x8c, 0xad,
|
||||
0xc8, 0x91, 0xb5, 0xd1, 0x8d, 0xb7, 0xd3, 0x94, 0xca, 0x00, 0x00, 0x00,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0x00, 0x00, 0x00, 0xa1, 0xa7, 0x98, 0xb1, 0xb6, 0xa1, 0xbd, 0xb9, 0xa5,
|
||||
0xd0, 0xb8, 0xa8, 0xca, 0xb5, 0xb7, 0xb8, 0xb1, 0xb1, 0xc2, 0xc8, 0xb2,
|
||||
0xe3, 0xd7, 0xb5, 0xe1, 0xbf, 0xaf, 0xdb, 0x92, 0x9a, 0xbe, 0x82, 0xa6,
|
||||
0xc0, 0x8c, 0xad, 0xc8, 0x91, 0xb4, 0xc7, 0x8b, 0xb0, 0x00, 0x00, 0x00,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xbc, 0xb6, 0xa1, 0xd0, 0xb8, 0xa8,
|
||||
0xcd, 0xb6, 0xb7, 0xc0, 0xb4, 0xb5, 0xb1, 0xb1, 0xaa, 0xca, 0xd1, 0xb4,
|
||||
0xe3, 0xd7, 0xb5, 0xe2, 0xc1, 0xb0, 0xdb, 0xa8, 0xa3, 0xd2, 0x8a, 0xa9,
|
||||
0xb7, 0x7e, 0xa2, 0xbd, 0x89, 0xa9, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xc9, 0xaf, 0xaf,
|
||||
0xc5, 0xb5, 0xb8, 0xb8, 0xb1, 0xb1, 0xb6, 0xbb, 0xad, 0xd0, 0xd6, 0xb5,
|
||||
0xe3, 0xd7, 0xb5, 0xe2, 0xbf, 0xaf, 0xdd, 0xb4, 0xa9, 0xdb, 0x92, 0x9a,
|
||||
0xc6, 0x84, 0xa7, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xac, 0xaa, 0xa6, 0xbd, 0xc3, 0xb0, 0xd2, 0xd7, 0xb5,
|
||||
0xe3, 0xd7, 0xb5, 0xe2, 0xbf, 0xae, 0xdb, 0xb6, 0xa8, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff
|
||||
struct _LoadContext
|
||||
{
|
||||
gchar *filename;
|
||||
GtkWidget *window;
|
||||
GdkPixbufLoader *pixbuf_loader;
|
||||
guint load_timeout;
|
||||
FILE* image_stream;
|
||||
};
|
||||
|
||||
static void
|
||||
quit_func (GtkWidget *widget, gpointer dummy)
|
||||
destroy_context (gpointer data)
|
||||
{
|
||||
gtk_main_quit ();
|
||||
LoadContext *lc = data;
|
||||
|
||||
g_free (lc->filename);
|
||||
|
||||
if (lc->load_timeout)
|
||||
g_source_remove (lc->load_timeout);
|
||||
|
||||
if (lc->image_stream)
|
||||
fclose (lc->image_stream);
|
||||
|
||||
if (lc->pixbuf_loader)
|
||||
{
|
||||
gdk_pixbuf_loader_close (lc->pixbuf_loader, NULL);
|
||||
g_object_unref (G_OBJECT (lc->pixbuf_loader));
|
||||
}
|
||||
|
||||
g_free (lc);
|
||||
}
|
||||
|
||||
static LoadContext*
|
||||
get_load_context (GtkWidget *image)
|
||||
{
|
||||
LoadContext *lc;
|
||||
|
||||
lc = g_object_get_data (G_OBJECT (image), "lc");
|
||||
|
||||
if (lc == NULL)
|
||||
{
|
||||
lc = g_new0 (LoadContext, 1);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (image),
|
||||
"lc",
|
||||
lc,
|
||||
destroy_context);
|
||||
}
|
||||
|
||||
return lc;
|
||||
}
|
||||
|
||||
static void
|
||||
expose_func (GtkWidget *drawing_area, GdkEventExpose *event, gpointer data)
|
||||
progressive_prepared_callback (GdkPixbufLoader* loader,
|
||||
gpointer data)
|
||||
{
|
||||
GdkPixbuf* pixbuf;
|
||||
GtkWidget* image;
|
||||
|
||||
pixbuf = (GdkPixbuf *)gtk_object_get_data(GTK_OBJECT(drawing_area), "pixbuf");
|
||||
image = GTK_WIDGET (data);
|
||||
|
||||
if (gdk_pixbuf_get_has_alpha (pixbuf)) {
|
||||
gdk_draw_rgb_32_image (drawing_area->window,
|
||||
drawing_area->style->black_gc,
|
||||
event->area.x, event->area.y,
|
||||
event->area.width,
|
||||
event->area.height,
|
||||
GDK_RGB_DITHER_MAX,
|
||||
gdk_pixbuf_get_pixels (pixbuf)
|
||||
+ (event->area.y * gdk_pixbuf_get_rowstride (pixbuf))
|
||||
+ (event->area.x * gdk_pixbuf_get_n_channels (pixbuf)),
|
||||
gdk_pixbuf_get_rowstride (pixbuf));
|
||||
} else {
|
||||
gdk_draw_rgb_image (drawing_area->window,
|
||||
drawing_area->style->white_gc,
|
||||
event->area.x, event->area.y,
|
||||
event->area.width,
|
||||
event->area.height,
|
||||
GDK_RGB_DITHER_NORMAL,
|
||||
gdk_pixbuf_get_pixels (pixbuf)
|
||||
+ (event->area.y * gdk_pixbuf_get_rowstride (pixbuf))
|
||||
+ (event->area.x * gdk_pixbuf_get_n_channels (pixbuf)),
|
||||
gdk_pixbuf_get_rowstride (pixbuf));
|
||||
}
|
||||
pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
|
||||
|
||||
/* Avoid displaying random memory contents, since the pixbuf
|
||||
* isn't filled in yet.
|
||||
*/
|
||||
gdk_pixbuf_fill (pixbuf, 0xaaaaaaff);
|
||||
|
||||
/* Could set the pixbuf instead, if we only wanted to display
|
||||
* static images.
|
||||
*/
|
||||
gtk_image_set_from_animation (GTK_IMAGE (image),
|
||||
gdk_pixbuf_loader_get_animation (loader));
|
||||
}
|
||||
|
||||
static void
|
||||
config_func (GtkWidget *drawing_area, GdkEventConfigure *event, gpointer data)
|
||||
progressive_updated_callback (GdkPixbufLoader* loader,
|
||||
gint x, gint y, gint width, gint height,
|
||||
gpointer data)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
GtkWidget* image;
|
||||
|
||||
pixbuf = (GdkPixbuf *)gtk_object_get_data(GTK_OBJECT(drawing_area), "pixbuf");
|
||||
image = GTK_WIDGET (data);
|
||||
|
||||
#if 0
|
||||
if (((event->width) != gdk_pixbuf_get_width (pixbuf)) ||
|
||||
((event->height) != gdk_pixbuf_get_height (pixbuf)))
|
||||
gdk_pixbuf_scale(pixbuf, event->width, event->height);
|
||||
#endif
|
||||
/* We know the pixbuf inside the GtkImage has changed, but the image
|
||||
* itself doesn't know this; so queue a redraw. If we wanted to be
|
||||
* really efficient, we could use a drawing area or something
|
||||
* instead of a GtkImage, so we could control the exact position of
|
||||
* the pixbuf on the display, then we could queue a draw for only
|
||||
* the updated area of the image.
|
||||
*/
|
||||
|
||||
/* We only really need to redraw if the image's animation iterator
|
||||
* is gdk_pixbuf_animation_iter_on_currently_loading_frame(), but
|
||||
* who cares.
|
||||
*/
|
||||
|
||||
gtk_widget_queue_draw (image);
|
||||
}
|
||||
|
||||
static gint
|
||||
progressive_timeout (gpointer data)
|
||||
{
|
||||
GtkWidget *image;
|
||||
LoadContext *lc;
|
||||
|
||||
image = GTK_WIDGET (data);
|
||||
lc = get_load_context (image);
|
||||
|
||||
/* This shows off fully-paranoid error handling, so looks scary.
|
||||
* You could factor out the error handling code into a nice separate
|
||||
* function to make things nicer.
|
||||
*/
|
||||
|
||||
if (lc->image_stream)
|
||||
{
|
||||
size_t bytes_read;
|
||||
guchar buf[256];
|
||||
GError *error = NULL;
|
||||
|
||||
bytes_read = fread (buf, 1, 256, lc->image_stream);
|
||||
|
||||
if (ferror (lc->image_stream))
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
|
||||
dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
"Failure reading image file 'alphatest.png': %s",
|
||||
g_strerror (errno));
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (dialog),
|
||||
"response",
|
||||
GTK_SIGNAL_FUNC (gtk_widget_destroy),
|
||||
NULL);
|
||||
|
||||
fclose (lc->image_stream);
|
||||
lc->image_stream = NULL;
|
||||
|
||||
gtk_widget_show (dialog);
|
||||
|
||||
lc->load_timeout = 0;
|
||||
|
||||
return FALSE; /* uninstall the timeout */
|
||||
}
|
||||
|
||||
if (!gdk_pixbuf_loader_write (lc->pixbuf_loader,
|
||||
buf, bytes_read,
|
||||
&error))
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
|
||||
dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
"Failed to load image: %s",
|
||||
error->message);
|
||||
|
||||
g_error_free (error);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (dialog),
|
||||
"response",
|
||||
GTK_SIGNAL_FUNC (gtk_widget_destroy),
|
||||
NULL);
|
||||
|
||||
fclose (lc->image_stream);
|
||||
lc->image_stream = NULL;
|
||||
|
||||
gtk_widget_show (dialog);
|
||||
|
||||
lc->load_timeout = 0;
|
||||
|
||||
return FALSE; /* uninstall the timeout */
|
||||
}
|
||||
|
||||
if (feof (lc->image_stream))
|
||||
{
|
||||
fclose (lc->image_stream);
|
||||
lc->image_stream = NULL;
|
||||
|
||||
/* Errors can happen on close, e.g. if the image
|
||||
* file was truncated we'll know on close that
|
||||
* it was incomplete.
|
||||
*/
|
||||
error = NULL;
|
||||
if (!gdk_pixbuf_loader_close (lc->pixbuf_loader,
|
||||
&error))
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
|
||||
dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
"Failed to load image: %s",
|
||||
error->message);
|
||||
|
||||
g_error_free (error);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (dialog),
|
||||
"response",
|
||||
GTK_SIGNAL_FUNC (gtk_widget_destroy),
|
||||
NULL);
|
||||
|
||||
gtk_widget_show (dialog);
|
||||
|
||||
g_object_unref (G_OBJECT (lc->pixbuf_loader));
|
||||
lc->pixbuf_loader = NULL;
|
||||
|
||||
lc->load_timeout = 0;
|
||||
|
||||
return FALSE; /* uninstall the timeout */
|
||||
}
|
||||
|
||||
g_object_unref (G_OBJECT (lc->pixbuf_loader));
|
||||
lc->pixbuf_loader = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lc->image_stream = fopen (lc->filename, "r");
|
||||
|
||||
if (lc->image_stream == NULL)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
|
||||
dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
"Unable to open image file '%s': %s",
|
||||
lc->filename,
|
||||
g_strerror (errno));
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (dialog),
|
||||
"response",
|
||||
GTK_SIGNAL_FUNC (gtk_widget_destroy),
|
||||
NULL);
|
||||
|
||||
gtk_widget_show (dialog);
|
||||
|
||||
lc->load_timeout = 0;
|
||||
|
||||
return FALSE; /* uninstall the timeout */
|
||||
}
|
||||
|
||||
if (lc->pixbuf_loader)
|
||||
{
|
||||
gdk_pixbuf_loader_close (lc->pixbuf_loader, NULL);
|
||||
g_object_unref (G_OBJECT (lc->pixbuf_loader));
|
||||
lc->pixbuf_loader = NULL;
|
||||
}
|
||||
|
||||
lc->pixbuf_loader = gdk_pixbuf_loader_new ();
|
||||
|
||||
g_signal_connect_data (G_OBJECT (lc->pixbuf_loader),
|
||||
"area_prepared",
|
||||
G_CALLBACK (progressive_prepared_callback),
|
||||
image,
|
||||
NULL, FALSE, FALSE);
|
||||
|
||||
g_signal_connect_data (G_OBJECT (lc->pixbuf_loader),
|
||||
"area_updated",
|
||||
G_CALLBACK (progressive_updated_callback),
|
||||
image,
|
||||
NULL, FALSE, FALSE);
|
||||
}
|
||||
|
||||
/* leave timeout installed */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
start_progressive_loading (GtkWidget *image)
|
||||
{
|
||||
LoadContext *lc;
|
||||
|
||||
lc = get_load_context (image);
|
||||
|
||||
/* This is obviously totally contrived (we slow down loading
|
||||
* on purpose to show how incremental loading works).
|
||||
* The real purpose of incremental loading is the case where
|
||||
* you are reading data from a slow source such as the network.
|
||||
* The timeout simply simulates a slow data source by inserting
|
||||
* pauses in the reading process.
|
||||
*/
|
||||
lc->load_timeout = g_timeout_add (100,
|
||||
progressive_timeout,
|
||||
image);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
new_testrgb_window (GdkPixbuf *pixbuf, gchar *title)
|
||||
do_image (const char *filename)
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkWidget *frame;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *temp_box;
|
||||
GtkWidget *button;
|
||||
GtkWidget *drawing_area;
|
||||
gint w, h;
|
||||
GtkWidget *image;
|
||||
GtkWidget *label;
|
||||
GtkWidget *align;
|
||||
GtkWidget *window;
|
||||
gchar *str, *escaped;
|
||||
LoadContext *lc;
|
||||
|
||||
w = gdk_pixbuf_get_width (pixbuf);
|
||||
h = gdk_pixbuf_get_height (pixbuf);
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Image Loading");
|
||||
|
||||
window = gtk_widget_new (gtk_window_get_type (),
|
||||
"GtkObject::user_data", NULL,
|
||||
"GtkWindow::type", GTK_WINDOW_TOPLEVEL,
|
||||
"GtkWindow::title", "testrgb",
|
||||
"GtkWindow::allow_shrink", TRUE,
|
||||
NULL);
|
||||
gtk_signal_connect (GTK_OBJECT (window), "destroy",
|
||||
(GtkSignalFunc) quit_func, NULL);
|
||||
|
||||
vbox = gtk_vbox_new (FALSE, 0);
|
||||
|
||||
if (title)
|
||||
gtk_box_pack_start (GTK_BOX (vbox), gtk_label_new (title),
|
||||
TRUE, TRUE, 0);
|
||||
|
||||
drawing_area = gtk_drawing_area_new ();
|
||||
|
||||
temp_box = gtk_hbox_new (FALSE, 0);
|
||||
gtk_widget_set_usize (GTK_WIDGET (drawing_area), w, h);
|
||||
gtk_box_pack_start (GTK_BOX (temp_box), drawing_area, FALSE, FALSE, 0);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), temp_box, FALSE, FALSE, 0);
|
||||
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT(drawing_area), "expose_event",
|
||||
GTK_SIGNAL_FUNC(expose_func), NULL);
|
||||
gtk_signal_connect (GTK_OBJECT(drawing_area), "configure_event",
|
||||
GTK_SIGNAL_FUNC (config_func), NULL);
|
||||
|
||||
gtk_object_set_data (GTK_OBJECT(drawing_area), "pixbuf", pixbuf);
|
||||
|
||||
gtk_widget_show (drawing_area);
|
||||
|
||||
button = gtk_button_new_with_label ("Quit");
|
||||
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
||||
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
|
||||
(GtkSignalFunc) gtk_widget_destroy,
|
||||
GTK_OBJECT (window));
|
||||
|
||||
gtk_widget_show (button);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (window), 8);
|
||||
|
||||
vbox = gtk_vbox_new (FALSE, 8);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
gtk_widget_show_all (vbox);
|
||||
|
||||
gtk_widget_show (window);
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
|
||||
escaped = g_markup_escape_text (filename, -1);
|
||||
str = g_strdup_printf ("Progressively loading: <b>%s</b>", escaped);
|
||||
gtk_label_set_markup (GTK_LABEL (label),
|
||||
str);
|
||||
g_free (escaped);
|
||||
g_free (str);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
||||
|
||||
frame = gtk_frame_new (NULL);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
|
||||
/* The alignment keeps the frame from growing when users resize
|
||||
* the window
|
||||
*/
|
||||
align = gtk_alignment_new (0.5, 0.5, 0, 0);
|
||||
gtk_container_add (GTK_CONTAINER (align), frame);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
|
||||
|
||||
image = gtk_image_new_from_pixbuf (NULL);
|
||||
gtk_container_add (GTK_CONTAINER (frame), image);
|
||||
|
||||
lc = get_load_context (image);
|
||||
|
||||
lc->window = window;
|
||||
lc->filename = g_strdup (filename);
|
||||
|
||||
start_progressive_loading (image);
|
||||
|
||||
gtk_widget_show_all (window);
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
static gint
|
||||
update_timeout(gpointer data)
|
||||
{
|
||||
ProgressFileStatus *status = data;
|
||||
gboolean done;
|
||||
|
||||
done = TRUE;
|
||||
if (!feof(status->imagefile)) {
|
||||
gint nbytes;
|
||||
|
||||
nbytes = fread(status->buf, 1, status->readlen,
|
||||
status->imagefile);
|
||||
|
||||
done = !gdk_pixbuf_loader_write (GDK_PIXBUF_LOADER (status->loader), status->buf, nbytes);
|
||||
|
||||
}
|
||||
|
||||
if (done) {
|
||||
gtk_widget_queue_draw(*status->rgbwin);
|
||||
gdk_pixbuf_loader_close (GDK_PIXBUF_LOADER (status->loader));
|
||||
g_object_destroy (G_OBJECT(status->loader));
|
||||
fclose (status->imagefile);
|
||||
g_free (status->buf);
|
||||
}
|
||||
|
||||
return !done;
|
||||
}
|
||||
|
||||
static void
|
||||
progressive_prepared_callback(GdkPixbufLoader* loader, gpointer data)
|
||||
do_nonprogressive (const gchar *filename)
|
||||
{
|
||||
GtkWidget** retloc = data;
|
||||
GdkPixbuf* pixbuf;
|
||||
GtkWidget *frame;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *image;
|
||||
GtkWidget *label;
|
||||
GtkWidget *align;
|
||||
GtkWidget *window;
|
||||
gchar *str, *escaped;
|
||||
|
||||
pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
|
||||
g_assert(pixbuf != NULL);
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Animation");
|
||||
|
||||
gdk_pixbuf_ref(pixbuf); /* for the RGB window */
|
||||
gtk_container_set_border_width (GTK_CONTAINER (window), 8);
|
||||
|
||||
*retloc = new_testrgb_window(pixbuf, "Progressive");
|
||||
vbox = gtk_vbox_new (FALSE, 8);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
|
||||
return;
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
|
||||
escaped = g_markup_escape_text (filename, -1);
|
||||
str = g_strdup_printf ("Loaded from file: <b>%s</b>", escaped);
|
||||
gtk_label_set_markup (GTK_LABEL (label),
|
||||
str);
|
||||
g_free (escaped);
|
||||
g_free (str);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
||||
|
||||
frame = gtk_frame_new (NULL);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
|
||||
/* The alignment keeps the frame from growing when users resize
|
||||
* the window
|
||||
*/
|
||||
align = gtk_alignment_new (0.5, 0.5, 0, 0);
|
||||
gtk_container_add (GTK_CONTAINER (align), frame);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
|
||||
|
||||
image = gtk_image_new_from_file (filename);
|
||||
gtk_container_add (GTK_CONTAINER (frame), image);
|
||||
|
||||
gtk_widget_show_all (window);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
progressive_updated_callback(GdkPixbufLoader* loader, guint x, guint y, guint width, guint height, gpointer data)
|
||||
{
|
||||
GtkWidget** window_loc = data;
|
||||
|
||||
/* g_print ("progressive_updated_callback:\n\t%d\t%d\t%d\t%d\n", x, y, width, height); */
|
||||
|
||||
if (*window_loc != NULL)
|
||||
gtk_widget_queue_draw_area(*window_loc,
|
||||
x, y, width, height);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int readlen = 4096;
|
||||
|
||||
extern void pixbuf_init();
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
int i;
|
||||
int found_valid = FALSE;
|
||||
|
||||
GdkPixbufAnimation *animation;
|
||||
|
||||
pixbuf_init ();
|
||||
gint i;
|
||||
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
gdk_rgb_set_verbose (TRUE);
|
||||
|
||||
gdk_rgb_init ();
|
||||
|
||||
gtk_widget_set_default_colormap (gdk_rgb_get_cmap ());
|
||||
|
||||
{
|
||||
char *tbf_readlen = getenv("TBF_READLEN");
|
||||
if(tbf_readlen) readlen = atoi(tbf_readlen);
|
||||
}
|
||||
|
||||
{
|
||||
char *tbf_bps = getenv("TBF_KBPS");
|
||||
guint bps;
|
||||
|
||||
if (tbf_bps) {
|
||||
bps = atoi(tbf_bps);
|
||||
g_print ("Simulating %d kBytes/sec\n", bps);
|
||||
readlen = (bps*1024)/10;
|
||||
}
|
||||
}
|
||||
|
||||
i = 1;
|
||||
if (argc == 1) {
|
||||
g_print ("USAGE: testanimation FILE1 ...\n");
|
||||
return 0;
|
||||
} else {
|
||||
for (i = 1; i < argc; i++) {
|
||||
GError *error;
|
||||
|
||||
error = NULL;
|
||||
animation = gdk_pixbuf_animation_new_from_file (argv[i],
|
||||
&error);
|
||||
|
||||
if (animation == NULL) {
|
||||
g_warning ("Failed to load animation: %s",
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
if (animation) {
|
||||
gint i = 0;
|
||||
GList *listptr;
|
||||
for (listptr = gdk_pixbuf_animation_get_frames (animation);
|
||||
listptr;
|
||||
listptr = listptr->next) {
|
||||
GdkPixbufFrame *frame;
|
||||
GdkPixbuf *pixbuf;
|
||||
gchar *title;
|
||||
|
||||
frame = listptr->data;
|
||||
pixbuf = gdk_pixbuf_frame_get_pixbuf (frame);
|
||||
|
||||
title = g_strdup_printf ("Frame %d", i);
|
||||
g_print ("Frame %d x:%d y:%d width:%d height:%d\n",
|
||||
i,
|
||||
gdk_pixbuf_frame_get_x_offset (frame),
|
||||
gdk_pixbuf_frame_get_y_offset (frame),
|
||||
gdk_pixbuf_get_width (pixbuf),
|
||||
gdk_pixbuf_get_height (pixbuf));
|
||||
new_testrgb_window (pixbuf, title);
|
||||
g_free (title);
|
||||
i++;
|
||||
}
|
||||
found_valid = TRUE;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
while (i < argc)
|
||||
{
|
||||
GtkWidget* rgb_window = NULL;
|
||||
ProgressFileStatus status;
|
||||
GdkPixbufLoader *pixbuf_loader;
|
||||
do_image (argv[i]);
|
||||
do_nonprogressive (argv[i]);
|
||||
|
||||
pixbuf_loader = gdk_pixbuf_loader_new ();
|
||||
status.loader = pixbuf_loader;
|
||||
|
||||
status.rgbwin = &rgb_window;
|
||||
|
||||
status.buf = g_malloc (readlen);
|
||||
g_signal_connect_data(G_OBJECT(pixbuf_loader),
|
||||
"area_prepared",
|
||||
GTK_SIGNAL_FUNC(progressive_prepared_callback),
|
||||
&rgb_window,
|
||||
NULL, FALSE, FALSE);
|
||||
|
||||
g_signal_connect_data(G_OBJECT(pixbuf_loader),
|
||||
"area_updated",
|
||||
GTK_SIGNAL_FUNC(progressive_updated_callback),
|
||||
&rgb_window,
|
||||
NULL, FALSE, FALSE);
|
||||
|
||||
|
||||
status.imagefile = fopen (argv[1], "r");
|
||||
g_assert (status.imagefile != NULL);
|
||||
|
||||
status.readlen = readlen;
|
||||
|
||||
status.timeout = gtk_timeout_add(100, update_timeout, &status);
|
||||
}
|
||||
#endif
|
||||
++i;
|
||||
}
|
||||
|
||||
if (found_valid)
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,4 +1,8 @@
|
||||
2001-04-20 Havoc Pennington <hp@redhat.com>
|
||||
2001-04-26 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* gtk/tmpl/gtkimage.sgml: document GtkImageType
|
||||
|
||||
* gtk/gtk-sections.txt: GtkImageType is public
|
||||
|
||||
* gdk/tmpl/images.sgml: add warning about gtk_image_new_bitmap
|
||||
|
||||
|
@ -2,15 +2,17 @@
|
||||
Animations
|
||||
|
||||
<!-- ##### SECTION Short_Description ##### -->
|
||||
Animations as multi-frame structures.
|
||||
Animated images.
|
||||
|
||||
<!-- ##### SECTION Long_Description ##### -->
|
||||
<para>
|
||||
The &gdk-pixbuf; library provides a simple mechanism to load and
|
||||
represent animations, primarily animated GIF files. Animations
|
||||
are represented as lists of #GdkPixbufFrame structures. Each
|
||||
frame structure contains a #GdkPixbuf structure and information
|
||||
about the frame's overlay mode and duration.
|
||||
The &gdk-pixbuf; library provides a simple mechanism to load and represent
|
||||
animations. An animation is conceptually a series of frames to be displayed
|
||||
over time. Each frame is the same size. The animation may not be represented
|
||||
as a series of frames internally; for example, it may be stored as a
|
||||
sprite and instructions for moving the sprite around a background. To display
|
||||
an animation you don't need to understand its representation, however; you just
|
||||
ask &gdk-pixbuf; what should be displayed at a given point in time.
|
||||
</para>
|
||||
|
||||
<!-- ##### SECTION See_Also ##### -->
|
||||
@ -18,34 +20,9 @@ Animations as multi-frame structures.
|
||||
#GdkPixbufLoader
|
||||
</para>
|
||||
|
||||
<!-- ##### ENUM GdkPixbufFrameAction ##### -->
|
||||
<para>
|
||||
Each animation frame can have several things happen to it when the
|
||||
next frame is displayed. The #GdkPixbufFrameAction determines
|
||||
this. These are essentially the overlay modes supported by GIF
|
||||
animations.
|
||||
</para>
|
||||
|
||||
@GDK_PIXBUF_FRAME_RETAIN: The previous image should remain displayed,
|
||||
and will potentially be occluded by the new frame.
|
||||
@GDK_PIXBUF_FRAME_DISPOSE: The animation will be reverted to the state
|
||||
before the frame was shown.
|
||||
@GDK_PIXBUF_FRAME_REVERT: The animation will be reverted to the first
|
||||
frame.
|
||||
|
||||
<!-- ##### STRUCT GdkPixbufFrame ##### -->
|
||||
<para>
|
||||
This structure describes a frame in a #GdkPixbufAnimation. Each
|
||||
frame consists of a #GdkPixbuf, an offset of the frame within the
|
||||
animation's bounding box, a duration, and an overlay mode or
|
||||
action.
|
||||
</para>
|
||||
|
||||
|
||||
<!-- ##### STRUCT GdkPixbufAnimation ##### -->
|
||||
<para>
|
||||
This structure describes an animation, which is represented as a
|
||||
list of #GdkPixbufFrame structures.
|
||||
This object describes an animation.
|
||||
</para>
|
||||
|
||||
|
||||
@ -76,15 +53,6 @@ frame.
|
||||
@animation:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gdk_pixbuf_animation_get_frames ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@animation:
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gdk_pixbuf_animation_get_width ##### -->
|
||||
<para>
|
||||
|
||||
@ -94,15 +62,6 @@ frame.
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gdk_pixbuf_animation_get_num_frames ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@animation:
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gdk_pixbuf_animation_get_height ##### -->
|
||||
<para>
|
||||
|
||||
@ -112,70 +71,3 @@ frame.
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gdk_pixbuf_frame_copy ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@src:
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gdk_pixbuf_frame_free ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@frame:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gdk_pixbuf_frame_get_pixbuf ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@frame:
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gdk_pixbuf_frame_get_action ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@frame:
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gdk_pixbuf_frame_get_y_offset ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@frame:
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gdk_pixbuf_frame_get_delay_time ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@frame:
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gdk_pixbuf_frame_get_x_offset ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@frame:
|
||||
@Returns: <!--
|
||||
Local variables:
|
||||
mode: sgml
|
||||
sgml-parent-document: ("../gdk-pixbuf.sgml" "book" "refsect2" "")
|
||||
End:
|
||||
-->
|
||||
|
||||
|
||||
|
@ -132,15 +132,6 @@ Application-driven progressive image loading.
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### SIGNAL GdkPixbufLoader::animation-done ##### -->
|
||||
<para>
|
||||
This signal is emitted when an animation is done loading.
|
||||
</para>
|
||||
|
||||
@gdkpixbufloader: the object which received the signal.
|
||||
<!-- # Unused Parameters # -->
|
||||
@loader: Loader which emitted the signal.
|
||||
|
||||
<!-- ##### SIGNAL GdkPixbufLoader::area-prepared ##### -->
|
||||
<para>
|
||||
This signal is emitted when the pixbuf loader has been fed the
|
||||
@ -194,15 +185,3 @@ sgml-parent-document: ("../gdk-pixbuf.sgml" "book" "refsect2" "")
|
||||
End:
|
||||
-->
|
||||
|
||||
<!-- ##### SIGNAL GdkPixbufLoader::frame-done ##### -->
|
||||
<para>
|
||||
This signal is emitted when a frame is done loading. It will be
|
||||
emitted for each frame in an animation data stream.
|
||||
</para>
|
||||
|
||||
@gdkpixbufloader: the object which received the signal.
|
||||
@arg1:
|
||||
<!-- # Unused Parameters # -->
|
||||
@loader: Loader which emitted the signal.
|
||||
@frame: Frame which just completed loading.
|
||||
|
||||
|
@ -28,6 +28,7 @@ Module Interface
|
||||
</para>
|
||||
|
||||
@pixbuf:
|
||||
@anim:
|
||||
@user_data:
|
||||
|
||||
|
||||
@ -44,24 +45,6 @@ Module Interface
|
||||
@user_data:
|
||||
|
||||
|
||||
<!-- ##### USER_FUNCTION ModuleFrameDoneNotifyFunc ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@frame:
|
||||
@user_data:
|
||||
|
||||
|
||||
<!-- ##### USER_FUNCTION ModuleAnimationDoneNotifyFunc ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@pixbuf:
|
||||
@user_data:
|
||||
|
||||
|
||||
<!-- ##### STRUCT GdkPixbufModule ##### -->
|
||||
<para>
|
||||
|
||||
|
@ -967,6 +967,7 @@ GTK_HSEPARATOR_GET_CLASS
|
||||
<FILE>gtkimage</FILE>
|
||||
<TITLE>GtkImage</TITLE>
|
||||
GtkImage
|
||||
GtkImageType
|
||||
gtk_image_get_icon_set
|
||||
gtk_image_get_image
|
||||
gtk_image_get_pixbuf
|
||||
@ -1002,7 +1003,6 @@ GtkImageImageData
|
||||
GtkImagePixbufData
|
||||
GtkImagePixmapData
|
||||
GtkImageStockData
|
||||
GtkImageType
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
@ -1621,19 +1621,3 @@ fundamental type.
|
||||
@window:
|
||||
@Returns:
|
||||
|
||||
<!-- ##### FUNCTION gtk_window_set_decorations_hint ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@window:
|
||||
@decorations:
|
||||
|
||||
<!-- ##### FUNCTION gtk_window_set_functions_hint ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@window:
|
||||
@functions:
|
||||
|
||||
|
@ -28,6 +28,24 @@ below.
|
||||
</para>
|
||||
|
||||
|
||||
<!-- ##### ENUM GtkImageType ##### -->
|
||||
<para>
|
||||
Describes the representation stored by a #GtkImage. If you want to get the image
|
||||
from the widget, you can only get the currently-stored representation. e.g. if
|
||||
the gtk_image_get_storage_type() returns #GTK_IMAGE_PIXBUF, then you can call
|
||||
gtk_image_get_pixbuf() but not gtk_image_get_stock(). For empty images, you can
|
||||
request any storage type (call any of the "get" functions), but they will all
|
||||
return %NULL values.
|
||||
</para>
|
||||
|
||||
@GTK_IMAGE_EMPTY: there is no image displayed by the widget
|
||||
@GTK_IMAGE_PIXMAP: the widget contains a #GdkPixmap
|
||||
@GTK_IMAGE_IMAGE: the widget contains a #GdkImage
|
||||
@GTK_IMAGE_PIXBUF: the widget contains a #GdkPixbuf
|
||||
@GTK_IMAGE_STOCK: the widget contains a stock icon name
|
||||
@GTK_IMAGE_ICON_SET: the widget contains a #GtkIconSet
|
||||
@GTK_IMAGE_ANIMATION:
|
||||
|
||||
<!-- ##### FUNCTION gtk_image_get_icon_set ##### -->
|
||||
<para>
|
||||
|
||||
|
@ -387,7 +387,6 @@ can define other sizes.
|
||||
|
||||
<para>
|
||||
It's also possible to use custom icons for a given state, for example:
|
||||
You can specify custom icons for specific sizes, as follows:
|
||||
<programlisting>
|
||||
stock["my-stock-item"] =
|
||||
{
|
||||
@ -496,6 +495,7 @@ This can later be composited together with other
|
||||
#GtkRcStyle structures to form a #GtkStyle.
|
||||
</para>
|
||||
|
||||
@parent_instance:
|
||||
@name:
|
||||
@bg_pixmap_name:
|
||||
@font_desc:
|
||||
|
@ -43,7 +43,9 @@ slider.</entry>
|
||||
|
||||
<!-- ##### FUNCTION gtk_scale_set_digits ##### -->
|
||||
<para>
|
||||
Sets the number of decimal places that are displayed in the value.
|
||||
Sets the number of decimal places that are displayed in the value. Also causes
|
||||
the value of the adjustment to be rounded off to this number of digits, so the
|
||||
retrieved value matches the value the user saw.
|
||||
</para>
|
||||
|
||||
@scale: a #GtkScale.
|
||||
@ -80,6 +82,15 @@ string.
|
||||
@Returns: the maximum width needed to display the value string.
|
||||
|
||||
|
||||
<!-- ##### SIGNAL GtkScale::format-value ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@scale: the object which received the signal.
|
||||
@arg1:
|
||||
@Returns:
|
||||
|
||||
<!-- ##### ARG GtkScale:digits ##### -->
|
||||
<para>
|
||||
The number of decimal places that are displayed in the value.
|
||||
|
@ -289,7 +289,7 @@ you don't want a return value.
|
||||
the callbacks.
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_signal_lookup ##### -->
|
||||
<!-- ##### MACRO gtk_signal_lookup ##### -->
|
||||
<para>
|
||||
Given the name of the signal and the type of object it connects
|
||||
to, get the signal's identifying integer. Emitting the signal
|
||||
@ -304,7 +304,7 @@ It also tries the ancestors of the given type.
|
||||
@Returns: the signal's identifying number, or 0 if no signal was found.
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_signal_name ##### -->
|
||||
<!-- ##### MACRO gtk_signal_name ##### -->
|
||||
<para>
|
||||
Given the signal's identifier, find its name.
|
||||
</para>
|
||||
@ -381,7 +381,7 @@ an array of GtkArgs instead of using C's varargs mechanism.
|
||||
followed by one which is a pointer to the return type.
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_signal_emit_stop ##### -->
|
||||
<!-- ##### MACRO gtk_signal_emit_stop ##### -->
|
||||
<para>
|
||||
This function aborts a signal's current emission.
|
||||
</para>
|
||||
@ -415,7 +415,7 @@ except it will lookup the signal id for you.
|
||||
@name: the name of the signal you wish to stop.
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_signal_connect ##### -->
|
||||
<!-- ##### MACRO gtk_signal_connect ##### -->
|
||||
<para>
|
||||
Attach a function pointer and user data to a signal for
|
||||
a particular object.
|
||||
@ -467,7 +467,7 @@ is getting pressed, this is that button.
|
||||
@d:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_signal_connect_after ##### -->
|
||||
<!-- ##### MACRO gtk_signal_connect_after ##### -->
|
||||
<para>
|
||||
Attach a function pointer and user data to a signal
|
||||
so that this handler will be called after the other handlers.
|
||||
@ -485,7 +485,7 @@ so that this handler will be called after the other handlers.
|
||||
@d:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_signal_connect_object ##### -->
|
||||
<!-- ##### MACRO gtk_signal_connect_object ##### -->
|
||||
<para>
|
||||
This function is for registering a callback that will
|
||||
call another object's callback. That is,
|
||||
@ -520,7 +520,7 @@ really pass any gpointer as the #slot_object .)
|
||||
@d:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_signal_connect_object_after ##### -->
|
||||
<!-- ##### MACRO gtk_signal_connect_object_after ##### -->
|
||||
<para>
|
||||
Attach a signal hook to a signal, passing in an alternate
|
||||
object as the first parameter, and guaranteeing
|
||||
@ -626,7 +626,7 @@ should signal the removal of this signal.
|
||||
@name: name of the signal.
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_signal_disconnect ##### -->
|
||||
<!-- ##### MACRO gtk_signal_disconnect ##### -->
|
||||
<para>
|
||||
Destroy a user-defined handler connection.
|
||||
</para>
|
||||
@ -635,7 +635,7 @@ Destroy a user-defined handler connection.
|
||||
@handler_id: the connection id.
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_signal_disconnect_by_func ##### -->
|
||||
<!-- ##### MACRO gtk_signal_disconnect_by_func ##### -->
|
||||
<para>
|
||||
Destroy all connections for a particular object, with
|
||||
the given function-pointer and user-data.
|
||||
@ -650,7 +650,7 @@ the given function-pointer and user-data.
|
||||
@d:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_signal_disconnect_by_data ##### -->
|
||||
<!-- ##### MACRO gtk_signal_disconnect_by_data ##### -->
|
||||
<para>
|
||||
Destroy all connections for a particular object, with
|
||||
the given user-data.
|
||||
@ -663,7 +663,7 @@ the given user-data.
|
||||
@d:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_signal_handler_block ##### -->
|
||||
<!-- ##### MACRO gtk_signal_handler_block ##### -->
|
||||
<para>
|
||||
Prevent an user-defined handler from being invoked. All other
|
||||
signal processing will go on as normal, but this particular
|
||||
@ -674,7 +674,7 @@ handler will ignore it.
|
||||
@handler_id: the connection id.
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_signal_handler_block_by_func ##### -->
|
||||
<!-- ##### MACRO gtk_signal_handler_block_by_func ##### -->
|
||||
<para>
|
||||
Prevent a user-defined handler from being invoked, by reference to
|
||||
the user-defined handler's function pointer and user data. (It may result in
|
||||
@ -690,7 +690,7 @@ multiple hooks being blocked, if you've called connect multiple times.)
|
||||
@d:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_signal_handler_block_by_data ##### -->
|
||||
<!-- ##### MACRO gtk_signal_handler_block_by_data ##### -->
|
||||
<para>
|
||||
Prevent all user-defined handlers with a certain user data from being invoked.
|
||||
</para>
|
||||
@ -702,7 +702,7 @@ Prevent all user-defined handlers with a certain user data from being invoked.
|
||||
@d:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_signal_handler_unblock ##### -->
|
||||
<!-- ##### MACRO gtk_signal_handler_unblock ##### -->
|
||||
<para>
|
||||
Undo a block, by connection id. Note that undoing a block doesn't
|
||||
necessarily make the hook callable, because if you block a
|
||||
@ -714,7 +714,7 @@ hook twice, you must unblock it twice.
|
||||
gtk_signal_connect(), etc.
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_signal_handler_unblock_by_func ##### -->
|
||||
<!-- ##### MACRO gtk_signal_handler_unblock_by_func ##### -->
|
||||
<para>
|
||||
Undo a block, by function pointer and data.
|
||||
Note that undoing a block doesn't
|
||||
@ -731,7 +731,7 @@ hook twice, you must unblock it twice.
|
||||
@d:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_signal_handler_unblock_by_data ##### -->
|
||||
<!-- ##### MACRO gtk_signal_handler_unblock_by_data ##### -->
|
||||
<para>
|
||||
Undo block(s), to all signals for a particular object
|
||||
with a particular user-data pointer
|
||||
@ -744,7 +744,7 @@ with a particular user-data pointer
|
||||
@d:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_signal_handler_pending ##### -->
|
||||
<!-- ##### MACRO gtk_signal_handler_pending ##### -->
|
||||
<para>
|
||||
Returns a connection id corresponding to a given signal id and object.
|
||||
</para>
|
||||
@ -766,7 +766,7 @@ handler.
|
||||
@b:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_signal_handler_pending_by_func ##### -->
|
||||
<!-- ##### MACRO gtk_signal_handler_pending_by_func ##### -->
|
||||
<para>
|
||||
Returns a connection id corresponding to a given signal id, object, function
|
||||
pointer and user data.
|
||||
|
@ -41,6 +41,7 @@ Styles
|
||||
@mid:
|
||||
@text:
|
||||
@base:
|
||||
@text_aa:
|
||||
@black:
|
||||
@white:
|
||||
@font:
|
||||
@ -54,6 +55,7 @@ Styles
|
||||
@mid_gc:
|
||||
@text_gc:
|
||||
@base_gc:
|
||||
@text_aa_gc:
|
||||
@black_gc:
|
||||
@white_gc:
|
||||
@bg_pixmap:
|
||||
@ -504,6 +506,7 @@ Styles
|
||||
@style:
|
||||
@window:
|
||||
@state_type:
|
||||
@use_text:
|
||||
@x:
|
||||
@y:
|
||||
@layout:
|
||||
@ -874,6 +877,7 @@ Styles
|
||||
@style:
|
||||
@window:
|
||||
@state_type:
|
||||
@use_text:
|
||||
@area:
|
||||
@widget:
|
||||
@detail:
|
||||
|
@ -378,15 +378,6 @@ types related to the text widget and how they work together.
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_text_iter_is_first ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@iter:
|
||||
@Returns:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_text_iter_forward_char ##### -->
|
||||
<para>
|
||||
|
||||
|
@ -58,6 +58,7 @@ Describes a type of line wrapping.
|
||||
@justification:
|
||||
@direction:
|
||||
@font:
|
||||
@font_scale:
|
||||
@left_margin:
|
||||
@indent:
|
||||
@right_margin:
|
||||
@ -279,6 +280,11 @@ Font as a #PangoFontDescription.
|
||||
|
||||
</para>
|
||||
|
||||
<!-- ##### ARG GtkTextTag:scale ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
<!-- ##### ARG GtkTextTag:size-points ##### -->
|
||||
<para>
|
||||
|
||||
@ -419,6 +425,11 @@ applies to the first character in a paragraph.
|
||||
|
||||
</para>
|
||||
|
||||
<!-- ##### ARG GtkTextTag:scale-set ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
<!-- ##### ARG GtkTextTag:justification-set ##### -->
|
||||
<para>
|
||||
|
||||
|
@ -560,7 +560,7 @@ Create a new, unique type.
|
||||
@type_info: must not be null, and @type_info->type_name must also not be null.
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_type_name ##### -->
|
||||
<!-- ##### MACRO gtk_type_name ##### -->
|
||||
<para>
|
||||
</para>
|
||||
|
||||
@ -568,7 +568,7 @@ Create a new, unique type.
|
||||
@Returns: a pointer to the name of a type, or NULL if it has none.
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_type_from_name ##### -->
|
||||
<!-- ##### MACRO gtk_type_from_name ##### -->
|
||||
<para>
|
||||
Get the internal representation of a type given its name.
|
||||
</para>
|
||||
@ -577,7 +577,7 @@ Get the internal representation of a type given its name.
|
||||
@Returns: a GtkType
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_type_parent ##### -->
|
||||
<!-- ##### MACRO gtk_type_parent ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
@ -608,7 +608,7 @@ has all the proper initializers called.
|
||||
@Returns: gpointer to a GtkTypeObject
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_type_is_a ##### -->
|
||||
<!-- ##### MACRO gtk_type_is_a ##### -->
|
||||
<para>
|
||||
Look in the type hierarchy to see if @type has @is_a_type among its
|
||||
ancestors. Do so with a simple lookup, not a loop.
|
||||
|
@ -393,6 +393,15 @@ it's larger
|
||||
@setting:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_window_set_decorations_hint ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@window:
|
||||
@decorations:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_window_set_frame_dimensions ##### -->
|
||||
<para>
|
||||
|
||||
@ -405,6 +414,15 @@ it's larger
|
||||
@bottom:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_window_set_functions_hint ##### -->
|
||||
<para>
|
||||
|
||||
</para>
|
||||
|
||||
@window:
|
||||
@functions:
|
||||
|
||||
|
||||
<!-- ##### FUNCTION gtk_window_set_has_frame ##### -->
|
||||
<para>
|
||||
|
||||
|
@ -1,3 +1,32 @@
|
||||
2001-05-04 Havoc Pennington <hp@redhat.com>
|
||||
|
||||
* pixops/pixops.c (pixops_process): merge fix from stable: Patch
|
||||
from hoshem@mel.comcen.com.au to fix nonzero X offsets. Fixes
|
||||
bug #50371.
|
||||
|
||||
* gdk-pixbuf/pixops/pixops.c (pixops_composite_nearest): merge
|
||||
from stable: Patch from OKADA Mitsuru <m-okada@fjb.co.jp> to fix
|
||||
confusion of using "src" instead of "p".
|
||||
(pixops_composite_color_nearest): Use a more accurate (and
|
||||
correct, to begin with) compositing method. This cures checks
|
||||
showing through on images with no alpha.
|
||||
|
||||
* gdk-pixbuf.c (gdk_pixbuf_fill): fix bug that left some trailing
|
||||
bytes unfilled.
|
||||
|
||||
* gdk-pixbuf-io.h: fix UpdatedNotifyFunc to use signed ints
|
||||
|
||||
* gdk-pixbuf-loader.h (struct _GdkPixbufLoaderClass): Change
|
||||
area_updated signal to use signed ints. Removed animation-related
|
||||
signals.
|
||||
|
||||
* io-gif.c, io-gif-animation.h, io-gif-animation.c: Massive
|
||||
rewrite action
|
||||
|
||||
* gdk-pixbuf-animation.c: Add GdkPixbufAnimationIter to abstract
|
||||
all the pesky details. Remove old frame-based API. Make
|
||||
GdkPixbufAnimation an abstract base class, derived by the loaders.
|
||||
|
||||
Sun Apr 22 15:51:32 2001 Owen Taylor <otaylor@redhat.com>
|
||||
|
||||
* Makefile.am (LDADDS): Add $(MATH_LIB).
|
||||
|
@ -32,8 +32,8 @@ libpixbufloader_xpm_la_LIBADD =
|
||||
#
|
||||
# The GIF loader
|
||||
#
|
||||
libpixbufloader_static_gif_la_SOURCES = io-gif.c
|
||||
libpixbufloader_gif_la_SOURCES = io-gif.c
|
||||
libpixbufloader_static_gif_la_SOURCES = io-gif.c io-gif-animation.c io-gif-animation.h
|
||||
libpixbufloader_gif_la_SOURCES = io-gif.c io-gif-animation.c io-gif-animation.h
|
||||
libpixbufloader_gif_la_LDFLAGS = -avoid-version -module
|
||||
libpixbufloader_gif_la_LIBADD =
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
|
||||
/* GdkPixbuf library - Simple animation support
|
||||
*
|
||||
* Copyright (C) 1999 The Free Software Foundation
|
||||
@ -26,12 +27,59 @@
|
||||
#include "gdk-pixbuf-io.h"
|
||||
#include "gdk-pixbuf-private.h"
|
||||
|
||||
static void gdk_pixbuf_animation_class_init (GdkPixbufAnimationClass *klass);
|
||||
static void gdk_pixbuf_animation_finalize (GObject *object);
|
||||
typedef struct _GdkPixbufNonAnim GdkPixbufNonAnim;
|
||||
typedef struct _GdkPixbufNonAnimClass GdkPixbufNonAnimClass;
|
||||
|
||||
#define GDK_TYPE_PIXBUF_NON_ANIM (gdk_pixbuf_non_anim_get_type ())
|
||||
#define GDK_PIXBUF_NON_ANIM(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnim))
|
||||
#define GDK_IS_PIXBUF_NON_ANIM(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_NON_ANIM))
|
||||
|
||||
#define GDK_PIXBUF_NON_ANIM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnimClass))
|
||||
#define GDK_IS_PIXBUF_NON_ANIM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_NON_ANIM))
|
||||
#define GDK_PIXBUF_NON_ANIM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_NON_ANIM, GdkPixbufNonAnimClass))
|
||||
|
||||
/* Private part of the GdkPixbufNonAnim structure */
|
||||
struct _GdkPixbufNonAnim {
|
||||
GdkPixbufAnimation parent_instance;
|
||||
|
||||
GdkPixbuf *pixbuf;
|
||||
};
|
||||
|
||||
struct _GdkPixbufNonAnimClass {
|
||||
GdkPixbufAnimationClass parent_class;
|
||||
|
||||
};
|
||||
|
||||
static GType gdk_pixbuf_non_anim_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
|
||||
static gpointer parent_class;
|
||||
typedef struct _GdkPixbufNonAnimIter GdkPixbufNonAnimIter;
|
||||
typedef struct _GdkPixbufNonAnimIterClass GdkPixbufNonAnimIterClass;
|
||||
|
||||
|
||||
#define GDK_TYPE_PIXBUF_NON_ANIM_ITER (gdk_pixbuf_non_anim_iter_get_type ())
|
||||
#define GDK_PIXBUF_NON_ANIM_ITER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIter))
|
||||
#define GDK_IS_PIXBUF_NON_ANIM_ITER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_NON_ANIM_ITER))
|
||||
|
||||
#define GDK_PIXBUF_NON_ANIM_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIterClass))
|
||||
#define GDK_IS_PIXBUF_NON_ANIM_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_NON_ANIM_ITER))
|
||||
#define GDK_PIXBUF_NON_ANIM_ITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_NON_ANIM_ITER, GdkPixbufNonAnimIterClass))
|
||||
|
||||
struct _GdkPixbufNonAnimIter {
|
||||
GdkPixbufAnimationIter parent_instance;
|
||||
|
||||
GdkPixbufNonAnim *non_anim;
|
||||
};
|
||||
|
||||
struct _GdkPixbufNonAnimIterClass {
|
||||
GdkPixbufAnimationIterClass parent_class;
|
||||
|
||||
};
|
||||
|
||||
static GType gdk_pixbuf_non_anim_iter_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
|
||||
GType
|
||||
gdk_pixbuf_animation_get_type (void)
|
||||
@ -43,7 +91,7 @@ gdk_pixbuf_animation_get_type (void)
|
||||
sizeof (GdkPixbufAnimationClass),
|
||||
(GBaseInitFunc) NULL,
|
||||
(GBaseFinalizeFunc) NULL,
|
||||
(GClassInitFunc) gdk_pixbuf_animation_class_init,
|
||||
(GClassInitFunc) NULL,
|
||||
NULL, /* class_finalize */
|
||||
NULL, /* class_data */
|
||||
sizeof (GdkPixbufAnimation),
|
||||
@ -59,35 +107,6 @@ gdk_pixbuf_animation_get_type (void)
|
||||
return object_type;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_pixbuf_animation_class_init (GdkPixbufAnimationClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
parent_class = g_type_class_peek_parent (klass);
|
||||
|
||||
object_class->finalize = gdk_pixbuf_animation_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_pixbuf_animation_finalize (GObject *object)
|
||||
{
|
||||
GdkPixbufAnimation *animation = GDK_PIXBUF_ANIMATION (object);
|
||||
|
||||
GList *l;
|
||||
GdkPixbufFrame *frame;
|
||||
|
||||
for (l = animation->frames; l; l = l->next) {
|
||||
frame = l->data;
|
||||
gdk_pixbuf_unref (frame->pixbuf);
|
||||
g_free (frame);
|
||||
}
|
||||
|
||||
g_list_free (animation->frames);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
@ -154,7 +173,6 @@ gdk_pixbuf_animation_new_from_file (const char *filename,
|
||||
|
||||
if (image_module->load_animation == NULL) {
|
||||
GdkPixbuf *pixbuf;
|
||||
GdkPixbufFrame *frame;
|
||||
|
||||
/* Keep this logic in sync with gdk_pixbuf_new_from_file() */
|
||||
|
||||
@ -191,20 +209,9 @@ gdk_pixbuf_animation_new_from_file (const char *filename,
|
||||
if (pixbuf == NULL)
|
||||
return NULL;
|
||||
|
||||
frame = g_new (GdkPixbufFrame, 1);
|
||||
frame->pixbuf = pixbuf;
|
||||
g_object_ref (G_OBJECT (frame->pixbuf));
|
||||
frame->x_offset = 0;
|
||||
frame->y_offset = 0;
|
||||
frame->delay_time = -1;
|
||||
frame->action = GDK_PIXBUF_FRAME_RETAIN;
|
||||
animation = gdk_pixbuf_non_anim_new (pixbuf);
|
||||
|
||||
animation = g_object_new (GDK_TYPE_PIXBUF_ANIMATION, NULL);
|
||||
|
||||
animation->n_frames = 1;
|
||||
animation->frames = g_list_prepend (NULL, frame);
|
||||
animation->width = gdk_pixbuf_get_width (pixbuf);
|
||||
animation->height = gdk_pixbuf_get_height (pixbuf);
|
||||
g_object_unref (G_OBJECT (pixbuf));
|
||||
} else {
|
||||
fseek (f, 0, SEEK_SET);
|
||||
animation = (* image_module->load_animation) (f, error);
|
||||
@ -261,6 +268,46 @@ gdk_pixbuf_animation_unref (GdkPixbufAnimation *animation)
|
||||
g_object_unref (G_OBJECT (animation));
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_pixbuf_animation_is_static_image:
|
||||
* @animation: a #GdkPixbufAnimation
|
||||
*
|
||||
* If you load a file with gdk_pixbuf_animation_new_from_file() and it turns
|
||||
* out to be a plain, unanimated image, then this function will return
|
||||
* %TRUE. Use gdk_pixbuf_animation_get_static_image() to retrieve
|
||||
* the image.
|
||||
*
|
||||
* Return value: %TRUE if the "animation" was really just an image
|
||||
**/
|
||||
gboolean
|
||||
gdk_pixbuf_animation_is_static_image (GdkPixbufAnimation *animation)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), FALSE);
|
||||
|
||||
return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->is_static_image (animation);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_pixbuf_animation_get_static_image:
|
||||
* @animation: a #GdkPixbufAnimation
|
||||
*
|
||||
* If an animation is really just a plain image (has only one frame),
|
||||
* this function returns that image. If the animation is an animation,
|
||||
* this function returns a reasonable thing to display as a static
|
||||
* unanimated image, which might be the first frame, or something more
|
||||
* sophisticated. If an animation hasn't loaded any frames yet, this
|
||||
* function will return %NULL.
|
||||
*
|
||||
* Return value: unanimated image representing the animation
|
||||
**/
|
||||
GdkPixbuf*
|
||||
gdk_pixbuf_animation_get_static_image (GdkPixbufAnimation *animation)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
|
||||
|
||||
return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_static_image (animation);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_pixbuf_animation_get_width:
|
||||
* @animation: An animation.
|
||||
@ -272,9 +319,16 @@ gdk_pixbuf_animation_unref (GdkPixbufAnimation *animation)
|
||||
int
|
||||
gdk_pixbuf_animation_get_width (GdkPixbufAnimation *animation)
|
||||
{
|
||||
g_return_val_if_fail (animation != NULL, -1);
|
||||
int width;
|
||||
|
||||
return animation->width;
|
||||
g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), 0);
|
||||
|
||||
width = 0;
|
||||
GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_size (animation,
|
||||
&width, NULL);
|
||||
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -288,179 +342,444 @@ gdk_pixbuf_animation_get_width (GdkPixbufAnimation *animation)
|
||||
int
|
||||
gdk_pixbuf_animation_get_height (GdkPixbufAnimation *animation)
|
||||
{
|
||||
g_return_val_if_fail (animation != NULL, -1);
|
||||
int height;
|
||||
|
||||
return animation->height;
|
||||
g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), 0);
|
||||
|
||||
height = 0;
|
||||
GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_size (animation,
|
||||
NULL, &height);
|
||||
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_pixbuf_animation_get_num_frames:
|
||||
* @animation: An animation.
|
||||
*
|
||||
* Queries the number of frames in a pixbuf animation.
|
||||
*
|
||||
* Return value: Number of frames in the animation.
|
||||
**/
|
||||
int
|
||||
gdk_pixbuf_animation_get_num_frames (GdkPixbufAnimation *animation)
|
||||
{
|
||||
g_return_val_if_fail (animation != NULL, -1);
|
||||
|
||||
return animation->n_frames;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_pixbuf_animation_get_frames:
|
||||
* @animation: An animation.
|
||||
* gdk_pixbuf_animation_get_iter:
|
||||
* @animation: a #GdkPixbufAnimation
|
||||
* @start_time: time when the animation starts playing
|
||||
*
|
||||
* Queries the list of frames of an animation.
|
||||
* Get an iterator for displaying an animation. The iterator provides
|
||||
* the frames that should be displayed at a given time.
|
||||
* It should be freed after use with g_object_unref().
|
||||
*
|
||||
* Return value: List of frames in the animation; this is a #GList of
|
||||
* #GdkPixbufFrame structures.
|
||||
* @start_time would normally come from g_get_current_time(), and
|
||||
* marks the beginning of animation playback. After creating an
|
||||
* iterator, you should immediately display the pixbuf returned by
|
||||
* gdk_pixbuf_animation_iter_get_pixbuf(). Then, you should install a
|
||||
* timeout (with g_timeout_add()) or by some other mechanism ensure
|
||||
* that you'll update the image after
|
||||
* gdk_pixbuf_animation_iter_get_delay_time() milliseconds. Each time
|
||||
* the image is updated, you should reinstall the timeout with the new,
|
||||
* possibly-changed delay time.
|
||||
*
|
||||
* As a shortcut, if @start_time is %NULL, the result of
|
||||
* g_get_current_time() will be used automatically.
|
||||
*
|
||||
* To update the image (i.e. possibly change the result of
|
||||
* gdk_pixbuf_animation_iter_get_pixbuf() to a new frame of the animation),
|
||||
* call gdk_pixbuf_animation_iter_advance().
|
||||
*
|
||||
* If you're using #GdkPixbufLoader, in addition to updating the image
|
||||
* after the delay time, you should also update it whenever you
|
||||
* receive the area_updated signal and
|
||||
* gdk_pixbuf_animation_iter_on_currently_loading_frame() returns
|
||||
* %TRUE. In this case, the frame currently being fed into the loader
|
||||
* has received new data, so needs to be refreshed. The delay time for
|
||||
* a frame may also be modified after an area_updated signal, for
|
||||
* example if the delay time for a frame is encoded in the data after
|
||||
* the frame itself. So your timeout should be reinstalled after any
|
||||
* area_updated signal.
|
||||
*
|
||||
* A delay time of -1 is possible, indicating "infinite."
|
||||
*
|
||||
* Return value: an iterator to move over the animation
|
||||
**/
|
||||
GList *
|
||||
gdk_pixbuf_animation_get_frames (GdkPixbufAnimation *animation)
|
||||
GdkPixbufAnimationIter*
|
||||
gdk_pixbuf_animation_get_iter (GdkPixbufAnimation *animation,
|
||||
const GTimeVal *start_time)
|
||||
{
|
||||
g_return_val_if_fail (animation != NULL, NULL);
|
||||
GTimeVal val;
|
||||
|
||||
return animation->frames;
|
||||
g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
|
||||
|
||||
|
||||
if (start_time)
|
||||
val = *start_time;
|
||||
else
|
||||
g_get_current_time (&val);
|
||||
|
||||
return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_iter (animation, &val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GType
|
||||
gdk_pixbuf_animation_iter_get_type (void)
|
||||
{
|
||||
static GType object_type = 0;
|
||||
|
||||
if (!object_type) {
|
||||
static const GTypeInfo object_info = {
|
||||
sizeof (GdkPixbufAnimationIterClass),
|
||||
(GBaseInitFunc) NULL,
|
||||
(GBaseFinalizeFunc) NULL,
|
||||
(GClassInitFunc) NULL,
|
||||
NULL, /* class_finalize */
|
||||
NULL, /* class_data */
|
||||
sizeof (GdkPixbufAnimationIter),
|
||||
0, /* n_preallocs */
|
||||
(GInstanceInitFunc) NULL,
|
||||
};
|
||||
|
||||
object_type = g_type_register_static (G_TYPE_OBJECT,
|
||||
"GdkPixbufAnimationIter",
|
||||
&object_info, 0);
|
||||
}
|
||||
|
||||
return object_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_pixbuf_frame_get_pixbuf:
|
||||
* @frame: A pixbuf animation frame.
|
||||
* gdk_pixbuf_animation_iter_get_delay_time:
|
||||
* @iter: an animation iterator
|
||||
*
|
||||
* Queries the pixbuf of an animation frame.
|
||||
* Gets the number of milliseconds the current pixbuf should be displayed,
|
||||
* or -1 if the current pixbuf should be displayed forever. g_timeout_add()
|
||||
* conveniently takes a timeout in milliseconds, so you can use a timeout
|
||||
* to schedule the next update.
|
||||
*
|
||||
* Return value: A pixbuf.
|
||||
* Return value: delay time in milliseconds (thousandths of a second)
|
||||
**/
|
||||
int
|
||||
gdk_pixbuf_animation_iter_get_delay_time (GdkPixbufAnimationIter *iter)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), -1);
|
||||
|
||||
return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_delay_time (iter);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_pixbuf_animation_iter_get_pixbuf:
|
||||
* @iter: an animation iterator
|
||||
*
|
||||
* Gets the current pixbuf which should be displayed; the pixbuf will
|
||||
* be the same size as the animation itself
|
||||
* (gdk_pixbuf_animation_get_width(),
|
||||
* gdk_pixbuf_animation_get_height()). This pixbuf should be displayed
|
||||
* for gdk_pixbuf_animation_get_delay_time() milliseconds. The caller
|
||||
* of this function does not own a reference to the returned pixbuf;
|
||||
* the returned pixbuf will become invalid when the iterator advances
|
||||
* to the next frame, which may happen anytime you call
|
||||
* gdk_pixbuf_animation_iter_advance(). Copy the pixbuf to keep it
|
||||
* (don't just add a reference), as it may get recycled as you advance
|
||||
* the iterator.
|
||||
*
|
||||
* Return value: the pixbuf to be displayed
|
||||
**/
|
||||
GdkPixbuf*
|
||||
gdk_pixbuf_frame_get_pixbuf (GdkPixbufFrame *frame)
|
||||
gdk_pixbuf_animation_iter_get_pixbuf (GdkPixbufAnimationIter *iter)
|
||||
{
|
||||
g_return_val_if_fail (frame != NULL, NULL);
|
||||
g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), NULL);
|
||||
|
||||
return frame->pixbuf;
|
||||
return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_pixbuf (iter);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_pixbuf_frame_get_x_offset:
|
||||
* @frame: A pixbuf animation frame.
|
||||
* gdk_pixbuf_animation_iter_on_currently_loading_frame:
|
||||
* @iter: a #GdkPixbufAnimationIter
|
||||
*
|
||||
* Queries the X offset of an animation frame.
|
||||
* Used to determine how to respond to the area_updated signal on
|
||||
* #GdkPixbufLoader when loading an animation. area_updated is emitted
|
||||
* for an area of the frame currently streaming in to the loader. So if
|
||||
* you're on the currently loading frame, you need to redraw the screen for
|
||||
* the updated area.
|
||||
*
|
||||
* Return value: X offset from the top left corner of the animation.
|
||||
* Return value: %TRUE if the frame we're on is partially loaded, or the last frame
|
||||
**/
|
||||
int
|
||||
gdk_pixbuf_frame_get_x_offset (GdkPixbufFrame *frame)
|
||||
gboolean
|
||||
gdk_pixbuf_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter)
|
||||
{
|
||||
g_return_val_if_fail (frame != NULL, -1);
|
||||
g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), FALSE);
|
||||
|
||||
return frame->x_offset;
|
||||
return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->on_currently_loading_frame (iter);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_pixbuf_frame_get_y_offset:
|
||||
* @frame: A pixbuf animation frame.
|
||||
* gdk_pixbuf_animation_iter_advance:
|
||||
* @iter: a #GdkPixbufAnimationIter
|
||||
* @current_time: current time
|
||||
*
|
||||
* Queries the Y offset of an animation frame.
|
||||
* Possibly advances an animation to a new frame. Chooses the frame based
|
||||
* on the start time passed to gdk_pixbuf_animation_get_iter().
|
||||
*
|
||||
* @current_time would normally come from g_get_current_time(), and
|
||||
* must be greater than or equal to the time passed to
|
||||
* gdk_pixbuf_animation_get_iter(), and must increase or remain
|
||||
* unchanged each time gdk_pixbuf_animation_iter_get_pixbuf() is
|
||||
* called. That is, you can't go backward in time; animations only
|
||||
* play forward.
|
||||
*
|
||||
* As a shortcut, pass %NULL for the current time and g_get_current_time()
|
||||
* will be invoked on your behalf. So you only need to explicitly pass
|
||||
* @current_time if you're doing something odd like playing the animation
|
||||
* at double speed.
|
||||
*
|
||||
* If this function returns %FALSE, there's no need to update the animation
|
||||
* display, assuming the display had been rendered prior to advancing;
|
||||
* if %TRUE, you need to call gdk_animation_iter_get_pixbuf() and update the
|
||||
* display with the new pixbuf.
|
||||
*
|
||||
* Returns: %TRUE if the image may need updating
|
||||
*
|
||||
* Return value: Y offset from the top left corner of the animation.
|
||||
**/
|
||||
int
|
||||
gdk_pixbuf_frame_get_y_offset (GdkPixbufFrame *frame)
|
||||
gboolean
|
||||
gdk_pixbuf_animation_iter_advance (GdkPixbufAnimationIter *iter,
|
||||
const GTimeVal *current_time)
|
||||
{
|
||||
g_return_val_if_fail (frame != NULL, -1);
|
||||
GTimeVal val;
|
||||
|
||||
return frame->y_offset;
|
||||
g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), FALSE);
|
||||
|
||||
if (current_time)
|
||||
val = *current_time;
|
||||
else
|
||||
g_get_current_time (&val);
|
||||
|
||||
return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->advance (iter, &val);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_pixbuf_frame_get_delay_time:
|
||||
* @frame: A pixbuf animation frame.
|
||||
*
|
||||
* Queries the delay time in milliseconds of an animation frame.
|
||||
*
|
||||
* Return value: Delay time in milliseconds.
|
||||
**/
|
||||
int
|
||||
gdk_pixbuf_frame_get_delay_time (GdkPixbufFrame *frame)
|
||||
{
|
||||
g_return_val_if_fail (frame != NULL, -1);
|
||||
|
||||
|
||||
return frame->delay_time;
|
||||
}
|
||||
static void gdk_pixbuf_non_anim_class_init (GdkPixbufNonAnimClass *klass);
|
||||
static void gdk_pixbuf_non_anim_finalize (GObject *object);
|
||||
|
||||
/**
|
||||
* gdk_pixbuf_frame_get_action:
|
||||
* @frame: A pixbuf animation frame.
|
||||
*
|
||||
* Queries the overlay action of an animation frame.
|
||||
*
|
||||
* Return value: Overlay action for this frame.
|
||||
**/
|
||||
GdkPixbufFrameAction
|
||||
gdk_pixbuf_frame_get_action (GdkPixbufFrame *frame)
|
||||
{
|
||||
g_return_val_if_fail (frame != NULL, GDK_PIXBUF_FRAME_RETAIN);
|
||||
static gboolean gdk_pixbuf_non_anim_is_static_image (GdkPixbufAnimation *animation);
|
||||
static GdkPixbuf* gdk_pixbuf_non_anim_get_static_image (GdkPixbufAnimation *animation);
|
||||
static void gdk_pixbuf_non_anim_get_size (GdkPixbufAnimation *anim,
|
||||
int *width,
|
||||
int *height);
|
||||
static GdkPixbufAnimationIter* gdk_pixbuf_non_anim_get_iter (GdkPixbufAnimation *anim,
|
||||
const GTimeVal *start_time);
|
||||
|
||||
return frame->action;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_pixbuf_frame_copy:
|
||||
* @src: a #GdkPixbufFrame to copy
|
||||
*
|
||||
* Copies a #GdkPixbufFrame. Free the result
|
||||
* with gdk_pixbuf_frame_free().
|
||||
*
|
||||
* Return value: a new #GdkPixbufFrame
|
||||
**/
|
||||
GdkPixbufFrame*
|
||||
gdk_pixbuf_frame_copy (GdkPixbufFrame *src)
|
||||
{
|
||||
GdkPixbufFrame *frame;
|
||||
|
||||
frame = g_new (GdkPixbufFrame, 1);
|
||||
frame->pixbuf = src->pixbuf;
|
||||
g_object_ref (G_OBJECT (frame->pixbuf));
|
||||
frame->x_offset = src->x_offset;
|
||||
frame->y_offset = src->y_offset;
|
||||
frame->delay_time = src->delay_time;
|
||||
frame->action = src->action;
|
||||
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_pixbuf_frame_free:
|
||||
* @frame: a #GdkPixbufFrame
|
||||
*
|
||||
* Frees a #GdkPixbufFrame. Don't do this with frames you got from
|
||||
* #GdkPixbufAnimation, usually the animation owns those (it doesn't
|
||||
* make a copy before returning the frame).
|
||||
**/
|
||||
void
|
||||
gdk_pixbuf_frame_free (GdkPixbufFrame *frame)
|
||||
{
|
||||
g_return_if_fail (frame != NULL);
|
||||
|
||||
g_object_unref (G_OBJECT (frame->pixbuf));
|
||||
g_free (frame);
|
||||
}
|
||||
static gpointer non_parent_class;
|
||||
|
||||
GType
|
||||
gdk_pixbuf_frame_get_type (void)
|
||||
gdk_pixbuf_non_anim_get_type (void)
|
||||
{
|
||||
static GType our_type = 0;
|
||||
static GType object_type = 0;
|
||||
|
||||
if (our_type == 0)
|
||||
our_type = g_boxed_type_register_static ("GdkPixbufFrame",
|
||||
NULL,
|
||||
gdk_pixbuf_frame_copy,
|
||||
gdk_pixbuf_frame_free,
|
||||
FALSE);
|
||||
if (!object_type) {
|
||||
static const GTypeInfo object_info = {
|
||||
sizeof (GdkPixbufNonAnimClass),
|
||||
(GBaseInitFunc) NULL,
|
||||
(GBaseFinalizeFunc) NULL,
|
||||
(GClassInitFunc) gdk_pixbuf_non_anim_class_init,
|
||||
NULL, /* class_finalize */
|
||||
NULL, /* class_data */
|
||||
sizeof (GdkPixbufNonAnim),
|
||||
0, /* n_preallocs */
|
||||
(GInstanceInitFunc) NULL,
|
||||
};
|
||||
|
||||
return our_type;
|
||||
object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION,
|
||||
"GdkPixbufNonAnim",
|
||||
&object_info, 0);
|
||||
}
|
||||
|
||||
return object_type;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_pixbuf_non_anim_class_init (GdkPixbufNonAnimClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
|
||||
|
||||
non_parent_class = g_type_class_peek_parent (klass);
|
||||
|
||||
object_class->finalize = gdk_pixbuf_non_anim_finalize;
|
||||
|
||||
anim_class->is_static_image = gdk_pixbuf_non_anim_is_static_image;
|
||||
anim_class->get_static_image = gdk_pixbuf_non_anim_get_static_image;
|
||||
anim_class->get_size = gdk_pixbuf_non_anim_get_size;
|
||||
anim_class->get_iter = gdk_pixbuf_non_anim_get_iter;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_pixbuf_non_anim_finalize (GObject *object)
|
||||
{
|
||||
GdkPixbufNonAnim *non_anim = GDK_PIXBUF_NON_ANIM (object);
|
||||
|
||||
if (non_anim->pixbuf)
|
||||
g_object_unref (G_OBJECT (non_anim->pixbuf));
|
||||
|
||||
G_OBJECT_CLASS (non_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
GdkPixbufAnimation*
|
||||
gdk_pixbuf_non_anim_new (GdkPixbuf *pixbuf)
|
||||
{
|
||||
GdkPixbufNonAnim *non_anim;
|
||||
|
||||
non_anim = g_object_new (GDK_TYPE_PIXBUF_NON_ANIM, NULL);
|
||||
|
||||
non_anim->pixbuf = pixbuf;
|
||||
|
||||
if (pixbuf)
|
||||
g_object_ref (G_OBJECT (pixbuf));
|
||||
|
||||
return GDK_PIXBUF_ANIMATION (non_anim);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_pixbuf_non_anim_is_static_image (GdkPixbufAnimation *animation)
|
||||
{
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GdkPixbuf*
|
||||
gdk_pixbuf_non_anim_get_static_image (GdkPixbufAnimation *animation)
|
||||
{
|
||||
GdkPixbufNonAnim *non_anim;
|
||||
|
||||
non_anim = GDK_PIXBUF_NON_ANIM (animation);
|
||||
|
||||
return non_anim->pixbuf;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_pixbuf_non_anim_get_size (GdkPixbufAnimation *anim,
|
||||
int *width,
|
||||
int *height)
|
||||
{
|
||||
GdkPixbufNonAnim *non_anim;
|
||||
|
||||
non_anim = GDK_PIXBUF_NON_ANIM (anim);
|
||||
|
||||
if (width)
|
||||
*width = gdk_pixbuf_get_width (non_anim->pixbuf);
|
||||
|
||||
if (height)
|
||||
*height = gdk_pixbuf_get_height (non_anim->pixbuf);
|
||||
}
|
||||
|
||||
|
||||
static GdkPixbufAnimationIter*
|
||||
gdk_pixbuf_non_anim_get_iter (GdkPixbufAnimation *anim,
|
||||
const GTimeVal *start_time)
|
||||
{
|
||||
GdkPixbufNonAnimIter *iter;
|
||||
|
||||
iter = g_object_new (GDK_TYPE_PIXBUF_NON_ANIM_ITER, NULL);
|
||||
|
||||
iter->non_anim = GDK_PIXBUF_NON_ANIM (anim);
|
||||
|
||||
g_object_ref (G_OBJECT (iter->non_anim));
|
||||
|
||||
return GDK_PIXBUF_ANIMATION_ITER (iter);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void gdk_pixbuf_non_anim_iter_class_init (GdkPixbufNonAnimIterClass *klass);
|
||||
static void gdk_pixbuf_non_anim_iter_finalize (GObject *object);
|
||||
static int gdk_pixbuf_non_anim_iter_get_delay_time (GdkPixbufAnimationIter *iter);
|
||||
static GdkPixbuf* gdk_pixbuf_non_anim_iter_get_pixbuf (GdkPixbufAnimationIter *iter);
|
||||
static gboolean gdk_pixbuf_non_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
|
||||
static gboolean gdk_pixbuf_non_anim_iter_advance (GdkPixbufAnimationIter *iter,
|
||||
const GTimeVal *current_time);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static gpointer non_iter_parent_class;
|
||||
|
||||
GType
|
||||
gdk_pixbuf_non_anim_iter_get_type (void)
|
||||
{
|
||||
static GType object_type = 0;
|
||||
|
||||
if (!object_type) {
|
||||
static const GTypeInfo object_info = {
|
||||
sizeof (GdkPixbufNonAnimIterClass),
|
||||
(GBaseInitFunc) NULL,
|
||||
(GBaseFinalizeFunc) NULL,
|
||||
(GClassInitFunc) gdk_pixbuf_non_anim_iter_class_init,
|
||||
NULL, /* class_finalize */
|
||||
NULL, /* class_data */
|
||||
sizeof (GdkPixbufNonAnimIter),
|
||||
0, /* n_preallocs */
|
||||
(GInstanceInitFunc) NULL,
|
||||
};
|
||||
|
||||
object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION_ITER,
|
||||
"GdkPixbufNonAnimIter",
|
||||
&object_info, 0);
|
||||
}
|
||||
|
||||
return object_type;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_pixbuf_non_anim_iter_class_init (GdkPixbufNonAnimIterClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GdkPixbufAnimationIterClass *anim_iter_class =
|
||||
GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
|
||||
|
||||
non_iter_parent_class = g_type_class_peek_parent (klass);
|
||||
|
||||
object_class->finalize = gdk_pixbuf_non_anim_iter_finalize;
|
||||
|
||||
anim_iter_class->get_delay_time = gdk_pixbuf_non_anim_iter_get_delay_time;
|
||||
anim_iter_class->get_pixbuf = gdk_pixbuf_non_anim_iter_get_pixbuf;
|
||||
anim_iter_class->on_currently_loading_frame = gdk_pixbuf_non_anim_iter_on_currently_loading_frame;
|
||||
anim_iter_class->advance = gdk_pixbuf_non_anim_iter_advance;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_pixbuf_non_anim_iter_finalize (GObject *object)
|
||||
{
|
||||
GdkPixbufNonAnimIter *iter = GDK_PIXBUF_NON_ANIM_ITER (object);
|
||||
|
||||
g_object_unref (G_OBJECT (iter->non_anim));
|
||||
|
||||
G_OBJECT_CLASS (non_iter_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static int
|
||||
gdk_pixbuf_non_anim_iter_get_delay_time (GdkPixbufAnimationIter *iter)
|
||||
{
|
||||
return -1; /* show only frame forever */
|
||||
}
|
||||
|
||||
static GdkPixbuf*
|
||||
gdk_pixbuf_non_anim_iter_get_pixbuf (GdkPixbufAnimationIter *iter)
|
||||
{
|
||||
return GDK_PIXBUF_NON_ANIM_ITER (iter)->non_anim->pixbuf;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gdk_pixbuf_non_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_pixbuf_non_anim_iter_advance (GdkPixbufAnimationIter *iter,
|
||||
const GTimeVal *current_time)
|
||||
{
|
||||
|
||||
/* Advancing never requires a refresh */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -39,15 +39,14 @@ extern "C" {
|
||||
|
||||
|
||||
|
||||
typedef void (* ModulePreparedNotifyFunc) (GdkPixbuf *pixbuf, gpointer user_data);
|
||||
typedef void (* ModulePreparedNotifyFunc) (GdkPixbuf *pixbuf,
|
||||
GdkPixbufAnimation *anim,
|
||||
gpointer user_data);
|
||||
typedef void (* ModuleUpdatedNotifyFunc) (GdkPixbuf *pixbuf,
|
||||
guint x, guint y,
|
||||
guint width, guint height,
|
||||
gpointer user_data);
|
||||
/* Needed only for animated images. */
|
||||
typedef void (* ModuleFrameDoneNotifyFunc) (GdkPixbufFrame *frame,
|
||||
gpointer user_data);
|
||||
typedef void (* ModuleAnimationDoneNotifyFunc) (GdkPixbuf *pixbuf,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height,
|
||||
gpointer user_data);
|
||||
|
||||
typedef struct _GdkPixbufModule GdkPixbufModule;
|
||||
@ -63,8 +62,6 @@ struct _GdkPixbufModule {
|
||||
|
||||
gpointer (* begin_load) (ModulePreparedNotifyFunc prepare_func,
|
||||
ModuleUpdatedNotifyFunc update_func,
|
||||
ModuleFrameDoneNotifyFunc frame_done_func,
|
||||
ModuleAnimationDoneNotifyFunc anim_done_func,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
gboolean (* stop_load) (gpointer context,
|
||||
|
@ -35,8 +35,6 @@
|
||||
enum {
|
||||
AREA_UPDATED,
|
||||
AREA_PREPARED,
|
||||
FRAME_DONE,
|
||||
ANIMATION_DONE,
|
||||
CLOSED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
@ -56,7 +54,6 @@ static guint pixbuf_loader_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
GdkPixbufAnimation *animation;
|
||||
gboolean closed;
|
||||
guchar header_buf[LOADER_HEADER_SIZE];
|
||||
@ -136,25 +133,6 @@ gdk_pixbuf_loader_class_init (GdkPixbufLoaderClass *class)
|
||||
G_TYPE_INT,
|
||||
G_TYPE_INT);
|
||||
|
||||
pixbuf_loader_signals[FRAME_DONE] =
|
||||
g_signal_newc ("frame_done",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GdkPixbufLoaderClass, frame_done),
|
||||
NULL, NULL,
|
||||
gdk_pixbuf_marshal_VOID__POINTER,
|
||||
G_TYPE_NONE, 1,
|
||||
GDK_TYPE_PIXBUF_FRAME);
|
||||
|
||||
pixbuf_loader_signals[ANIMATION_DONE] =
|
||||
g_signal_newc ("animation_done",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GdkPixbufLoaderClass, animation_done),
|
||||
NULL, NULL,
|
||||
gdk_pixbuf_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
pixbuf_loader_signals[CLOSED] =
|
||||
g_signal_newc ("closed",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
@ -189,9 +167,6 @@ gdk_pixbuf_loader_finalize (GObject *object)
|
||||
if (priv->animation)
|
||||
gdk_pixbuf_animation_unref (priv->animation);
|
||||
|
||||
if (priv->pixbuf)
|
||||
gdk_pixbuf_unref (priv->pixbuf);
|
||||
|
||||
g_free (priv);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
@ -199,25 +174,29 @@ gdk_pixbuf_loader_finalize (GObject *object)
|
||||
|
||||
static void
|
||||
gdk_pixbuf_loader_prepare (GdkPixbuf *pixbuf,
|
||||
GdkPixbufAnimation *anim,
|
||||
gpointer loader)
|
||||
{
|
||||
GdkPixbufLoaderPrivate *priv = NULL;
|
||||
|
||||
priv = GDK_PIXBUF_LOADER (loader)->priv;
|
||||
gdk_pixbuf_ref (pixbuf);
|
||||
|
||||
g_assert (priv->pixbuf == NULL);
|
||||
if (anim)
|
||||
g_object_ref (G_OBJECT (anim));
|
||||
else
|
||||
anim = gdk_pixbuf_non_anim_new (pixbuf);
|
||||
|
||||
priv->animation = anim;
|
||||
|
||||
priv->pixbuf = pixbuf;
|
||||
g_signal_emit (G_OBJECT (loader), pixbuf_loader_signals[AREA_PREPARED], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_pixbuf_loader_update (GdkPixbuf *pixbuf,
|
||||
guint x,
|
||||
guint y,
|
||||
guint width,
|
||||
guint height,
|
||||
gint x,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height,
|
||||
gpointer loader)
|
||||
{
|
||||
GdkPixbufLoaderPrivate *priv = NULL;
|
||||
@ -229,82 +208,8 @@ gdk_pixbuf_loader_update (GdkPixbuf *pixbuf,
|
||||
0,
|
||||
x, y,
|
||||
/* sanity check in here. Defend against an errant loader */
|
||||
MIN (width, gdk_pixbuf_get_width (priv->pixbuf)),
|
||||
MIN (height, gdk_pixbuf_get_height (priv->pixbuf)));
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_pixbuf_loader_frame_done (GdkPixbufFrame *frame,
|
||||
gpointer loader)
|
||||
{
|
||||
GdkPixbufLoaderPrivate *priv = NULL;
|
||||
|
||||
priv = GDK_PIXBUF_LOADER (loader)->priv;
|
||||
|
||||
priv->pixbuf = NULL;
|
||||
|
||||
if (priv->animation == NULL)
|
||||
{
|
||||
priv->animation = g_object_new (GDK_TYPE_PIXBUF_ANIMATION, NULL);
|
||||
|
||||
priv->animation->n_frames = 0;
|
||||
priv->animation->width = gdk_pixbuf_get_width (frame->pixbuf) + frame->x_offset;
|
||||
priv->animation->height = gdk_pixbuf_get_height (frame->pixbuf) + frame->y_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
int w, h;
|
||||
|
||||
/* update bbox size */
|
||||
w = gdk_pixbuf_get_width (frame->pixbuf) + frame->x_offset;
|
||||
h = gdk_pixbuf_get_height (frame->pixbuf) + frame->y_offset;
|
||||
|
||||
if (w > priv->animation->width) {
|
||||
priv->animation->width = w;
|
||||
}
|
||||
if (h > priv->animation->height) {
|
||||
priv->animation->height = h;
|
||||
}
|
||||
}
|
||||
|
||||
priv->animation->frames = g_list_append (priv->animation->frames, frame);
|
||||
priv->animation->n_frames++;
|
||||
g_signal_emit (G_OBJECT (loader),
|
||||
pixbuf_loader_signals[FRAME_DONE],
|
||||
0,
|
||||
frame);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_pixbuf_loader_animation_done (GdkPixbuf *pixbuf,
|
||||
gpointer loader)
|
||||
{
|
||||
GdkPixbufLoaderPrivate *priv = NULL;
|
||||
GdkPixbufFrame *frame;
|
||||
GList *current = NULL;
|
||||
gint h, w;
|
||||
|
||||
priv = GDK_PIXBUF_LOADER (loader)->priv;
|
||||
priv->pixbuf = NULL;
|
||||
|
||||
current = gdk_pixbuf_animation_get_frames (priv->animation);
|
||||
|
||||
while (current)
|
||||
{
|
||||
frame = (GdkPixbufFrame *) current->data;
|
||||
|
||||
/* update bbox size */
|
||||
w = gdk_pixbuf_get_width (frame->pixbuf) + frame->x_offset;
|
||||
h = gdk_pixbuf_get_height (frame->pixbuf) + frame->y_offset;
|
||||
|
||||
if (w > priv->animation->width)
|
||||
priv->animation->width = w;
|
||||
if (h > priv->animation->height)
|
||||
priv->animation->height = h;
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
g_signal_emit (G_OBJECT (loader), pixbuf_loader_signals[ANIMATION_DONE], 0);
|
||||
MIN (width, gdk_pixbuf_animation_get_width (priv->animation)),
|
||||
MIN (height, gdk_pixbuf_animation_get_height (priv->animation)));
|
||||
}
|
||||
|
||||
static gint
|
||||
@ -353,8 +258,6 @@ gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader,
|
||||
|
||||
priv->context = priv->image_module->begin_load (gdk_pixbuf_loader_prepare,
|
||||
gdk_pixbuf_loader_update,
|
||||
gdk_pixbuf_loader_frame_done,
|
||||
gdk_pixbuf_loader_animation_done,
|
||||
loader,
|
||||
error);
|
||||
|
||||
@ -540,13 +443,14 @@ gdk_pixbuf_loader_new_with_type (const char *image_type,
|
||||
* "area_prepared" signal has been emitted by the loader; this means
|
||||
* that enough data has been read to know the size of the image that
|
||||
* will be allocated. If the loader has not received enough data via
|
||||
* gdk_pixbuf_loader_write(), then this function returns NULL. The
|
||||
* gdk_pixbuf_loader_write(), then this function returns %NULL. The
|
||||
* returned pixbuf will be the same in all future calls to the loader,
|
||||
* so simply calling gdk_pixbuf_ref() should be sufficient to continue
|
||||
* using it. Additionally, if the loader is an animation, it will
|
||||
* return the first frame of the animation.
|
||||
* return the "static image" of the animation
|
||||
* (see gdk_pixbuf_animation_get_static_image()).
|
||||
*
|
||||
* Return value: The GdkPixbuf that the loader is creating, or NULL if not
|
||||
* Return value: The #GdkPixbuf that the loader is creating, or %NULL if not
|
||||
* enough data has been read to determine how to create the image buffer.
|
||||
**/
|
||||
GdkPixbuf *
|
||||
@ -560,19 +464,9 @@ gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader)
|
||||
priv = loader->priv;
|
||||
|
||||
if (priv->animation)
|
||||
{
|
||||
GList *list;
|
||||
|
||||
list = gdk_pixbuf_animation_get_frames (priv->animation);
|
||||
if (list != NULL)
|
||||
{
|
||||
GdkPixbufFrame *frame = list->data;
|
||||
|
||||
return gdk_pixbuf_frame_get_pixbuf (frame);
|
||||
}
|
||||
}
|
||||
|
||||
return priv->pixbuf;
|
||||
return gdk_pixbuf_animation_get_static_image (priv->animation);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -581,8 +475,9 @@ gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader)
|
||||
*
|
||||
* Queries the GdkPixbufAnimation that a pixbuf loader is currently creating.
|
||||
* In general it only makes sense to call this function afer the "area_prepared"
|
||||
* signal has been emitted by the loader. If the image is not an animation,
|
||||
* then it will return NULL.
|
||||
* signal has been emitted by the loader. If the loader doesn't have enough
|
||||
* bytes yet (hasn't emitted the area_prepared signal) this function will return
|
||||
* %NULL.
|
||||
*
|
||||
* Return value: The GdkPixbufAnimation that the loader is loading, or NULL if
|
||||
not enough data has been read to determine the information.
|
||||
|
@ -53,14 +53,14 @@ struct _GdkPixbufLoaderClass
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (*area_prepared) (GdkPixbufLoader *loader);
|
||||
|
||||
/* Last known frame needs a redraw for x, y, width, height */
|
||||
void (*area_updated) (GdkPixbufLoader *loader,
|
||||
guint x,
|
||||
guint y,
|
||||
guint width,
|
||||
guint height);
|
||||
void (*frame_done) (GdkPixbufLoader *loader,
|
||||
GdkPixbufFrame *frame);
|
||||
void (*animation_done) (GdkPixbufLoader *loader);
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
void (*closed) (GdkPixbufLoader *loader);
|
||||
};
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
|
||||
/* GdkPixbuf library - Private declarations
|
||||
*
|
||||
* Copyright (C) 1999 The Free Software Foundation
|
||||
@ -73,22 +74,6 @@ struct _GdkPixbufClass {
|
||||
|
||||
};
|
||||
|
||||
/* Private part of the GdkPixbufFrame structure */
|
||||
struct _GdkPixbufFrame {
|
||||
/* The pixbuf with this frame's image data */
|
||||
GdkPixbuf *pixbuf;
|
||||
|
||||
/* Offsets for overlaying onto the animation's area */
|
||||
int x_offset;
|
||||
int y_offset;
|
||||
|
||||
/* Frame duration in ms */
|
||||
int delay_time;
|
||||
|
||||
/* Overlay mode */
|
||||
GdkPixbufFrameAction action;
|
||||
};
|
||||
|
||||
typedef struct _GdkPixbufAnimationClass GdkPixbufAnimationClass;
|
||||
|
||||
#define GDK_PIXBUF_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_ANIMATION, GdkPixbufAnimationClass))
|
||||
@ -99,20 +84,48 @@ typedef struct _GdkPixbufAnimationClass GdkPixbufAnimationClass;
|
||||
struct _GdkPixbufAnimation {
|
||||
GObject parent_instance;
|
||||
|
||||
/* Number of frames */
|
||||
int n_frames;
|
||||
|
||||
/* List of GdkPixbufFrame structures */
|
||||
GList *frames;
|
||||
|
||||
/* bounding box size */
|
||||
int width, height;
|
||||
};
|
||||
|
||||
struct _GdkPixbufAnimationClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
gboolean (*is_static_image) (GdkPixbufAnimation *anim);
|
||||
|
||||
GdkPixbuf* (*get_static_image) (GdkPixbufAnimation *anim);
|
||||
|
||||
void (*get_size) (GdkPixbufAnimation *anim,
|
||||
int *width,
|
||||
int *height);
|
||||
|
||||
GdkPixbufAnimationIter* (*get_iter) (GdkPixbufAnimation *anim,
|
||||
const GTimeVal *start_time);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef struct _GdkPixbufAnimationIterClass GdkPixbufAnimationIterClass;
|
||||
|
||||
#define GDK_PIXBUF_ANIMATION_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_ANIMATION_ITER, GdkPixbufAnimationIterClass))
|
||||
#define GDK_IS_PIXBUF_ANIMATION_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_ANIMATION_ITER))
|
||||
#define GDK_PIXBUF_ANIMATION_ITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_ANIMATION_ITER, GdkPixbufAnimationIterClass))
|
||||
|
||||
struct _GdkPixbufAnimationIter {
|
||||
GObject parent_instance;
|
||||
|
||||
};
|
||||
|
||||
struct _GdkPixbufAnimationIterClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
int (*get_delay_time) (GdkPixbufAnimationIter *iter);
|
||||
|
||||
GdkPixbuf* (*get_pixbuf) (GdkPixbufAnimationIter *iter);
|
||||
|
||||
gboolean (*on_currently_loading_frame) (GdkPixbufAnimationIter *iter);
|
||||
|
||||
gboolean (*advance) (GdkPixbufAnimationIter *iter,
|
||||
const GTimeVal *current_time);
|
||||
};
|
||||
|
||||
|
||||
@ -125,6 +138,8 @@ typedef enum
|
||||
GDK_PIXBUF_INLINE_RLE = 1
|
||||
} GdkPixbufInlineFormat;
|
||||
|
||||
|
||||
|
||||
GdkPixbufAnimation* gdk_pixbuf_non_anim_new (GdkPixbuf *pixbuf);
|
||||
|
||||
#endif
|
||||
|
@ -121,6 +121,8 @@ gdk_pixbuf_copy_area (const GdkPixbuf *src_pixbuf,
|
||||
g_return_if_fail (dest_x >= 0 && dest_x + width <= dest_pixbuf->width);
|
||||
g_return_if_fail (dest_y >= 0 && dest_y + height <= dest_pixbuf->height);
|
||||
|
||||
g_return_if_fail (!(gdk_pixbuf_get_has_alpha (src_pixbuf) && !gdk_pixbuf_get_has_alpha (dest_pixbuf)));
|
||||
|
||||
/* This will perform format conversions automatically */
|
||||
|
||||
gdk_pixbuf_scale (src_pixbuf,
|
||||
|
@ -412,7 +412,7 @@ gdk_pixbuf_error_quark (void)
|
||||
/**
|
||||
* gdk_pixbuf_fill:
|
||||
* @pixbuf: a #GdkPixbuf
|
||||
* @pixel: RGBA pixel to clear to (0xffffff00 is opaque white, 0x000000ff transparent black)
|
||||
* @pixel: RGBA pixel to clear to (0xffffffff is opaque white, 0x00000000 transparent black)
|
||||
*
|
||||
* Clears a pixbuf to the given RGBA value, converting the RGBA value into
|
||||
* the pixbuf's pixel format. The alpha will be ignored if the pixbuf
|
||||
@ -454,7 +454,7 @@ gdk_pixbuf_fill (GdkPixbuf *pixbuf,
|
||||
|
||||
p = pixels;
|
||||
end = pixels + pixbuf->rowstride * pixbuf->height;
|
||||
end -= (pixbuf->rowstride - pixbuf->width);
|
||||
end -= (pixbuf->rowstride - pixbuf->width * pixbuf->n_channels);
|
||||
|
||||
while (p < end) {
|
||||
*p++ = r;
|
||||
|
@ -54,6 +54,7 @@ typedef enum {
|
||||
/* All of these are opaque structures */
|
||||
typedef struct _GdkPixbuf GdkPixbuf;
|
||||
typedef struct _GdkPixbufAnimation GdkPixbufAnimation;
|
||||
typedef struct _GdkPixbufAnimationIter GdkPixbufAnimationIter;
|
||||
typedef struct _GdkPixbufFrame GdkPixbufFrame;
|
||||
|
||||
#define GDK_TYPE_PIXBUF (gdk_pixbuf_get_type ())
|
||||
@ -64,6 +65,9 @@ typedef struct _GdkPixbufFrame GdkPixbufFrame;
|
||||
#define GDK_PIXBUF_ANIMATION(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_ANIMATION, GdkPixbufAnimation))
|
||||
#define GDK_IS_PIXBUF_ANIMATION(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_ANIMATION))
|
||||
|
||||
#define GDK_TYPE_PIXBUF_ANIMATION_ITER (gdk_pixbuf_animation_iter_get_type ())
|
||||
#define GDK_PIXBUF_ANIMATION_ITER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_ANIMATION_ITER, GdkPixbufAnimationIter))
|
||||
#define GDK_IS_PIXBUF_ANIMATION_ITER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_ANIMATION_ITER))
|
||||
|
||||
/* Handler that must free the pixel array */
|
||||
typedef void (* GdkPixbufDestroyNotify) (guchar *pixels, gpointer data);
|
||||
@ -255,13 +259,6 @@ GdkPixbuf *gdk_pixbuf_composite_color_simple (const GdkPixbuf *src,
|
||||
|
||||
/* Animation support */
|
||||
|
||||
/* GIF-like animation overlay modes for frames */
|
||||
typedef enum {
|
||||
GDK_PIXBUF_FRAME_RETAIN,
|
||||
GDK_PIXBUF_FRAME_DISPOSE,
|
||||
GDK_PIXBUF_FRAME_REVERT
|
||||
} GdkPixbufFrameAction;
|
||||
|
||||
GType gdk_pixbuf_animation_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GdkPixbufAnimation *gdk_pixbuf_animation_new_from_file (const char *filename,
|
||||
@ -272,20 +269,19 @@ void gdk_pixbuf_animation_unref (GdkPixbufAnimation *an
|
||||
|
||||
int gdk_pixbuf_animation_get_width (GdkPixbufAnimation *animation);
|
||||
int gdk_pixbuf_animation_get_height (GdkPixbufAnimation *animation);
|
||||
GList *gdk_pixbuf_animation_get_frames (GdkPixbufAnimation *animation);
|
||||
int gdk_pixbuf_animation_get_num_frames (GdkPixbufAnimation *animation);
|
||||
gboolean gdk_pixbuf_animation_is_static_image (GdkPixbufAnimation *animation);
|
||||
GdkPixbuf *gdk_pixbuf_animation_get_static_image (GdkPixbufAnimation *animation);
|
||||
|
||||
GdkPixbufAnimationIter *gdk_pixbuf_animation_get_iter (GdkPixbufAnimation *animation,
|
||||
const GTimeVal *start_time);
|
||||
GType gdk_pixbuf_animation_iter_get_type (void) G_GNUC_CONST;
|
||||
int gdk_pixbuf_animation_iter_get_delay_time (GdkPixbufAnimationIter *iter);
|
||||
GdkPixbuf *gdk_pixbuf_animation_iter_get_pixbuf (GdkPixbufAnimationIter *iter);
|
||||
gboolean gdk_pixbuf_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
|
||||
gboolean gdk_pixbuf_animation_iter_advance (GdkPixbufAnimationIter *iter,
|
||||
const GTimeVal *current_time);
|
||||
|
||||
/* Frame accessors */
|
||||
|
||||
GdkPixbuf *gdk_pixbuf_frame_get_pixbuf (GdkPixbufFrame *frame);
|
||||
int gdk_pixbuf_frame_get_x_offset (GdkPixbufFrame *frame);
|
||||
int gdk_pixbuf_frame_get_y_offset (GdkPixbufFrame *frame);
|
||||
int gdk_pixbuf_frame_get_delay_time (GdkPixbufFrame *frame);
|
||||
GdkPixbufFrameAction gdk_pixbuf_frame_get_action (GdkPixbufFrame *frame);
|
||||
GdkPixbufFrame *gdk_pixbuf_frame_copy (GdkPixbufFrame *src);
|
||||
void gdk_pixbuf_frame_free (GdkPixbufFrame *frame);
|
||||
GType gdk_pixbuf_frame_get_type (void) G_GNUC_CONST;
|
||||
#define GDK_TYPE_PIXBUF_FRAME gdk_pixbuf_frame_get_type ()
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf-loader.h>
|
||||
|
||||
|
@ -174,9 +174,7 @@ struct bmp_progressive_state {
|
||||
static gpointer
|
||||
gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
|
||||
ModuleUpdatedNotifyFunc updated_func,
|
||||
ModuleFrameDoneNotifyFunc frame_done_func,
|
||||
ModuleAnimationDoneNotifyFunc
|
||||
anim_done_func, gpointer user_data,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
|
||||
static gboolean gdk_pixbuf__bmp_image_stop_load(gpointer data, GError **error);
|
||||
@ -198,7 +196,7 @@ static GdkPixbuf *gdk_pixbuf__bmp_image_load(FILE * f, GError **error)
|
||||
GdkPixbuf *pb;
|
||||
|
||||
State =
|
||||
gdk_pixbuf__bmp_image_begin_load(NULL, NULL, NULL, NULL, NULL,
|
||||
gdk_pixbuf__bmp_image_begin_load(NULL, NULL, NULL,
|
||||
error);
|
||||
|
||||
if (State == NULL)
|
||||
@ -312,7 +310,7 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
|
||||
|
||||
if (State->prepared_func != NULL)
|
||||
/* Notify the client that we are ready to go */
|
||||
(*State->prepared_func) (State->pixbuf, State->user_data);
|
||||
(*State->prepared_func) (State->pixbuf, NULL, State->user_data);
|
||||
|
||||
}
|
||||
|
||||
@ -328,9 +326,7 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
|
||||
static gpointer
|
||||
gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
|
||||
ModuleUpdatedNotifyFunc updated_func,
|
||||
ModuleFrameDoneNotifyFunc frame_done_func,
|
||||
ModuleAnimationDoneNotifyFunc
|
||||
anim_done_func, gpointer user_data,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
struct bmp_progressive_state *context;
|
||||
|
557
gdk-pixbuf/io-gif-animation.c
Normal file
557
gdk-pixbuf/io-gif-animation.c
Normal file
@ -0,0 +1,557 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
|
||||
/* GdkPixbuf library - animated gif support
|
||||
*
|
||||
* Copyright (C) 1999 The Free Software Foundation
|
||||
*
|
||||
* Authors: Jonathan Blandford <jrb@redhat.com>
|
||||
* Havoc Pennington <hp@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include "gdk-pixbuf-io.h"
|
||||
#include "gdk-pixbuf-private.h"
|
||||
#include "io-gif-animation.h"
|
||||
|
||||
static void gdk_pixbuf_gif_anim_class_init (GdkPixbufGifAnimClass *klass);
|
||||
static void gdk_pixbuf_gif_anim_finalize (GObject *object);
|
||||
|
||||
static gboolean gdk_pixbuf_gif_anim_is_static_image (GdkPixbufAnimation *animation);
|
||||
static GdkPixbuf* gdk_pixbuf_gif_anim_get_static_image (GdkPixbufAnimation *animation);
|
||||
|
||||
static void gdk_pixbuf_gif_anim_get_size (GdkPixbufAnimation *anim,
|
||||
int *width,
|
||||
int *height);
|
||||
static GdkPixbufAnimationIter* gdk_pixbuf_gif_anim_get_iter (GdkPixbufAnimation *anim,
|
||||
const GTimeVal *start_time);
|
||||
|
||||
|
||||
|
||||
|
||||
static gpointer parent_class;
|
||||
|
||||
GType
|
||||
gdk_pixbuf_gif_anim_get_type (void)
|
||||
{
|
||||
static GType object_type = 0;
|
||||
|
||||
if (!object_type) {
|
||||
static const GTypeInfo object_info = {
|
||||
sizeof (GdkPixbufGifAnimClass),
|
||||
(GBaseInitFunc) NULL,
|
||||
(GBaseFinalizeFunc) NULL,
|
||||
(GClassInitFunc) gdk_pixbuf_gif_anim_class_init,
|
||||
NULL, /* class_finalize */
|
||||
NULL, /* class_data */
|
||||
sizeof (GdkPixbufGifAnim),
|
||||
0, /* n_preallocs */
|
||||
(GInstanceInitFunc) NULL,
|
||||
};
|
||||
|
||||
object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION,
|
||||
"GdkPixbufGifAnim",
|
||||
&object_info, 0);
|
||||
}
|
||||
|
||||
return object_type;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_pixbuf_gif_anim_class_init (GdkPixbufGifAnimClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
|
||||
|
||||
parent_class = g_type_class_peek_parent (klass);
|
||||
|
||||
object_class->finalize = gdk_pixbuf_gif_anim_finalize;
|
||||
|
||||
anim_class->is_static_image = gdk_pixbuf_gif_anim_is_static_image;
|
||||
anim_class->get_static_image = gdk_pixbuf_gif_anim_get_static_image;
|
||||
anim_class->get_size = gdk_pixbuf_gif_anim_get_size;
|
||||
anim_class->get_iter = gdk_pixbuf_gif_anim_get_iter;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_pixbuf_gif_anim_finalize (GObject *object)
|
||||
{
|
||||
GdkPixbufGifAnim *gif_anim = GDK_PIXBUF_GIF_ANIM (object);
|
||||
|
||||
GList *l;
|
||||
GdkPixbufFrame *frame;
|
||||
|
||||
for (l = gif_anim->frames; l; l = l->next) {
|
||||
frame = l->data;
|
||||
gdk_pixbuf_unref (frame->pixbuf);
|
||||
if (frame->composited)
|
||||
gdk_pixbuf_unref (frame->composited);
|
||||
if (frame->revert)
|
||||
gdk_pixbuf_unref (frame->revert);
|
||||
g_free (frame);
|
||||
}
|
||||
|
||||
g_list_free (gif_anim->frames);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_pixbuf_gif_anim_is_static_image (GdkPixbufAnimation *animation)
|
||||
{
|
||||
GdkPixbufGifAnim *gif_anim;
|
||||
|
||||
gif_anim = GDK_PIXBUF_GIF_ANIM (animation);
|
||||
|
||||
return (gif_anim->frames != NULL &&
|
||||
gif_anim->frames->next == NULL);
|
||||
}
|
||||
|
||||
static GdkPixbuf*
|
||||
gdk_pixbuf_gif_anim_get_static_image (GdkPixbufAnimation *animation)
|
||||
{
|
||||
GdkPixbufGifAnim *gif_anim;
|
||||
|
||||
gif_anim = GDK_PIXBUF_GIF_ANIM (animation);
|
||||
|
||||
if (gif_anim->frames == NULL)
|
||||
return NULL;
|
||||
else
|
||||
return GDK_PIXBUF (((GdkPixbufFrame*)gif_anim->frames->data)->pixbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_pixbuf_gif_anim_get_size (GdkPixbufAnimation *anim,
|
||||
int *width,
|
||||
int *height)
|
||||
{
|
||||
GdkPixbufGifAnim *gif_anim;
|
||||
|
||||
gif_anim = GDK_PIXBUF_GIF_ANIM (anim);
|
||||
|
||||
if (width)
|
||||
*width = gif_anim->width;
|
||||
|
||||
if (height)
|
||||
*height = gif_anim->height;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
iter_clear (GdkPixbufGifAnimIter *iter)
|
||||
{
|
||||
iter->current_frame = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
iter_restart (GdkPixbufGifAnimIter *iter)
|
||||
{
|
||||
iter_clear (iter);
|
||||
|
||||
iter->current_frame = iter->gif_anim->frames;
|
||||
}
|
||||
|
||||
static GdkPixbufAnimationIter*
|
||||
gdk_pixbuf_gif_anim_get_iter (GdkPixbufAnimation *anim,
|
||||
const GTimeVal *start_time)
|
||||
{
|
||||
GdkPixbufGifAnimIter *iter;
|
||||
|
||||
iter = g_object_new (GDK_TYPE_PIXBUF_GIF_ANIM_ITER, NULL);
|
||||
|
||||
iter->gif_anim = GDK_PIXBUF_GIF_ANIM (anim);
|
||||
|
||||
g_object_ref (G_OBJECT (iter->gif_anim));
|
||||
|
||||
iter_restart (iter);
|
||||
|
||||
iter->start_time = *start_time;
|
||||
iter->current_time = *start_time;
|
||||
|
||||
return GDK_PIXBUF_ANIMATION_ITER (iter);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void gdk_pixbuf_gif_anim_iter_class_init (GdkPixbufGifAnimIterClass *klass);
|
||||
static void gdk_pixbuf_gif_anim_iter_finalize (GObject *object);
|
||||
|
||||
static int gdk_pixbuf_gif_anim_iter_get_delay_time (GdkPixbufAnimationIter *iter);
|
||||
static GdkPixbuf* gdk_pixbuf_gif_anim_iter_get_pixbuf (GdkPixbufAnimationIter *iter);
|
||||
static gboolean gdk_pixbuf_gif_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
|
||||
static gboolean gdk_pixbuf_gif_anim_iter_advance (GdkPixbufAnimationIter *iter,
|
||||
const GTimeVal *current_time);
|
||||
|
||||
|
||||
|
||||
static gpointer iter_parent_class;
|
||||
|
||||
GType
|
||||
gdk_pixbuf_gif_anim_iter_get_type (void)
|
||||
{
|
||||
static GType object_type = 0;
|
||||
|
||||
if (!object_type) {
|
||||
static const GTypeInfo object_info = {
|
||||
sizeof (GdkPixbufGifAnimIterClass),
|
||||
(GBaseInitFunc) NULL,
|
||||
(GBaseFinalizeFunc) NULL,
|
||||
(GClassInitFunc) gdk_pixbuf_gif_anim_iter_class_init,
|
||||
NULL, /* class_finalize */
|
||||
NULL, /* class_data */
|
||||
sizeof (GdkPixbufGifAnimIter),
|
||||
0, /* n_preallocs */
|
||||
(GInstanceInitFunc) NULL,
|
||||
};
|
||||
|
||||
object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION_ITER,
|
||||
"GdkPixbufGifAnimIter",
|
||||
&object_info, 0);
|
||||
}
|
||||
|
||||
return object_type;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_pixbuf_gif_anim_iter_class_init (GdkPixbufGifAnimIterClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GdkPixbufAnimationIterClass *anim_iter_class =
|
||||
GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
|
||||
|
||||
iter_parent_class = g_type_class_peek_parent (klass);
|
||||
|
||||
object_class->finalize = gdk_pixbuf_gif_anim_iter_finalize;
|
||||
|
||||
anim_iter_class->get_delay_time = gdk_pixbuf_gif_anim_iter_get_delay_time;
|
||||
anim_iter_class->get_pixbuf = gdk_pixbuf_gif_anim_iter_get_pixbuf;
|
||||
anim_iter_class->on_currently_loading_frame = gdk_pixbuf_gif_anim_iter_on_currently_loading_frame;
|
||||
anim_iter_class->advance = gdk_pixbuf_gif_anim_iter_advance;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_pixbuf_gif_anim_iter_finalize (GObject *object)
|
||||
{
|
||||
GdkPixbufGifAnimIter *iter = GDK_PIXBUF_GIF_ANIM_ITER (object);
|
||||
|
||||
iter_clear (iter);
|
||||
|
||||
g_object_unref (G_OBJECT (iter->gif_anim));
|
||||
|
||||
G_OBJECT_CLASS (iter_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_pixbuf_gif_anim_iter_advance (GdkPixbufAnimationIter *anim_iter,
|
||||
const GTimeVal *current_time)
|
||||
{
|
||||
GdkPixbufGifAnimIter *iter;
|
||||
gint elapsed;
|
||||
GList *tmp;
|
||||
GList *old;
|
||||
|
||||
iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
|
||||
|
||||
iter->current_time = *current_time;
|
||||
|
||||
/* We use milliseconds for all times */
|
||||
elapsed =
|
||||
(((iter->current_time.tv_sec - iter->start_time.tv_sec) * G_USEC_PER_SEC +
|
||||
iter->current_time.tv_usec - iter->start_time.tv_usec)) / 1000;
|
||||
|
||||
if (elapsed < 0) {
|
||||
/* Try to compensate; probably the system clock
|
||||
* was set backwards
|
||||
*/
|
||||
iter->start_time = iter->current_time;
|
||||
elapsed = 0;
|
||||
}
|
||||
|
||||
/* See how many times we've already played the full animation,
|
||||
* and subtract time for that.
|
||||
*/
|
||||
elapsed = elapsed % iter->gif_anim->total_time;
|
||||
|
||||
g_assert (elapsed < iter->gif_anim->total_time);
|
||||
|
||||
iter->position = elapsed;
|
||||
|
||||
/* Now move to the proper frame */
|
||||
tmp = iter->gif_anim->frames;
|
||||
while (tmp != NULL) {
|
||||
GdkPixbufFrame *frame = tmp->data;
|
||||
|
||||
if (iter->position >= frame->elapsed &&
|
||||
iter->position < (frame->elapsed + frame->delay_time))
|
||||
break;
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
old = iter->current_frame;
|
||||
|
||||
iter->current_frame = tmp;
|
||||
|
||||
return iter->current_frame != old;
|
||||
}
|
||||
|
||||
int
|
||||
gdk_pixbuf_gif_anim_iter_get_delay_time (GdkPixbufAnimationIter *anim_iter)
|
||||
{
|
||||
GdkPixbufFrame *frame;
|
||||
GdkPixbufGifAnimIter *iter;
|
||||
|
||||
iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
|
||||
|
||||
if (iter->current_frame) {
|
||||
frame = iter->current_frame->data;
|
||||
|
||||
#if 0
|
||||
g_print ("frame start: %d pos: %d frame len: %d frame remaining: %d\n",
|
||||
frame->elapsed,
|
||||
iter->position,
|
||||
frame->delay_time,
|
||||
frame->delay_time - (iter->position - frame->elapsed));
|
||||
#endif
|
||||
|
||||
return frame->delay_time - (iter->position - frame->elapsed);
|
||||
} else {
|
||||
return -1; /* show last frame forever */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gdk_pixbuf_gif_anim_frame_composite (GdkPixbufGifAnim *gif_anim,
|
||||
GdkPixbufFrame *frame)
|
||||
{
|
||||
GList *link;
|
||||
GList *tmp;
|
||||
|
||||
link = g_list_find (gif_anim->frames, frame);
|
||||
|
||||
if (frame->need_recomposite || frame->composited == NULL) {
|
||||
/* For now, to composite we start with the last
|
||||
* composited frame and composite everything up to
|
||||
* here.
|
||||
*/
|
||||
|
||||
/* Rewind to last composited frame. */
|
||||
tmp = link;
|
||||
while (tmp != NULL) {
|
||||
GdkPixbufFrame *f = tmp->data;
|
||||
|
||||
if (f->need_recomposite) {
|
||||
if (f->composited) {
|
||||
g_object_unref (G_OBJECT (f->composited));
|
||||
f->composited = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (f->composited != NULL)
|
||||
break;
|
||||
|
||||
tmp = tmp->prev;
|
||||
}
|
||||
|
||||
/* Go forward, compositing all frames up to the current frame */
|
||||
if (tmp == NULL)
|
||||
tmp = gif_anim->frames;
|
||||
|
||||
while (tmp != NULL) {
|
||||
GdkPixbufFrame *f = tmp->data;
|
||||
|
||||
if (f->need_recomposite) {
|
||||
if (f->composited) {
|
||||
g_object_unref (G_OBJECT (f->composited));
|
||||
f->composited = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (f->composited != NULL)
|
||||
goto next;
|
||||
|
||||
if (tmp->prev == NULL) {
|
||||
/* First frame may be smaller than the whole image;
|
||||
* if so, we make the area outside it full alpha if the
|
||||
* image has alpha, and background color otherwise.
|
||||
* GIF spec doesn't actually say what to do about this.
|
||||
*/
|
||||
f->composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
|
||||
TRUE,
|
||||
8, gif_anim->width, gif_anim->height);
|
||||
|
||||
/* alpha gets dumped if f->composited has no alpha */
|
||||
|
||||
gdk_pixbuf_fill (f->composited,
|
||||
(gif_anim->bg_red << 24) |
|
||||
(gif_anim->bg_green << 16) |
|
||||
(gif_anim->bg_blue << 8) |
|
||||
(f->bg_transparent ? 0 : 255));
|
||||
|
||||
gdk_pixbuf_composite (f->pixbuf,
|
||||
f->composited,
|
||||
f->x_offset,
|
||||
f->y_offset,
|
||||
gdk_pixbuf_get_width (f->pixbuf),
|
||||
gdk_pixbuf_get_height (f->pixbuf),
|
||||
f->x_offset, f->y_offset,
|
||||
1.0, 1.0,
|
||||
GDK_INTERP_BILINEAR,
|
||||
255);
|
||||
#if 0
|
||||
gdk_pixbuf_copy_area (f->pixbuf,
|
||||
0, 0,
|
||||
gdk_pixbuf_get_width (f->pixbuf),
|
||||
gdk_pixbuf_get_height (f->pixbuf),
|
||||
f->composited,
|
||||
f->x_offset,
|
||||
f->y_offset);
|
||||
|
||||
#endif
|
||||
|
||||
if (f->action == GDK_PIXBUF_FRAME_REVERT)
|
||||
g_warning ("First frame of GIF has bad dispose mode, GIF loader should not have loaded this image");
|
||||
|
||||
f->need_recomposite = FALSE;
|
||||
} else {
|
||||
GdkPixbufFrame *prev_frame;
|
||||
|
||||
prev_frame = tmp->prev->data;
|
||||
|
||||
/* Init f->composited with what we should have after the previous
|
||||
* frame
|
||||
*/
|
||||
|
||||
if (prev_frame->action == GDK_PIXBUF_FRAME_RETAIN) {
|
||||
f->composited = gdk_pixbuf_copy (prev_frame->composited);
|
||||
|
||||
} else if (prev_frame->action == GDK_PIXBUF_FRAME_DISPOSE) {
|
||||
GdkPixbuf *area;
|
||||
|
||||
f->composited = gdk_pixbuf_copy (prev_frame->composited);
|
||||
|
||||
/* Clear area of previous frame to background */
|
||||
area = gdk_pixbuf_new_subpixbuf (f->composited,
|
||||
prev_frame->x_offset,
|
||||
prev_frame->y_offset,
|
||||
gdk_pixbuf_get_width (prev_frame->pixbuf),
|
||||
gdk_pixbuf_get_height (prev_frame->pixbuf));
|
||||
|
||||
gdk_pixbuf_fill (area,
|
||||
(gif_anim->bg_red << 24) |
|
||||
(gif_anim->bg_green << 16) |
|
||||
(gif_anim->bg_blue << 8) |
|
||||
prev_frame->bg_transparent ? 0 : 255);
|
||||
|
||||
g_object_unref (G_OBJECT (area));
|
||||
|
||||
} else if (prev_frame->action == GDK_PIXBUF_FRAME_REVERT) {
|
||||
f->composited = gdk_pixbuf_copy (prev_frame->composited);
|
||||
|
||||
/* Copy in the revert frame */
|
||||
gdk_pixbuf_copy_area (prev_frame->revert,
|
||||
0, 0,
|
||||
gdk_pixbuf_get_width (prev_frame->revert),
|
||||
gdk_pixbuf_get_height (prev_frame->revert),
|
||||
f->composited,
|
||||
prev_frame->x_offset,
|
||||
prev_frame->y_offset);
|
||||
} else {
|
||||
g_warning ("Unknown revert action for GIF frame");
|
||||
}
|
||||
|
||||
if (f->revert == NULL &&
|
||||
f->action == GDK_PIXBUF_FRAME_REVERT) {
|
||||
/* We need to save the contents before compositing */
|
||||
GdkPixbuf *area;
|
||||
|
||||
area = gdk_pixbuf_new_subpixbuf (f->composited,
|
||||
f->x_offset,
|
||||
f->y_offset,
|
||||
gdk_pixbuf_get_width (f->pixbuf),
|
||||
gdk_pixbuf_get_height (f->pixbuf));
|
||||
|
||||
f->revert = gdk_pixbuf_copy (area);
|
||||
|
||||
g_object_unref (G_OBJECT (area));
|
||||
}
|
||||
|
||||
/* Put current frame onto f->composited */
|
||||
gdk_pixbuf_composite (f->pixbuf,
|
||||
f->composited,
|
||||
f->x_offset,
|
||||
f->y_offset,
|
||||
gdk_pixbuf_get_width (f->pixbuf),
|
||||
gdk_pixbuf_get_height (f->pixbuf),
|
||||
f->x_offset, f->y_offset,
|
||||
1.0, 1.0,
|
||||
GDK_INTERP_NEAREST,
|
||||
255);
|
||||
|
||||
f->need_recomposite = FALSE;
|
||||
}
|
||||
|
||||
next:
|
||||
if (tmp == link)
|
||||
break;
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
g_assert (frame->composited != NULL);
|
||||
g_assert (gdk_pixbuf_get_width (frame->composited) == gif_anim->width);
|
||||
g_assert (gdk_pixbuf_get_height (frame->composited) == gif_anim->height);
|
||||
}
|
||||
|
||||
GdkPixbuf*
|
||||
gdk_pixbuf_gif_anim_iter_get_pixbuf (GdkPixbufAnimationIter *anim_iter)
|
||||
{
|
||||
GdkPixbufGifAnimIter *iter;
|
||||
GdkPixbufFrame *frame;
|
||||
|
||||
iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
|
||||
|
||||
frame = iter->current_frame ? iter->current_frame->data : NULL;
|
||||
|
||||
#if 0
|
||||
if (FALSE && frame)
|
||||
g_print ("current frame %d dispose mode %d %d x %d\n",
|
||||
g_list_index (iter->gif_anim->frames,
|
||||
frame),
|
||||
frame->action,
|
||||
gdk_pixbuf_get_width (frame->pixbuf),
|
||||
gdk_pixbuf_get_height (frame->pixbuf));
|
||||
#endif
|
||||
|
||||
if (frame == NULL)
|
||||
return NULL;
|
||||
|
||||
gdk_pixbuf_gif_anim_frame_composite (iter->gif_anim, frame);
|
||||
|
||||
return frame->composited;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_pixbuf_gif_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *anim_iter)
|
||||
{
|
||||
GdkPixbufGifAnimIter *iter;
|
||||
|
||||
iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
|
||||
|
||||
return iter->current_frame == NULL || iter->current_frame->next == NULL;
|
||||
}
|
169
gdk-pixbuf/io-gif-animation.h
Normal file
169
gdk-pixbuf/io-gif-animation.h
Normal file
@ -0,0 +1,169 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
|
||||
/* GdkPixbuf library - GIF loader declarations
|
||||
*
|
||||
* Copyright (C) 1999 The Free Software Foundation
|
||||
*
|
||||
* Authors: Mark Crichton <crichton@gimp.org>
|
||||
* Miguel de Icaza <miguel@gnu.org>
|
||||
* Federico Mena-Quintero <federico@gimp.org>
|
||||
* Havoc Pennington <hp@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef GDK_PIXBUF_GIF_H
|
||||
#define GDK_PIXBUF_GIF_H
|
||||
|
||||
#include "gdk-pixbuf-private.h"
|
||||
|
||||
typedef enum {
|
||||
/* Keep this frame and composite next frame over it */
|
||||
/* (GIF disposal method 1) */
|
||||
GDK_PIXBUF_FRAME_RETAIN,
|
||||
/* Revert to background color before compositing next frame */
|
||||
/* (GIF disposal method 2) */
|
||||
GDK_PIXBUF_FRAME_DISPOSE,
|
||||
/* Revert to previously-displayed composite image after
|
||||
* displaying this frame
|
||||
*/
|
||||
/* (GIF disposal method 3) */
|
||||
GDK_PIXBUF_FRAME_REVERT
|
||||
} GdkPixbufFrameAction;
|
||||
|
||||
|
||||
|
||||
typedef struct _GdkPixbufGifAnim GdkPixbufGifAnim;
|
||||
typedef struct _GdkPixbufGifAnimClass GdkPixbufGifAnimClass;
|
||||
|
||||
#define GDK_TYPE_PIXBUF_GIF_ANIM (gdk_pixbuf_gif_anim_get_type ())
|
||||
#define GDK_PIXBUF_GIF_ANIM(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_GIF_ANIM, GdkPixbufGifAnim))
|
||||
#define GDK_IS_PIXBUF_GIF_ANIM(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_GIF_ANIM))
|
||||
|
||||
#define GDK_PIXBUF_GIF_ANIM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_GIF_ANIM, GdkPixbufGifAnimClass))
|
||||
#define GDK_IS_PIXBUF_GIF_ANIM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_GIF_ANIM))
|
||||
#define GDK_PIXBUF_GIF_ANIM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_GIF_ANIM, GdkPixbufGifAnimClass))
|
||||
|
||||
/* Private part of the GdkPixbufGifAnim structure */
|
||||
struct _GdkPixbufGifAnim {
|
||||
GdkPixbufAnimation parent_instance;
|
||||
|
||||
/* Number of frames */
|
||||
int n_frames;
|
||||
|
||||
/* Total length of animation */
|
||||
int total_time;
|
||||
|
||||
/* List of GdkPixbufFrame structures */
|
||||
GList *frames;
|
||||
|
||||
/* bounding box size */
|
||||
int width, height;
|
||||
|
||||
guchar bg_red;
|
||||
guchar bg_green;
|
||||
guchar bg_blue;
|
||||
};
|
||||
|
||||
struct _GdkPixbufGifAnimClass {
|
||||
GdkPixbufAnimationClass parent_class;
|
||||
|
||||
};
|
||||
|
||||
GType gdk_pixbuf_gif_anim_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
|
||||
typedef struct _GdkPixbufGifAnimIter GdkPixbufGifAnimIter;
|
||||
typedef struct _GdkPixbufGifAnimIterClass GdkPixbufGifAnimIterClass;
|
||||
|
||||
|
||||
#define GDK_TYPE_PIXBUF_GIF_ANIM_ITER (gdk_pixbuf_gif_anim_iter_get_type ())
|
||||
#define GDK_PIXBUF_GIF_ANIM_ITER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_GIF_ANIM_ITER, GdkPixbufGifAnimIter))
|
||||
#define GDK_IS_PIXBUF_GIF_ANIM_ITER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_GIF_ANIM_ITER))
|
||||
|
||||
#define GDK_PIXBUF_GIF_ANIM_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_GIF_ANIM_ITER, GdkPixbufGifAnimIterClass))
|
||||
#define GDK_IS_PIXBUF_GIF_ANIM_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_GIF_ANIM_ITER))
|
||||
#define GDK_PIXBUF_GIF_ANIM_ITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_GIF_ANIM_ITER, GdkPixbufGifAnimIterClass))
|
||||
|
||||
struct _GdkPixbufGifAnimIter {
|
||||
GdkPixbufAnimationIter parent_instance;
|
||||
|
||||
GdkPixbufGifAnim *gif_anim;
|
||||
|
||||
GTimeVal start_time;
|
||||
GTimeVal current_time;
|
||||
|
||||
/* Time in milliseconds into this run of the animation */
|
||||
gint position;
|
||||
|
||||
GList *current_frame;
|
||||
};
|
||||
|
||||
struct _GdkPixbufGifAnimIterClass {
|
||||
GdkPixbufAnimationIterClass parent_class;
|
||||
|
||||
};
|
||||
|
||||
GType gdk_pixbuf_gif_anim_iter_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
|
||||
struct _GdkPixbufFrame {
|
||||
/* The pixbuf with this frame's image data */
|
||||
GdkPixbuf *pixbuf;
|
||||
|
||||
/* Offsets for overlaying onto the GIF graphic area */
|
||||
int x_offset;
|
||||
int y_offset;
|
||||
|
||||
/* Frame duration in ms */
|
||||
int delay_time;
|
||||
|
||||
/* Sum of preceding delay times */
|
||||
int elapsed;
|
||||
|
||||
/* Overlay mode */
|
||||
GdkPixbufFrameAction action;
|
||||
|
||||
/* TRUE if the pixbuf has been modified since
|
||||
* the last frame composite operation
|
||||
*/
|
||||
gboolean need_recomposite;
|
||||
|
||||
/* TRUE if the background for this frame is transparent */
|
||||
gboolean bg_transparent;
|
||||
|
||||
/* The below reflects the "use hell of a lot of RAM"
|
||||
* philosophy of coding
|
||||
*/
|
||||
|
||||
/* Cached composite image (the image you actually display
|
||||
* for this frame)
|
||||
*/
|
||||
GdkPixbuf *composited;
|
||||
|
||||
/* Cached revert image (the contents of the area
|
||||
* covered by the frame prior to compositing;
|
||||
* same size as pixbuf, not as the composite image; only
|
||||
* used for FRAME_REVERT frames)
|
||||
*/
|
||||
GdkPixbuf *revert;
|
||||
};
|
||||
|
||||
void gdk_pixbuf_gif_anim_frame_composite (GdkPixbufGifAnim *gif_anim,
|
||||
GdkPixbufFrame *frame);
|
||||
|
||||
#endif
|
@ -1,3 +1,4 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
|
||||
/* GdkPixbuf library - GIF image loader
|
||||
*
|
||||
* Copyright (C) 1999 Mark Crichton
|
||||
@ -30,10 +31,6 @@
|
||||
* in it got a bit messy. Basicly, every function is written to expect a failed
|
||||
* read_gif, and lets you call it again assuming that the bytes are there.
|
||||
*
|
||||
* A note on Animations:
|
||||
* Currently, it doesn't correctly read the different colormap per frame. This
|
||||
* needs implementing sometime.
|
||||
*
|
||||
* Return vals.
|
||||
* Unless otherwise specified, these are the return vals for most functions:
|
||||
*
|
||||
@ -59,11 +56,15 @@
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "gdk-pixbuf-private.h"
|
||||
#include "gdk-pixbuf-io.h"
|
||||
#include "io-gif-animation.h"
|
||||
|
||||
|
||||
|
||||
#undef DUMP_IMAGE_DETAILS
|
||||
|
||||
#define MAXCOLORMAPSIZE 256
|
||||
#define MAX_LZW_BITS 12
|
||||
|
||||
@ -88,7 +89,7 @@ enum {
|
||||
GIF_LZW_FILL_BUFFER,
|
||||
GIF_LZW_CLEAR_CODE,
|
||||
GIF_GET_LZW,
|
||||
GIF_DONE,
|
||||
GIF_DONE
|
||||
};
|
||||
|
||||
|
||||
@ -107,19 +108,27 @@ struct _GifContext
|
||||
int state; /* really only relevant for progressive loading */
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
CMap color_map;
|
||||
|
||||
gboolean has_global_cmap;
|
||||
|
||||
CMap global_color_map;
|
||||
gint global_colormap_size;
|
||||
unsigned int global_bit_pixel;
|
||||
unsigned int global_color_resolution;
|
||||
unsigned int background_index;
|
||||
|
||||
gboolean frame_cmap_active;
|
||||
CMap frame_color_map;
|
||||
unsigned int bit_pixel;
|
||||
unsigned int color_resolution;
|
||||
unsigned int background;
|
||||
gint frame_colormap_size;
|
||||
unsigned int frame_bit_pixel;
|
||||
|
||||
unsigned int aspect_ratio;
|
||||
GdkPixbuf *pixbuf;
|
||||
GdkPixbufAnimation *animation;
|
||||
GdkPixbufGifAnim *animation;
|
||||
GdkPixbufFrame *frame;
|
||||
Gif89 gif89;
|
||||
|
||||
/* stuff per frame. As we only support the first one, not so
|
||||
* relevant. But still needed */
|
||||
/* stuff per frame. */
|
||||
int frame_len;
|
||||
int frame_height;
|
||||
int frame_interlace;
|
||||
@ -132,18 +141,12 @@ struct _GifContext
|
||||
/* progressive read, only. */
|
||||
ModulePreparedNotifyFunc prepare_func;
|
||||
ModuleUpdatedNotifyFunc update_func;
|
||||
ModuleFrameDoneNotifyFunc frame_done_func;
|
||||
ModuleAnimationDoneNotifyFunc anim_done_func;
|
||||
gpointer user_data;
|
||||
guchar *buf;
|
||||
guint ptr;
|
||||
guint size;
|
||||
guint amount_needed;
|
||||
|
||||
/* colormap context */
|
||||
gint colormap_index;
|
||||
gint colormap_flag;
|
||||
|
||||
/* extension context */
|
||||
guchar extension_label;
|
||||
guchar extension_flag;
|
||||
@ -208,6 +211,13 @@ gif_read (GifContext *context, guchar *buffer, size_t len)
|
||||
g_print ("Fsize :%d\tcount :%d\t", len, count);
|
||||
#endif
|
||||
retval = (fread(buffer, len, 1, context->file) != 0);
|
||||
|
||||
if (!retval && ferror (context->file))
|
||||
g_set_error (context->error,
|
||||
G_FILE_ERROR,
|
||||
g_file_error_from_errno (errno),
|
||||
_("Failure reading GIF: %s"), strerror (errno));
|
||||
|
||||
#ifdef IO_GIFDEBUG
|
||||
if (len < 100) {
|
||||
for (i = 0; i < len; i++)
|
||||
@ -247,16 +257,14 @@ gif_read (GifContext *context, guchar *buffer, size_t len)
|
||||
static void
|
||||
gif_set_get_colormap (GifContext *context)
|
||||
{
|
||||
context->colormap_flag = TRUE;
|
||||
context->colormap_index = 0;
|
||||
context->global_colormap_size = 0;
|
||||
context->state = GIF_GET_COLORMAP;
|
||||
}
|
||||
|
||||
static void
|
||||
gif_set_get_colormap2 (GifContext *context)
|
||||
{
|
||||
context->colormap_flag = TRUE;
|
||||
context->colormap_index = 0;
|
||||
context->frame_colormap_size = 0;
|
||||
context->state = GIF_GET_COLORMAP2;
|
||||
}
|
||||
|
||||
@ -265,18 +273,43 @@ gif_get_colormap (GifContext *context)
|
||||
{
|
||||
unsigned char rgb[3];
|
||||
|
||||
while (context->colormap_index < context->bit_pixel) {
|
||||
while (context->global_colormap_size < context->global_bit_pixel) {
|
||||
if (!gif_read (context, rgb, sizeof (rgb))) {
|
||||
/*g_message (_("GIF: bad colormap\n"));*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
context->color_map[0][context->colormap_index] = rgb[0];
|
||||
context->color_map[1][context->colormap_index] = rgb[1];
|
||||
context->color_map[2][context->colormap_index] = rgb[2];
|
||||
context->global_color_map[0][context->global_colormap_size] = rgb[0];
|
||||
context->global_color_map[1][context->global_colormap_size] = rgb[1];
|
||||
context->global_color_map[2][context->global_colormap_size] = rgb[2];
|
||||
|
||||
context->colormap_flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]);
|
||||
context->colormap_index ++;
|
||||
if (context->global_colormap_size == context->background_index) {
|
||||
context->animation->bg_red = rgb[0];
|
||||
context->animation->bg_green = rgb[1];
|
||||
context->animation->bg_blue = rgb[2];
|
||||
}
|
||||
|
||||
context->global_colormap_size ++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static gint
|
||||
gif_get_colormap2 (GifContext *context)
|
||||
{
|
||||
unsigned char rgb[3];
|
||||
|
||||
while (context->frame_colormap_size < context->frame_bit_pixel) {
|
||||
if (!gif_read (context, rgb, sizeof (rgb))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
context->frame_color_map[0][context->frame_colormap_size] = rgb[0];
|
||||
context->frame_color_map[1][context->frame_colormap_size] = rgb[1];
|
||||
context->frame_color_map[2][context->frame_colormap_size] = rgb[2];
|
||||
|
||||
context->frame_colormap_size ++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -348,9 +381,11 @@ gif_get_extension (GifContext *context)
|
||||
retval = get_data_block (context, (unsigned char *) context->block_buf, NULL);
|
||||
if (retval != 0)
|
||||
return retval;
|
||||
if (context->pixbuf == NULL) {
|
||||
|
||||
if (context->frame == NULL) {
|
||||
/* I only want to set the transparency if I haven't
|
||||
* created the pixbuf yet. */
|
||||
* created the frame yet.
|
||||
*/
|
||||
context->gif89.disposal = (context->block_buf[0] >> 2) & 0x7;
|
||||
context->gif89.input_flag = (context->block_buf[0] >> 1) & 0x1;
|
||||
context->gif89.delay_time = LM_to_uint (context->block_buf[1], context->block_buf[2]);
|
||||
@ -623,18 +658,24 @@ static void
|
||||
gif_fill_in_pixels (GifContext *context, guchar *dest, gint offset, guchar v)
|
||||
{
|
||||
guchar *pixel = NULL;
|
||||
guchar (*cmap)[MAXCOLORMAPSIZE];
|
||||
|
||||
if (context->frame_cmap_active)
|
||||
cmap = context->frame_color_map;
|
||||
else
|
||||
cmap = context->global_color_map;
|
||||
|
||||
if (context->gif89.transparent != -1) {
|
||||
pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 4;
|
||||
*pixel = context->color_map [0][(guchar) v];
|
||||
*(pixel+1) = context->color_map [1][(guchar) v];
|
||||
*(pixel+2) = context->color_map [2][(guchar) v];
|
||||
*(pixel+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 65535);
|
||||
pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 4;
|
||||
*pixel = cmap [0][(guchar) v];
|
||||
*(pixel+1) = cmap [1][(guchar) v];
|
||||
*(pixel+2) = cmap [2][(guchar) v];
|
||||
*(pixel+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 255);
|
||||
} else {
|
||||
pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 3;
|
||||
*pixel = context->color_map [0][(guchar) v];
|
||||
*(pixel+1) = context->color_map [1][(guchar) v];
|
||||
*(pixel+2) = context->color_map [2][(guchar) v];
|
||||
pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 3;
|
||||
*pixel = cmap [0][(guchar) v];
|
||||
*(pixel+1) = cmap [1][(guchar) v];
|
||||
*(pixel+2) = cmap [2][(guchar) v];
|
||||
}
|
||||
}
|
||||
|
||||
@ -682,20 +723,28 @@ gif_get_lzw (GifContext *context)
|
||||
gint first_pass; /* bounds for emitting the area_updated signal */
|
||||
gint v;
|
||||
|
||||
if (context->pixbuf == NULL) {
|
||||
context->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
|
||||
context->gif89.transparent != -1,
|
||||
if (context->frame == NULL) {
|
||||
context->frame = g_new (GdkPixbufFrame, 1);
|
||||
|
||||
context->frame->composited = NULL;
|
||||
context->frame->revert = NULL;
|
||||
|
||||
context->frame->pixbuf =
|
||||
gdk_pixbuf_new (GDK_COLORSPACE_RGB,
|
||||
TRUE,
|
||||
8,
|
||||
context->frame_len,
|
||||
context->frame_height);
|
||||
|
||||
if (context->prepare_func)
|
||||
(* context->prepare_func) (context->pixbuf, context->user_data);
|
||||
if (context->animation || context->frame_done_func || context->anim_done_func) {
|
||||
context->frame = g_new (GdkPixbufFrame, 1);
|
||||
context->frame->x_offset = context->x_offset;
|
||||
context->frame->y_offset = context->y_offset;;
|
||||
context->frame->delay_time = context->gif89.delay_time;
|
||||
context->frame->y_offset = context->y_offset;
|
||||
context->frame->need_recomposite = TRUE;
|
||||
|
||||
/* GIF delay is in hundredths, we want thousandths */
|
||||
context->frame->delay_time = context->gif89.delay_time * 10;
|
||||
context->frame->elapsed = context->animation->total_time;
|
||||
context->animation->total_time += context->frame->delay_time;
|
||||
|
||||
switch (context->gif89.disposal) {
|
||||
case 0:
|
||||
case 1:
|
||||
@ -711,45 +760,80 @@ gif_get_lzw (GifContext *context)
|
||||
context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
|
||||
break;
|
||||
}
|
||||
context->frame->pixbuf = context->pixbuf;
|
||||
if (context->animation) {
|
||||
|
||||
context->frame->bg_transparent = (context->gif89.transparent == context->background_index);
|
||||
|
||||
{
|
||||
/* Update animation size */
|
||||
int w, h;
|
||||
|
||||
context->animation->n_frames ++;
|
||||
context->animation->frames = g_list_append (context->animation->frames, context->frame);
|
||||
w = gdk_pixbuf_get_width (context->pixbuf);
|
||||
h = gdk_pixbuf_get_height (context->pixbuf);
|
||||
|
||||
w = context->frame->x_offset +
|
||||
gdk_pixbuf_get_width (context->frame->pixbuf);
|
||||
h = context->frame->y_offset +
|
||||
gdk_pixbuf_get_height (context->frame->pixbuf);
|
||||
if (w > context->animation->width)
|
||||
context->animation->width = w;
|
||||
if (h > context->animation->height)
|
||||
context->animation->height = h;
|
||||
}
|
||||
|
||||
/* Only call prepare_func for the first frame */
|
||||
if (context->animation->frames->next == NULL) {
|
||||
if (context->prepare_func)
|
||||
(* context->prepare_func) (context->frame->pixbuf,
|
||||
GDK_PIXBUF_ANIMATION (context->animation),
|
||||
context->user_data);
|
||||
} else {
|
||||
/* Otherwise init frame with last frame */
|
||||
GList *link;
|
||||
GdkPixbufFrame *prev_frame;
|
||||
|
||||
link = g_list_find (context->animation->frames, context->frame);
|
||||
|
||||
prev_frame = link->prev->data;
|
||||
|
||||
gdk_pixbuf_gif_anim_frame_composite (context->animation, prev_frame);
|
||||
|
||||
gdk_pixbuf_copy_area (prev_frame->composited,
|
||||
context->frame->x_offset,
|
||||
context->frame->y_offset,
|
||||
gdk_pixbuf_get_width (context->frame->pixbuf),
|
||||
gdk_pixbuf_get_height (context->frame->pixbuf),
|
||||
context->frame->pixbuf,
|
||||
0, 0);
|
||||
}
|
||||
}
|
||||
dest = gdk_pixbuf_get_pixels (context->pixbuf);
|
||||
|
||||
dest = gdk_pixbuf_get_pixels (context->frame->pixbuf);
|
||||
|
||||
bound_flag = FALSE;
|
||||
lower_bound = upper_bound = context->draw_ypos;
|
||||
first_pass = context->draw_pass;
|
||||
|
||||
while (TRUE) {
|
||||
guchar (*cmap)[MAXCOLORMAPSIZE];
|
||||
|
||||
if (context->frame_cmap_active)
|
||||
cmap = context->frame_color_map;
|
||||
else
|
||||
cmap = context->global_color_map;
|
||||
|
||||
v = lzw_read_byte (context);
|
||||
if (v < 0) {
|
||||
goto finished_data;
|
||||
}
|
||||
bound_flag = TRUE;
|
||||
|
||||
if (context->gif89.transparent != -1) {
|
||||
temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 4;
|
||||
*temp = context->color_map [0][(guchar) v];
|
||||
*(temp+1) = context->color_map [1][(guchar) v];
|
||||
*(temp+2) = context->color_map [2][(guchar) v];
|
||||
*(temp+3) = (guchar) ((v == context->gif89.transparent) ? 0 : -1);
|
||||
} else {
|
||||
temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 3;
|
||||
*temp = context->color_map [0][(guchar) v];
|
||||
*(temp+1) = context->color_map [1][(guchar) v];
|
||||
*(temp+2) = context->color_map [2][(guchar) v];
|
||||
}
|
||||
g_assert (gdk_pixbuf_get_has_alpha (context->frame->pixbuf));
|
||||
|
||||
temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 4;
|
||||
*temp = cmap [0][(guchar) v];
|
||||
*(temp+1) = cmap [1][(guchar) v];
|
||||
*(temp+2) = cmap [2][(guchar) v];
|
||||
*(temp+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 255);
|
||||
|
||||
if (context->prepare_func && context->frame_interlace)
|
||||
gif_fill_in_lines (context, dest, v);
|
||||
@ -804,56 +888,60 @@ gif_get_lzw (GifContext *context)
|
||||
if (context->draw_ypos >= context->frame_height)
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
/* we got enough data. there may be more (ie, newer layers) but we can quit now */
|
||||
if (context->animation || context->frame_done_func || context->anim_done_func) {
|
||||
|
||||
context->state = GIF_GET_NEXT_STEP;
|
||||
} else
|
||||
context->state = GIF_DONE;
|
||||
|
||||
v = 0;
|
||||
|
||||
finished_data:
|
||||
|
||||
if (bound_flag)
|
||||
context->frame->need_recomposite = TRUE;
|
||||
|
||||
if (bound_flag && context->update_func) {
|
||||
if (lower_bound <= upper_bound && first_pass == context->draw_pass) {
|
||||
(* context->update_func)
|
||||
(context->pixbuf,
|
||||
(context->frame->pixbuf,
|
||||
0, lower_bound,
|
||||
gdk_pixbuf_get_width (context->pixbuf),
|
||||
gdk_pixbuf_get_width (context->frame->pixbuf),
|
||||
upper_bound - lower_bound,
|
||||
context->user_data);
|
||||
} else {
|
||||
if (lower_bound <= upper_bound) {
|
||||
(* context->update_func)
|
||||
(context->pixbuf,
|
||||
0, 0,
|
||||
gdk_pixbuf_get_width (context->pixbuf),
|
||||
gdk_pixbuf_get_height (context->pixbuf),
|
||||
(context->frame->pixbuf,
|
||||
context->frame->x_offset,
|
||||
context->frame->y_offset,
|
||||
gdk_pixbuf_get_width (context->frame->pixbuf),
|
||||
gdk_pixbuf_get_height (context->frame->pixbuf),
|
||||
context->user_data);
|
||||
} else {
|
||||
(* context->update_func)
|
||||
(context->pixbuf,
|
||||
0, 0,
|
||||
gdk_pixbuf_get_width (context->pixbuf),
|
||||
(context->frame->pixbuf,
|
||||
context->frame->x_offset,
|
||||
context->frame->y_offset,
|
||||
gdk_pixbuf_get_width (context->frame->pixbuf),
|
||||
upper_bound,
|
||||
context->user_data);
|
||||
(* context->update_func)
|
||||
(context->pixbuf,
|
||||
0, lower_bound,
|
||||
gdk_pixbuf_get_width (context->pixbuf),
|
||||
gdk_pixbuf_get_height (context->pixbuf),
|
||||
(context->frame->pixbuf,
|
||||
context->frame->x_offset,
|
||||
lower_bound + context->frame->y_offset,
|
||||
gdk_pixbuf_get_width (context->frame->pixbuf),
|
||||
gdk_pixbuf_get_height (context->frame->pixbuf),
|
||||
context->user_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((context->animation || context->frame_done_func || context->anim_done_func)
|
||||
&& context->state == GIF_GET_NEXT_STEP) {
|
||||
if (context->frame_done_func)
|
||||
(* context->frame_done_func) (context->frame,
|
||||
context->user_data);
|
||||
if (context->frame_done_func)
|
||||
gdk_pixbuf_unref (context->pixbuf);
|
||||
context->pixbuf = NULL;
|
||||
if (context->state == GIF_GET_NEXT_STEP) {
|
||||
/* Will be freed with context->animation, we are just
|
||||
* marking that we're done with it (no current frame)
|
||||
*/
|
||||
context->frame = NULL;
|
||||
context->frame_cmap_active = FALSE;
|
||||
}
|
||||
|
||||
return v;
|
||||
@ -943,16 +1031,36 @@ gif_init (GifContext *context)
|
||||
|
||||
context->width = LM_to_uint (buf[0], buf[1]);
|
||||
context->height = LM_to_uint (buf[2], buf[3]);
|
||||
context->bit_pixel = 2 << (buf[4] & 0x07);
|
||||
context->color_resolution = (((buf[4] & 0x70) >> 3) + 1);
|
||||
context->background = buf[5];
|
||||
/* The 4th byte is
|
||||
* high bit: whether to use the background index
|
||||
* next 3: color resolution
|
||||
* next: whether colormap is sorted by priority of allocation
|
||||
* last 3: size of colormap
|
||||
*/
|
||||
context->global_bit_pixel = 2 << (buf[4] & 0x07);
|
||||
context->global_color_resolution = (((buf[4] & 0x70) >> 3) + 1);
|
||||
context->has_global_cmap = (buf[4] & 0x80) != 0;
|
||||
context->background_index = buf[5];
|
||||
context->aspect_ratio = buf[6];
|
||||
|
||||
if (BitSet (buf[4], LOCALCOLORMAP)) {
|
||||
/* Use background of transparent black as default, though if
|
||||
* one isn't set explicitly no one should ever use it.
|
||||
*/
|
||||
context->animation->bg_red = 0;
|
||||
context->animation->bg_green = 0;
|
||||
context->animation->bg_blue = 0;
|
||||
|
||||
if (context->has_global_cmap) {
|
||||
gif_set_get_colormap (context);
|
||||
} else {
|
||||
context->state = GIF_GET_NEXT_STEP;
|
||||
}
|
||||
|
||||
#ifdef DUMP_IMAGE_DETAILS
|
||||
g_print (">Image width: %d height: %d global_cmap: %d background: %d\n",
|
||||
context->width, context->height, context->has_global_cmap, context->background_index);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -966,38 +1074,81 @@ static gint
|
||||
gif_get_frame_info (GifContext *context)
|
||||
{
|
||||
unsigned char buf[9];
|
||||
|
||||
if (!gif_read (context, buf, 9)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Okay, we got all the info we need. Lets record it */
|
||||
context->frame_len = LM_to_uint (buf[4], buf[5]);
|
||||
context->frame_height = LM_to_uint (buf[6], buf[7]);
|
||||
context->x_offset = LM_to_uint (buf[0], buf[1]);
|
||||
context->y_offset = LM_to_uint (buf[2], buf[3]);
|
||||
|
||||
if (context->frame_height > context->height) {
|
||||
/* we don't want to resize things. So we exit */
|
||||
if (((context->frame_height + context->y_offset) > context->height) ||
|
||||
((context->frame_len + context->x_offset) > context->width)) {
|
||||
/* All frames must fit in the image bounds */
|
||||
context->state = GIF_DONE;
|
||||
|
||||
g_set_error (context->error,
|
||||
GDK_PIXBUF_ERROR,
|
||||
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
|
||||
_("GIF animation contained a frame with an incorrect size"));
|
||||
_("GIF image contained a frame appearing outside the image bounds."));
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (context->animation->frames == NULL &&
|
||||
context->gif89.disposal == 3) {
|
||||
/* First frame can't have "revert to previous" as its
|
||||
* dispose mode.
|
||||
*/
|
||||
|
||||
context->state = GIF_DONE;
|
||||
|
||||
g_set_error (context->error,
|
||||
GDK_PIXBUF_ERROR,
|
||||
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
|
||||
_("First frame of GIF image had 'revert to previous' as its disposal mode."));
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
#ifdef DUMP_IMAGE_DETAILS
|
||||
g_print (">width: %d height: %d xoffset: %d yoffset: %d disposal: %d delay: %d transparent: %d\n",
|
||||
context->frame_len, context->frame_height, context->x_offset, context->y_offset,
|
||||
context->gif89.disposal, context->gif89.delay_time, context->gif89.transparent);
|
||||
#endif
|
||||
|
||||
context->frame_interlace = BitSet (buf[8], INTERLACE);
|
||||
if (BitSet (buf[8], LOCALCOLORMAP)) {
|
||||
|
||||
#ifdef DUMP_IMAGE_DETAILS
|
||||
g_print (">has local colormap\n");
|
||||
#endif
|
||||
|
||||
/* Does this frame have it's own colormap. */
|
||||
/* really only relevant when looking at the first frame
|
||||
* of an animated gif. */
|
||||
/* if it does, we need to re-read in the colormap,
|
||||
* the gray_scale, and the bit_pixel */
|
||||
context->bit_pixel = 1 << ((buf[8] & 0x07) + 1);
|
||||
context->frame_cmap_active = TRUE;
|
||||
context->frame_bit_pixel = 1 << ((buf[8] & 0x07) + 1);
|
||||
gif_set_get_colormap2 (context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!context->has_global_cmap) {
|
||||
context->state = GIF_DONE;
|
||||
|
||||
g_set_error (context->error,
|
||||
GDK_PIXBUF_ERROR,
|
||||
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
|
||||
_("GIF image has no global colormap, and a frame inside it has no local colormap."));
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
gif_set_prepare_lzw (context);
|
||||
return 0;
|
||||
|
||||
@ -1037,6 +1188,8 @@ gif_get_next_step (GifContext *context)
|
||||
}
|
||||
|
||||
|
||||
#define LOG(x)
|
||||
|
||||
static gint
|
||||
gif_main_loop (GifContext *context)
|
||||
{
|
||||
@ -1045,52 +1198,63 @@ gif_main_loop (GifContext *context)
|
||||
do {
|
||||
switch (context->state) {
|
||||
case GIF_START:
|
||||
LOG("start\n");
|
||||
retval = gif_init (context);
|
||||
break;
|
||||
|
||||
case GIF_GET_COLORMAP:
|
||||
LOG("get_colormap\n");
|
||||
retval = gif_get_colormap (context);
|
||||
if (retval == 0)
|
||||
context->state = GIF_GET_NEXT_STEP;
|
||||
break;
|
||||
|
||||
case GIF_GET_NEXT_STEP:
|
||||
LOG("next_step\n");
|
||||
retval = gif_get_next_step (context);
|
||||
break;
|
||||
|
||||
case GIF_GET_FRAME_INFO:
|
||||
LOG("frame_info\n");
|
||||
retval = gif_get_frame_info (context);
|
||||
break;
|
||||
|
||||
case GIF_GET_EXTENTION:
|
||||
LOG("get_extension\n");
|
||||
retval = gif_get_extension (context);
|
||||
if (retval == 0)
|
||||
context->state = GIF_GET_NEXT_STEP;
|
||||
break;
|
||||
|
||||
case GIF_GET_COLORMAP2:
|
||||
retval = gif_get_colormap (context);
|
||||
LOG("get_colormap2\n");
|
||||
retval = gif_get_colormap2 (context);
|
||||
if (retval == 0)
|
||||
gif_set_prepare_lzw (context);
|
||||
break;
|
||||
|
||||
case GIF_PREPARE_LZW:
|
||||
LOG("prepare_lzw\n");
|
||||
retval = gif_prepare_lzw (context);
|
||||
break;
|
||||
|
||||
case GIF_LZW_FILL_BUFFER:
|
||||
LOG("fill_buffer\n");
|
||||
retval = gif_lzw_fill_buffer (context);
|
||||
break;
|
||||
|
||||
case GIF_LZW_CLEAR_CODE:
|
||||
LOG("clear_code\n");
|
||||
retval = gif_lzw_clear_code (context);
|
||||
break;
|
||||
|
||||
case GIF_GET_LZW:
|
||||
LOG("get_lzw\n");
|
||||
retval = gif_get_lzw (context);
|
||||
break;
|
||||
|
||||
case GIF_DONE:
|
||||
LOG("done\n");
|
||||
default:
|
||||
retval = 0;
|
||||
goto done;
|
||||
@ -1107,13 +1271,12 @@ new_context (void)
|
||||
|
||||
context = g_new0 (GifContext, 1);
|
||||
|
||||
context->pixbuf = NULL;
|
||||
context->animation = g_object_new (GDK_TYPE_PIXBUF_GIF_ANIM, NULL);
|
||||
context->frame = NULL;
|
||||
context->file = NULL;
|
||||
context->state = GIF_START;
|
||||
context->prepare_func = NULL;
|
||||
context->update_func = NULL;
|
||||
context->frame_done_func = NULL;
|
||||
context->anim_done_func = NULL;
|
||||
context->user_data = NULL;
|
||||
context->buf = NULL;
|
||||
context->amount_needed = 0;
|
||||
@ -1137,9 +1300,22 @@ gdk_pixbuf__gif_image_load (FILE *file, GError **error)
|
||||
context->file = file;
|
||||
context->error = error;
|
||||
|
||||
gif_main_loop (context);
|
||||
if (gif_main_loop (context) == -1 || context->animation->frames == NULL) {
|
||||
if (context->error && *(context->error) == NULL)
|
||||
g_set_error (context->error,
|
||||
GDK_PIXBUF_ERROR,
|
||||
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
|
||||
_("GIF file was missing some data (perhaps it was truncated somehow?)"));
|
||||
}
|
||||
|
||||
pixbuf = context->pixbuf;
|
||||
pixbuf = gdk_pixbuf_animation_get_static_image (GDK_PIXBUF_ANIMATION (context->animation));
|
||||
|
||||
if (pixbuf)
|
||||
g_object_ref (G_OBJECT (pixbuf));
|
||||
|
||||
g_object_unref (G_OBJECT (context->animation));
|
||||
|
||||
g_free (context->buf);
|
||||
g_free (context);
|
||||
|
||||
return pixbuf;
|
||||
@ -1148,8 +1324,6 @@ gdk_pixbuf__gif_image_load (FILE *file, GError **error)
|
||||
static gpointer
|
||||
gdk_pixbuf__gif_image_begin_load (ModulePreparedNotifyFunc prepare_func,
|
||||
ModuleUpdatedNotifyFunc update_func,
|
||||
ModuleFrameDoneNotifyFunc frame_done_func,
|
||||
ModuleAnimationDoneNotifyFunc anim_done_func,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
@ -1162,8 +1336,6 @@ gdk_pixbuf__gif_image_begin_load (ModulePreparedNotifyFunc prepare_func,
|
||||
context->error = error;
|
||||
context->prepare_func = prepare_func;
|
||||
context->update_func = update_func;
|
||||
context->frame_done_func = frame_done_func;
|
||||
context->anim_done_func = anim_done_func;
|
||||
context->user_data = user_data;
|
||||
|
||||
return (gpointer) context;
|
||||
@ -1173,21 +1345,23 @@ static gboolean
|
||||
gdk_pixbuf__gif_image_stop_load (gpointer data, GError **error)
|
||||
{
|
||||
GifContext *context = (GifContext *) data;
|
||||
gboolean retval = TRUE;
|
||||
|
||||
/* FIXME: free the animation data */
|
||||
if (context->state != GIF_DONE) {
|
||||
g_set_error (error,
|
||||
GDK_PIXBUF_ERROR,
|
||||
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
|
||||
_("GIF image was truncated or incomplete."));
|
||||
|
||||
/* FIXME this thing needs to report errors if
|
||||
* we have unused image data
|
||||
*/
|
||||
retval = FALSE;
|
||||
}
|
||||
|
||||
if (context->pixbuf)
|
||||
gdk_pixbuf_unref (context->pixbuf);
|
||||
if (context->animation)
|
||||
gdk_pixbuf_animation_unref (context->animation);
|
||||
/* g_free (context->buf);*/
|
||||
g_object_unref (G_OBJECT (context->animation));
|
||||
|
||||
g_free (context->buf);
|
||||
g_free (context);
|
||||
|
||||
return TRUE;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -1264,18 +1438,28 @@ gdk_pixbuf__gif_image_load_animation (FILE *file,
|
||||
context = new_context ();
|
||||
|
||||
context->error = error;
|
||||
|
||||
context->animation = g_object_new (GDK_TYPE_PIXBUF_ANIMATION, NULL);
|
||||
|
||||
context->animation->n_frames = 0;
|
||||
context->animation->frames = NULL;
|
||||
context->animation->width = 0;
|
||||
context->animation->height = 0;
|
||||
context->file = file;
|
||||
|
||||
gif_main_loop (context);
|
||||
if (gif_main_loop (context) == -1 || context->animation->frames == NULL) {
|
||||
if (context->error && *(context->error) == NULL)
|
||||
g_set_error (context->error,
|
||||
GDK_PIXBUF_ERROR,
|
||||
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
|
||||
_("GIF file was missing some data (perhaps it was truncated somehow?)"));
|
||||
|
||||
animation = context->animation;
|
||||
g_object_unref (G_OBJECT (context->animation));
|
||||
context->animation = NULL;
|
||||
}
|
||||
|
||||
if (context->animation)
|
||||
animation = GDK_PIXBUF_ANIMATION (context->animation);
|
||||
else
|
||||
animation = NULL;
|
||||
|
||||
if (context->error && *(context->error))
|
||||
g_print ("%s\n", (*(context->error))->message);
|
||||
|
||||
g_free (context->buf);
|
||||
g_free (context);
|
||||
return animation;
|
||||
}
|
||||
|
@ -156,8 +156,6 @@ struct ico_progressive_state {
|
||||
static gpointer
|
||||
gdk_pixbuf__ico_image_begin_load(ModulePreparedNotifyFunc prepared_func,
|
||||
ModuleUpdatedNotifyFunc updated_func,
|
||||
ModuleFrameDoneNotifyFunc frame_done_func,
|
||||
ModuleAnimationDoneNotifyFunc anim_done_func,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
static gboolean gdk_pixbuf__ico_image_stop_load(gpointer data, GError **error);
|
||||
@ -178,8 +176,8 @@ gdk_pixbuf__ico_image_load(FILE * f, GError **error)
|
||||
|
||||
GdkPixbuf *pb;
|
||||
|
||||
State = gdk_pixbuf__ico_image_begin_load(NULL, NULL, NULL,
|
||||
NULL, NULL, error);
|
||||
State = gdk_pixbuf__ico_image_begin_load(NULL, NULL, NULL, error);
|
||||
|
||||
if (State == NULL)
|
||||
return NULL;
|
||||
|
||||
@ -363,6 +361,7 @@ static void DecodeHeader(guchar *Data, gint Bytes,
|
||||
if (State->prepared_func != NULL)
|
||||
/* Notify the client that we are ready to go */
|
||||
(*State->prepared_func) (State->pixbuf,
|
||||
NULL,
|
||||
State->user_data);
|
||||
|
||||
}
|
||||
@ -378,8 +377,6 @@ static void DecodeHeader(guchar *Data, gint Bytes,
|
||||
static gpointer
|
||||
gdk_pixbuf__ico_image_begin_load(ModulePreparedNotifyFunc prepared_func,
|
||||
ModuleUpdatedNotifyFunc updated_func,
|
||||
ModuleFrameDoneNotifyFunc frame_done_func,
|
||||
ModuleAnimationDoneNotifyFunc anim_done_func,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
|
@ -96,8 +96,6 @@ typedef struct {
|
||||
static GdkPixbuf *gdk_pixbuf__jpeg_image_load (FILE *f, GError **error);
|
||||
static gpointer gdk_pixbuf__jpeg_image_begin_load (ModulePreparedNotifyFunc func,
|
||||
ModuleUpdatedNotifyFunc func2,
|
||||
ModuleFrameDoneNotifyFunc func3,
|
||||
ModuleAnimationDoneNotifyFunc func4,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
static gboolean gdk_pixbuf__jpeg_image_stop_load (gpointer context, GError **error);
|
||||
@ -321,8 +319,6 @@ skip_input_data (j_decompress_ptr cinfo, long num_bytes)
|
||||
gpointer
|
||||
gdk_pixbuf__jpeg_image_begin_load (ModulePreparedNotifyFunc prepared_func,
|
||||
ModuleUpdatedNotifyFunc updated_func,
|
||||
ModuleFrameDoneNotifyFunc frame_func,
|
||||
ModuleAnimationDoneNotifyFunc anim_done_func,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
@ -539,6 +535,7 @@ gdk_pixbuf__jpeg_image_load_increment (gpointer data,
|
||||
|
||||
/* Notify the client that we are ready to go */
|
||||
(* context->prepared_func) (context->pixbuf,
|
||||
NULL,
|
||||
context->user_data);
|
||||
|
||||
} else if (!context->did_prescan) {
|
||||
|
@ -324,8 +324,6 @@ struct _LoadContext {
|
||||
static gpointer
|
||||
gdk_pixbuf__png_image_begin_load (ModulePreparedNotifyFunc prepare_func,
|
||||
ModuleUpdatedNotifyFunc update_func,
|
||||
ModuleFrameDoneNotifyFunc frame_done_func,
|
||||
ModuleAnimationDoneNotifyFunc anim_done_func,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
@ -540,7 +538,7 @@ png_info_callback (png_structp png_read_ptr,
|
||||
/* Notify the client that we are ready to go */
|
||||
|
||||
if (lc->prepare_func)
|
||||
(* lc->prepare_func) (lc->pixbuf, lc->notify_user_data);
|
||||
(* lc->prepare_func) (lc->pixbuf, NULL, lc->notify_user_data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -84,8 +84,6 @@ typedef struct {
|
||||
static GdkPixbuf *gdk_pixbuf__pnm_image_load (FILE *f, GError **error);
|
||||
static gpointer gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc func,
|
||||
ModuleUpdatedNotifyFunc func2,
|
||||
ModuleFrameDoneNotifyFunc frame_done_func,
|
||||
ModuleAnimationDoneNotifyFunc anim_done_func,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
static gboolean gdk_pixbuf__pnm_image_stop_load (gpointer context, GError **error);
|
||||
@ -763,8 +761,6 @@ gdk_pixbuf__pnm_image_load (FILE *f, GError **error)
|
||||
static gpointer
|
||||
gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc prepared_func,
|
||||
ModuleUpdatedNotifyFunc updated_func,
|
||||
ModuleFrameDoneNotifyFunc frame_done_func,
|
||||
ModuleAnimationDoneNotifyFunc anim_done_func,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
@ -923,6 +919,7 @@ gdk_pixbuf__pnm_image_load_increment (gpointer data,
|
||||
|
||||
/* Notify the client that we are ready to go */
|
||||
(* context->prepared_func) (context->pixbuf,
|
||||
NULL,
|
||||
context->user_data);
|
||||
}
|
||||
|
||||
|
@ -96,8 +96,6 @@ struct ras_progressive_state {
|
||||
static gpointer
|
||||
gdk_pixbuf__ras_image_begin_load(ModulePreparedNotifyFunc prepared_func,
|
||||
ModuleUpdatedNotifyFunc updated_func,
|
||||
ModuleFrameDoneNotifyFunc frame_done_func,
|
||||
ModuleAnimationDoneNotifyFunc anim_done_func,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
static gboolean gdk_pixbuf__ras_image_stop_load(gpointer data, GError **error);
|
||||
@ -116,8 +114,7 @@ static GdkPixbuf *gdk_pixbuf__ras_image_load(FILE * f, GError **error)
|
||||
|
||||
GdkPixbuf *pb;
|
||||
|
||||
State = gdk_pixbuf__ras_image_begin_load(NULL, NULL, NULL,
|
||||
NULL, NULL, error);
|
||||
State = gdk_pixbuf__ras_image_begin_load(NULL, NULL, NULL, error);
|
||||
|
||||
membuf = g_malloc(4096);
|
||||
|
||||
@ -195,6 +192,7 @@ static void RAS2State(struct rasterfile *RAS,
|
||||
if (State->prepared_func != NULL)
|
||||
/* Notify the client that we are ready to go */
|
||||
(*State->prepared_func) (State->pixbuf,
|
||||
NULL,
|
||||
State->user_data);
|
||||
|
||||
}
|
||||
@ -219,8 +217,6 @@ static void RAS2State(struct rasterfile *RAS,
|
||||
static gpointer
|
||||
gdk_pixbuf__ras_image_begin_load(ModulePreparedNotifyFunc prepared_func,
|
||||
ModuleUpdatedNotifyFunc updated_func,
|
||||
ModuleFrameDoneNotifyFunc frame_done_func,
|
||||
ModuleAnimationDoneNotifyFunc anim_done_func,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
|
@ -92,7 +92,7 @@ gdk_pixbuf__tiff_image_load_real (FILE *f, TiffData *context, GError **error)
|
||||
}
|
||||
|
||||
if (context)
|
||||
(* context->prepare_func) (pixbuf, context->user_data);
|
||||
(* context->prepare_func) (pixbuf, NULL, context->user_data);
|
||||
|
||||
/* Yes, it needs to be _TIFFMalloc... */
|
||||
rast = (uint32 *) _TIFFmalloc (num_pixs * sizeof (uint32));
|
||||
@ -163,8 +163,6 @@ gdk_pixbuf__tiff_image_load (FILE *f, GError **error)
|
||||
static gpointer
|
||||
gdk_pixbuf__tiff_image_begin_load (ModulePreparedNotifyFunc prepare_func,
|
||||
ModuleUpdatedNotifyFunc update_func,
|
||||
ModuleFrameDoneNotifyFunc frame_done_func,
|
||||
ModuleAnimationDoneNotifyFunc anim_done_func,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
|
@ -65,9 +65,7 @@ struct wbmp_progressive_state {
|
||||
static gpointer
|
||||
gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
|
||||
ModuleUpdatedNotifyFunc updated_func,
|
||||
ModuleFrameDoneNotifyFunc frame_done_func,
|
||||
ModuleAnimationDoneNotifyFunc
|
||||
anim_done_func, gpointer user_data,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
|
||||
static gboolean gdk_pixbuf__wbmp_image_stop_load(gpointer data, GError **error);
|
||||
@ -87,7 +85,7 @@ static GdkPixbuf *gdk_pixbuf__wbmp_image_load(FILE * f, GError **error)
|
||||
|
||||
GdkPixbuf *pb;
|
||||
|
||||
State = gdk_pixbuf__wbmp_image_begin_load(NULL, NULL, NULL, NULL, NULL,
|
||||
State = gdk_pixbuf__wbmp_image_begin_load(NULL, NULL, NULL,
|
||||
error);
|
||||
|
||||
if (State == NULL)
|
||||
@ -120,9 +118,7 @@ static GdkPixbuf *gdk_pixbuf__wbmp_image_load(FILE * f, GError **error)
|
||||
static gpointer
|
||||
gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
|
||||
ModuleUpdatedNotifyFunc updated_func,
|
||||
ModuleFrameDoneNotifyFunc frame_done_func,
|
||||
ModuleAnimationDoneNotifyFunc
|
||||
anim_done_func, gpointer user_data,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
struct wbmp_progressive_state *context;
|
||||
@ -285,7 +281,7 @@ static gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data,
|
||||
g_assert(context->pixbuf);
|
||||
|
||||
if(context->prepared_func)
|
||||
context->prepared_func(context->pixbuf, context->user_data);
|
||||
context->prepared_func(context->pixbuf, NULL, context->user_data);
|
||||
}
|
||||
}
|
||||
else if(context->needmore)
|
||||
|
@ -300,7 +300,7 @@ gdk_pixbuf__xbm_image_load_real (FILE *f, XBMData *context, GError **error)
|
||||
row_stride = gdk_pixbuf_get_rowstride (pixbuf);
|
||||
|
||||
if (context)
|
||||
(* context->prepare_func) (pixbuf, context->user_data);
|
||||
(* context->prepare_func) (pixbuf, NULL, context->user_data);
|
||||
|
||||
|
||||
/* Initialize PIXBUF */
|
||||
@ -355,8 +355,6 @@ gdk_pixbuf__xbm_image_load (FILE *f, GError **error)
|
||||
static gpointer
|
||||
gdk_pixbuf__xbm_image_begin_load (ModulePreparedNotifyFunc prepare_func,
|
||||
ModuleUpdatedNotifyFunc update_func,
|
||||
ModuleFrameDoneNotifyFunc frame_done_func,
|
||||
ModuleAnimationDoneNotifyFunc anim_done_func,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
|
@ -1424,8 +1424,6 @@ struct _XPMContext
|
||||
static gpointer
|
||||
gdk_pixbuf__xpm_image_begin_load (ModulePreparedNotifyFunc prepare_func,
|
||||
ModuleUpdatedNotifyFunc update_func,
|
||||
ModuleFrameDoneNotifyFunc frame_done_func,
|
||||
ModuleAnimationDoneNotifyFunc anim_done_func,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
@ -1471,7 +1469,9 @@ gdk_pixbuf__xpm_image_stop_load (gpointer data,
|
||||
pixbuf = gdk_pixbuf__xpm_image_load (context->file, error);
|
||||
|
||||
if (pixbuf != NULL) {
|
||||
(* context->prepare_func) (pixbuf, context->user_data);
|
||||
(* context->prepare_func) (pixbuf,
|
||||
NULL,
|
||||
context->user_data);
|
||||
(* context->update_func) (pixbuf, 0, 0, pixbuf->width, pixbuf->height, context->user_data);
|
||||
gdk_pixbuf_unref (pixbuf);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <math.h>
|
||||
#include <glib.h>
|
||||
#include "config.h"
|
||||
|
||||
#include "pixops.h"
|
||||
@ -93,6 +94,7 @@ pixops_scale_nearest (guchar *dest_buf,
|
||||
for (i = 0; i < (render_y1 - render_y0); i++)
|
||||
{
|
||||
const guchar *src = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride;
|
||||
/* FIXME Owen needs to look at this */
|
||||
guchar *dest = dest_buf + i * dest_rowstride;
|
||||
|
||||
x = render_x0 * x_step + x_step / 2;
|
||||
@ -160,7 +162,6 @@ pixops_composite_nearest (guchar *dest_buf,
|
||||
for (i = 0; i < (render_y1 - render_y0); i++)
|
||||
{
|
||||
const guchar *src = src_buf + (((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT) * src_rowstride;
|
||||
/* FIXME Owen needs to look at this */
|
||||
guchar *dest = dest_buf + i * dest_rowstride;
|
||||
|
||||
x = render_x0 * x_step + x_step / 2;
|
||||
@ -183,9 +184,9 @@ pixops_composite_nearest (guchar *dest_buf,
|
||||
|
||||
if (w != 0)
|
||||
{
|
||||
dest[0] = (w0 * src[0] + w1 * dest[0]) / w;
|
||||
dest[1] = (w0 * src[1] + w1 * dest[1]) / w;
|
||||
dest[2] = (w0 * src[2] + w1 * dest[2]) / w;
|
||||
dest[0] = (w0 * p[0] + w1 * dest[0]) / w;
|
||||
dest[1] = (w0 * p[1] + w1 * dest[1]) / w;
|
||||
dest[2] = (w0 * p[2] + w1 * dest[2]) / w;
|
||||
dest[3] = w / 0xff;
|
||||
}
|
||||
else
|
||||
@ -274,24 +275,38 @@ pixops_composite_color_nearest (guchar *dest_buf,
|
||||
for (j=0 ; j < (render_x1 - render_x0); j++)
|
||||
{
|
||||
const guchar *p = src + (x >> SCALE_SHIFT) * src_channels;
|
||||
unsigned int a0;
|
||||
int a0;
|
||||
int tmp;
|
||||
|
||||
if (src_has_alpha)
|
||||
a0 = (p[3] * overall_alpha + 0xff) >> 8;
|
||||
else
|
||||
a0 = overall_alpha;
|
||||
|
||||
if (a0 == 255)
|
||||
{
|
||||
dest[0] = p[0];
|
||||
dest[1] = p[1];
|
||||
dest[2] = p[2];
|
||||
}
|
||||
else
|
||||
if (((j + check_x) >> check_shift) & 1)
|
||||
{
|
||||
dest[0] = r2 + ((a0 * ((int)p[0] - r2) + 0xff) >> 8);
|
||||
dest[1] = g2 + ((a0 * ((int)p[1] - g2) + 0xff) >> 8);
|
||||
dest[2] = b2 + ((a0 * ((int)p[2] - b2) + 0xff) >> 8);
|
||||
tmp = ((int) p[0] - r2) * a0;
|
||||
dest[0] = r2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
|
||||
tmp = ((int) p[1] - g2) * a0;
|
||||
dest[1] = g2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
|
||||
tmp = ((int) p[2] - b2) * a0;
|
||||
dest[2] = b2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
dest[0] = r1 + ((a0 * ((int)p[0] - r1) + 0xff) >> 8);
|
||||
dest[1] = g1 + ((a0 * ((int)p[1] - g1) + 0xff) >> 8);
|
||||
dest[2] = b1 + ((a0 * ((int)p[2] - b1) + 0xff) >> 8);
|
||||
tmp = ((int) p[0] - r1) * a0;
|
||||
dest[0] = r1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
|
||||
tmp = ((int) p[1] - g1) * a0;
|
||||
dest[1] = g1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
|
||||
tmp = ((int) p[2] - b1) * a0;
|
||||
dest[2] = b1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
|
||||
}
|
||||
|
||||
if (dest_channels == 4)
|
||||
@ -1003,7 +1018,7 @@ pixops_process (guchar *dest_buf,
|
||||
|
||||
dest_x += (new_outbuf - outbuf) / dest_channels;
|
||||
|
||||
x = dest_x * x_step + scaled_x_offset;
|
||||
x = (dest_x - check_x + render_x0) * x_step + scaled_x_offset;
|
||||
outbuf = new_outbuf;
|
||||
|
||||
while (outbuf < outbuf_end)
|
||||
|
@ -70,6 +70,7 @@ enum {
|
||||
PROP_STRETCH,
|
||||
PROP_SIZE,
|
||||
PROP_SIZE_POINTS,
|
||||
PROP_SCALE,
|
||||
PROP_EDITABLE,
|
||||
PROP_STRIKETHROUGH,
|
||||
PROP_UNDERLINE,
|
||||
@ -84,6 +85,7 @@ enum {
|
||||
PROP_WEIGHT_SET,
|
||||
PROP_STRETCH_SET,
|
||||
PROP_SIZE_SET,
|
||||
PROP_SCALE_SET,
|
||||
PROP_EDITABLE_SET,
|
||||
PROP_STRIKETHROUGH_SET,
|
||||
PROP_UNDERLINE_SET,
|
||||
@ -283,6 +285,16 @@ gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class)
|
||||
0.0,
|
||||
G_PARAM_READABLE | G_PARAM_WRITABLE));
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_SCALE,
|
||||
g_param_spec_double ("scale",
|
||||
_("Font scale"),
|
||||
_("Font scaling factor"),
|
||||
0.0,
|
||||
G_MAXDOUBLE,
|
||||
1.0,
|
||||
G_PARAM_READABLE | G_PARAM_WRITABLE));
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_RISE,
|
||||
g_param_spec_int ("rise",
|
||||
@ -351,6 +363,10 @@ gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class)
|
||||
_("Font size set"),
|
||||
_("Whether this tag affects the font size"));
|
||||
|
||||
ADD_SET_PROP ("scale_set", PROP_SCALE_SET,
|
||||
_("Font scale set"),
|
||||
_("Whether this tag scales the font size by a factor"));
|
||||
|
||||
ADD_SET_PROP ("rise_set", PROP_RISE_SET,
|
||||
_("Rise set"),
|
||||
_("Whether this tag affects the rise"));
|
||||
@ -462,6 +478,10 @@ gtk_cell_renderer_text_get_property (GObject *object,
|
||||
g_value_set_double (value, ((double)celltext->font.size) / (double)PANGO_SCALE);
|
||||
break;
|
||||
|
||||
case PROP_SCALE:
|
||||
g_value_set_double (value, celltext->font_scale);
|
||||
break;
|
||||
|
||||
case PROP_EDITABLE:
|
||||
g_value_set_boolean (value, celltext->editable);
|
||||
break;
|
||||
@ -510,6 +530,10 @@ gtk_cell_renderer_text_get_property (GObject *object,
|
||||
g_value_set_boolean (value, celltext->size_set);
|
||||
break;
|
||||
|
||||
case PROP_SCALE_SET:
|
||||
g_value_set_boolean (value, celltext->scale_set);
|
||||
break;
|
||||
|
||||
case PROP_EDITABLE_SET:
|
||||
g_value_set_boolean (value, celltext->editable_set);
|
||||
break;
|
||||
@ -824,6 +848,11 @@ gtk_cell_renderer_text_set_property (GObject *object,
|
||||
g_object_notify (G_OBJECT (celltext), "font");
|
||||
break;
|
||||
|
||||
case PROP_SCALE:
|
||||
celltext->font_scale = g_value_get_double (value);
|
||||
celltext->scale_set = TRUE;
|
||||
break;
|
||||
|
||||
case PROP_SIZE_POINTS:
|
||||
celltext->font.size = g_value_get_double (value) * PANGO_SCALE;
|
||||
|
||||
@ -849,6 +878,7 @@ gtk_cell_renderer_text_set_property (GObject *object,
|
||||
celltext->underline_style = g_value_get_enum (value);
|
||||
celltext->underline_set = TRUE;
|
||||
g_object_notify (G_OBJECT (celltext), "underline_set");
|
||||
|
||||
break;
|
||||
|
||||
case PROP_RISE:
|
||||
@ -859,62 +889,54 @@ gtk_cell_renderer_text_set_property (GObject *object,
|
||||
|
||||
case PROP_BACKGROUND_SET:
|
||||
celltext->background_set = g_value_get_boolean (value);
|
||||
g_object_notify(G_OBJECT(object), "background_set");
|
||||
break;
|
||||
|
||||
case PROP_FOREGROUND_SET:
|
||||
celltext->foreground_set = g_value_get_boolean (value);
|
||||
g_object_notify(G_OBJECT(object), "foreground_set");
|
||||
break;
|
||||
|
||||
case PROP_FAMILY_SET:
|
||||
celltext->family_set = g_value_get_boolean (value);
|
||||
g_object_notify(G_OBJECT(object), "family_set");
|
||||
break;
|
||||
|
||||
case PROP_STYLE_SET:
|
||||
celltext->style_set = g_value_get_boolean (value);
|
||||
g_object_notify(G_OBJECT(object), "style_set");
|
||||
break;
|
||||
|
||||
case PROP_VARIANT_SET:
|
||||
celltext->variant_set = g_value_get_boolean (value);
|
||||
g_object_notify(G_OBJECT(object), "variant_set");
|
||||
break;
|
||||
|
||||
case PROP_WEIGHT_SET:
|
||||
celltext->weight_set = g_value_get_boolean (value);
|
||||
g_object_notify(G_OBJECT(object), "weight_set");
|
||||
break;
|
||||
|
||||
case PROP_STRETCH_SET:
|
||||
celltext->stretch_set = g_value_get_boolean (value);
|
||||
g_object_notify(G_OBJECT(object), "stretch_set");
|
||||
break;
|
||||
|
||||
case PROP_SIZE_SET:
|
||||
celltext->size_set = g_value_get_boolean (value);
|
||||
g_object_notify(G_OBJECT(object), "size_set");
|
||||
break;
|
||||
|
||||
case PROP_SCALE_SET:
|
||||
celltext->scale_set = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
case PROP_EDITABLE_SET:
|
||||
celltext->editable_set = g_value_get_boolean (value);
|
||||
g_object_notify(G_OBJECT(object), "editable_set");
|
||||
break;
|
||||
|
||||
case PROP_STRIKETHROUGH_SET:
|
||||
celltext->strikethrough_set = g_value_get_boolean (value);
|
||||
g_object_notify(G_OBJECT(object), "strikethrough_set");
|
||||
break;
|
||||
|
||||
case PROP_UNDERLINE_SET:
|
||||
celltext->underline_set = g_value_get_boolean (value);
|
||||
g_object_notify(G_OBJECT(object), "underline_set");
|
||||
break;
|
||||
|
||||
case PROP_RISE_SET:
|
||||
celltext->rise_set = g_value_get_boolean (value);
|
||||
g_object_notify(G_OBJECT(object), "rise_set");
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1012,6 +1034,10 @@ get_layout (GtkCellRendererText *celltext,
|
||||
celltext->font.size >= 0)
|
||||
add_attr (attr_list, pango_attr_size_new (celltext->font.size));
|
||||
|
||||
if (celltext->scale_set &&
|
||||
celltext->font_scale != 1.0)
|
||||
add_attr (attr_list, pango_attr_scale_new (celltext->font_scale));
|
||||
|
||||
if (celltext->underline_set)
|
||||
uline = celltext->underline_style;
|
||||
else
|
||||
|
@ -44,6 +44,7 @@ struct _GtkCellRendererText
|
||||
/*< private >*/
|
||||
gchar *text;
|
||||
PangoFontDescription font;
|
||||
gdouble font_scale;
|
||||
PangoColor foreground;
|
||||
PangoColor background;
|
||||
|
||||
@ -66,6 +67,8 @@ struct _GtkCellRendererText
|
||||
guint stretch_set : 1;
|
||||
guint size_set : 1;
|
||||
|
||||
guint scale_set : 1;
|
||||
|
||||
guint foreground_set : 1;
|
||||
guint background_set : 1;
|
||||
|
||||
|
@ -246,8 +246,8 @@ gtk_check_button_size_request (GtkWidget *widget,
|
||||
gint indicator_spacing;
|
||||
gint border_width = GTK_CONTAINER (widget)->border_width;
|
||||
|
||||
requisition->width = border_width + 2;
|
||||
requisition->height = border_width + 2;
|
||||
requisition->width = border_width * 2 + 2;
|
||||
requisition->height = border_width * 2 + 2;
|
||||
|
||||
child = GTK_BIN (widget)->child;
|
||||
if (child && GTK_WIDGET_VISIBLE (child))
|
||||
|
@ -1848,7 +1848,7 @@ gtk_color_selection_destroy (GtkObject *object)
|
||||
|
||||
if (priv->tooltips)
|
||||
{
|
||||
gtk_object_destroy (priv->tooltips);
|
||||
gtk_object_destroy (GTK_OBJECT (priv->tooltips));
|
||||
priv->tooltips = NULL;
|
||||
}
|
||||
|
||||
|
@ -523,7 +523,6 @@ gtk_hscale_draw_value (GtkScale *scale)
|
||||
{
|
||||
GtkStateType state_type;
|
||||
GtkWidget *widget;
|
||||
gchar buffer[32];
|
||||
gint width, height;
|
||||
gint x, y;
|
||||
|
||||
@ -536,9 +535,14 @@ gtk_hscale_draw_value (GtkScale *scale)
|
||||
{
|
||||
PangoLayout *layout;
|
||||
PangoRectangle logical_rect;
|
||||
gchar *txt;
|
||||
|
||||
txt = _gtk_scale_format_value (scale,
|
||||
GTK_RANGE (scale)->adjustment->value);
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, txt);
|
||||
g_free (txt);
|
||||
|
||||
sprintf (buffer, "%0.*f", GTK_RANGE (scale)->digits, GTK_RANGE (scale)->adjustment->value);
|
||||
layout = gtk_widget_create_pango_layout (widget, buffer);
|
||||
pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
|
||||
|
||||
switch (scale->value_pos)
|
||||
|
244
gtk/gtkimage.c
244
gtk/gtkimage.c
@ -28,11 +28,13 @@
|
||||
#include "gtkimage.h"
|
||||
#include "gtkiconfactory.h"
|
||||
#include "gtkstock.h"
|
||||
#include <string.h>
|
||||
|
||||
static void gtk_image_class_init (GtkImageClass *klass);
|
||||
static void gtk_image_init (GtkImage *image);
|
||||
static gint gtk_image_expose (GtkWidget *widget,
|
||||
GdkEventExpose *event);
|
||||
static void gtk_image_unmap (GtkWidget *widget);
|
||||
static void gtk_image_size_request (GtkWidget *widget,
|
||||
GtkRequisition *requisition);
|
||||
static void gtk_image_destroy (GtkObject *object);
|
||||
@ -85,6 +87,7 @@ gtk_image_class_init (GtkImageClass *class)
|
||||
|
||||
widget_class->expose_event = gtk_image_expose;
|
||||
widget_class->size_request = gtk_image_size_request;
|
||||
widget_class->unmap = gtk_image_unmap;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -163,11 +166,22 @@ gtk_image_new_from_image (GdkImage *gdk_image,
|
||||
* gtk_image_new_from_file:
|
||||
* @filename: a filename
|
||||
*
|
||||
* Creates a new #GtkImage displaying the file @filename. If the
|
||||
* file isn't found or can't be loaded, the #GtkImage will display
|
||||
* a "broken image" icon. If you need to detect failures to load
|
||||
* the file, use gdk_pixbuf_new_from_file() to load the file yourself,
|
||||
* then create the #GtkImage from the pixbuf.
|
||||
* Creates a new #GtkImage displaying the file @filename. If the file
|
||||
* isn't found or can't be loaded, the resulting #GtkImage will
|
||||
* display a "broken image" icon. This function never returns %NULL,
|
||||
* it always returns a valid #GtkImage widget.
|
||||
*
|
||||
* If the file contains an animation, the image will contain an
|
||||
* animation.
|
||||
*
|
||||
* If you need to detect failures to load the file, use
|
||||
* gdk_pixbuf_new_from_file() to load the file yourself, then create
|
||||
* the #GtkImage from the pixbuf. (Or for animations, use
|
||||
* gdk_pixbuf_animation_new_from_file()).
|
||||
*
|
||||
* The storage type (gtk_image_get_storage_type()) of the returned
|
||||
* image is not defined, it will be whatever is appropriate for
|
||||
* displaying the file.
|
||||
*
|
||||
* Return value: a new #GtkImage
|
||||
**/
|
||||
@ -194,7 +208,7 @@ gtk_image_new_from_file (const gchar *filename)
|
||||
*
|
||||
* Note that this function just creates an #GtkImage from the pixbuf. The
|
||||
* #GtkImage created will not react to state changes. Should you want that, you
|
||||
* should use @gtk_image_new_from_icon_set.
|
||||
* should use gtk_image_new_from_icon_set().
|
||||
*
|
||||
* Return value: a new #GtkImage
|
||||
**/
|
||||
@ -268,6 +282,31 @@ gtk_image_new_from_icon_set (GtkIconSet *icon_set,
|
||||
return GTK_WIDGET (image);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_image_new_from_animation:
|
||||
* @animation: an animation
|
||||
*
|
||||
* Creates a #GtkImage displaying the given animation.
|
||||
* The #GtkImage does not assume a reference to the
|
||||
* animation; you still need to unref it if you own references.
|
||||
* #GtkImage will add its own reference rather than adopting yours.
|
||||
*
|
||||
* Return value: a new #GtkImage widget
|
||||
**/
|
||||
GtkWidget*
|
||||
gtk_image_new_from_animation (GdkPixbufAnimation *animation)
|
||||
{
|
||||
GtkImage *image;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
|
||||
|
||||
image = gtk_type_new (GTK_TYPE_IMAGE);
|
||||
|
||||
gtk_image_set_from_animation (image, animation);
|
||||
|
||||
return GTK_WIDGET (image);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_image_set_from_pixmap:
|
||||
* @image: a #GtkImage
|
||||
@ -376,7 +415,7 @@ void
|
||||
gtk_image_set_from_file (GtkImage *image,
|
||||
const gchar *filename)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
GdkPixbufAnimation *anim;
|
||||
|
||||
g_return_if_fail (GTK_IS_IMAGE (image));
|
||||
g_return_if_fail (filename != NULL);
|
||||
@ -386,9 +425,9 @@ gtk_image_set_from_file (GtkImage *image,
|
||||
if (filename == NULL)
|
||||
return;
|
||||
|
||||
pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
|
||||
anim = gdk_pixbuf_animation_new_from_file (filename, NULL);
|
||||
|
||||
if (pixbuf == NULL)
|
||||
if (anim == NULL)
|
||||
{
|
||||
gtk_image_set_from_stock (image,
|
||||
GTK_STOCK_MISSING_IMAGE,
|
||||
@ -396,9 +435,22 @@ gtk_image_set_from_file (GtkImage *image,
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_image_set_from_pixbuf (image, pixbuf);
|
||||
/* We could just unconditionally set_from_animation,
|
||||
* but it's nicer for memory if we toss the animation
|
||||
* if it's just a single pixbuf
|
||||
*/
|
||||
|
||||
g_object_unref (G_OBJECT (pixbuf));
|
||||
if (gdk_pixbuf_animation_is_static_image (anim))
|
||||
{
|
||||
gtk_image_set_from_pixbuf (image,
|
||||
gdk_pixbuf_animation_get_static_image (anim));
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_image_set_from_animation (image, anim);
|
||||
}
|
||||
|
||||
g_object_unref (G_OBJECT (anim));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -500,6 +552,41 @@ gtk_image_set_from_icon_set (GtkImage *image,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_image_set_from_animation:
|
||||
* @image: a #GtkImage
|
||||
* @animation: the #GdkPixbufAnimation
|
||||
*
|
||||
* Causes the #GtkImage to display the given animation (or display
|
||||
* nothing, if you set the animation to %NULL).
|
||||
**/
|
||||
void
|
||||
gtk_image_set_from_animation (GtkImage *image,
|
||||
GdkPixbufAnimation *animation)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_IMAGE (image));
|
||||
g_return_if_fail (animation == NULL ||
|
||||
GDK_IS_PIXBUF_ANIMATION (animation));
|
||||
|
||||
if (animation)
|
||||
g_object_ref (G_OBJECT (animation));
|
||||
|
||||
gtk_image_reset (image);
|
||||
|
||||
if (animation != NULL)
|
||||
{
|
||||
image->storage_type = GTK_IMAGE_ANIMATION;
|
||||
|
||||
image->data.anim.anim = animation;
|
||||
image->data.anim.frame_timeout = 0;
|
||||
image->data.anim.iter = NULL;
|
||||
|
||||
gtk_image_update_size (image,
|
||||
gdk_pixbuf_animation_get_width (animation),
|
||||
gdk_pixbuf_animation_get_height (animation));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_image_get_storage_type:
|
||||
* @image: a #GtkImage
|
||||
@ -660,6 +747,33 @@ gtk_image_get_icon_set (GtkImage *image,
|
||||
*size = image->data.icon_set.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_image_get_animation:
|
||||
* @image: a #GtkImage
|
||||
*
|
||||
*
|
||||
* Gets the #GdkPixbufAnimation being displayed by the #GtkImage.
|
||||
* The storage type of the image must be %GTK_IMAGE_EMPTY or
|
||||
* %GTK_IMAGE_ANIMATION (see gtk_image_get_storage_type()).
|
||||
* The caller of this function does not own a reference to the
|
||||
* returned animation.
|
||||
*
|
||||
* Return value: the displayed animation, or %NULL if the image is empty
|
||||
**/
|
||||
GdkPixbufAnimation*
|
||||
gtk_image_get_animation (GtkImage *image)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_IMAGE (image), NULL);
|
||||
g_return_val_if_fail (image->storage_type == GTK_IMAGE_ANIMATION ||
|
||||
image->storage_type == GTK_IMAGE_EMPTY,
|
||||
NULL);
|
||||
|
||||
if (image->storage_type == GTK_IMAGE_EMPTY)
|
||||
image->data.anim.anim = NULL;
|
||||
|
||||
return image->data.anim.anim;
|
||||
}
|
||||
|
||||
GtkWidget*
|
||||
gtk_image_new (GdkImage *val,
|
||||
GdkBitmap *mask)
|
||||
@ -695,6 +809,55 @@ gtk_image_get (GtkImage *image,
|
||||
gtk_image_get_image (image, val, mask);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_image_unmap (GtkWidget *widget)
|
||||
{
|
||||
GtkImage *image;
|
||||
|
||||
image = GTK_IMAGE (widget);
|
||||
|
||||
if (image->storage_type == GTK_IMAGE_ANIMATION)
|
||||
{
|
||||
/* Reset the animation */
|
||||
|
||||
if (image->data.anim.frame_timeout)
|
||||
{
|
||||
g_source_remove (image->data.anim.frame_timeout);
|
||||
image->data.anim.frame_timeout = 0;
|
||||
}
|
||||
|
||||
if (image->data.anim.iter)
|
||||
{
|
||||
g_object_unref (G_OBJECT (image->data.anim.iter));
|
||||
image->data.anim.iter = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (GTK_WIDGET_CLASS (parent_class)->unmap)
|
||||
GTK_WIDGET_CLASS (parent_class)->unmap (widget);
|
||||
}
|
||||
|
||||
gint
|
||||
animation_timeout (gpointer data)
|
||||
{
|
||||
GtkImage *image;
|
||||
|
||||
image = GTK_IMAGE (data);
|
||||
|
||||
image->data.anim.frame_timeout = 0;
|
||||
|
||||
gdk_pixbuf_animation_iter_advance (image->data.anim.iter, NULL);
|
||||
|
||||
if (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter) >= 0)
|
||||
image->data.anim.frame_timeout =
|
||||
g_timeout_add (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter),
|
||||
animation_timeout,
|
||||
image);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (image));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gint
|
||||
gtk_image_expose (GtkWidget *widget,
|
||||
@ -778,6 +941,24 @@ gtk_image_expose (GtkWidget *widget,
|
||||
}
|
||||
break;
|
||||
|
||||
case GTK_IMAGE_ANIMATION:
|
||||
{
|
||||
if (image->data.anim.iter == NULL)
|
||||
{
|
||||
image->data.anim.iter = gdk_pixbuf_animation_get_iter (image->data.anim.anim, NULL);
|
||||
|
||||
if (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter) >= 0)
|
||||
image->data.anim.frame_timeout =
|
||||
g_timeout_add (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter),
|
||||
animation_timeout,
|
||||
image);
|
||||
}
|
||||
|
||||
image_bound.width = gdk_pixbuf_animation_get_width (image->data.anim.anim);
|
||||
image_bound.height = gdk_pixbuf_animation_get_height (image->data.anim.anim);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -849,6 +1030,25 @@ gtk_image_expose (GtkWidget *widget,
|
||||
}
|
||||
break;
|
||||
|
||||
case GTK_IMAGE_ANIMATION:
|
||||
/* don't advance the anim iter here, or we could get frame changes between two
|
||||
* exposes of different areas.
|
||||
*/
|
||||
|
||||
gdk_pixbuf_render_to_drawable_alpha (gdk_pixbuf_animation_iter_get_pixbuf (image->data.anim.iter),
|
||||
widget->window,
|
||||
image_bound.x - x,
|
||||
image_bound.y - y,
|
||||
image_bound.x,
|
||||
image_bound.y,
|
||||
image_bound.width,
|
||||
image_bound.height,
|
||||
GDK_PIXBUF_ALPHA_FULL,
|
||||
128,
|
||||
GDK_RGB_DITHER_NORMAL,
|
||||
0, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -876,9 +1076,6 @@ gtk_image_clear (GtkImage *image)
|
||||
if (image->data.pixmap.mask)
|
||||
g_object_unref (G_OBJECT (image->data.pixmap.mask));
|
||||
|
||||
image->data.pixmap.pixmap = NULL;
|
||||
image->data.pixmap.mask = NULL;
|
||||
|
||||
break;
|
||||
|
||||
case GTK_IMAGE_IMAGE:
|
||||
@ -889,9 +1086,6 @@ gtk_image_clear (GtkImage *image)
|
||||
if (image->data.image.mask)
|
||||
g_object_unref (G_OBJECT (image->data.image.mask));
|
||||
|
||||
image->data.image.image = NULL;
|
||||
image->data.image.mask = NULL;
|
||||
|
||||
break;
|
||||
|
||||
case GTK_IMAGE_PIXBUF:
|
||||
@ -899,26 +1093,26 @@ gtk_image_clear (GtkImage *image)
|
||||
if (image->data.pixbuf.pixbuf)
|
||||
g_object_unref (G_OBJECT (image->data.pixbuf.pixbuf));
|
||||
|
||||
image->data.pixbuf.pixbuf = NULL;
|
||||
|
||||
break;
|
||||
|
||||
case GTK_IMAGE_STOCK:
|
||||
|
||||
g_free (image->data.stock.stock_id);
|
||||
|
||||
image->data.stock.stock_id = NULL;
|
||||
image->data.stock.size = 0;
|
||||
|
||||
break;
|
||||
|
||||
case GTK_IMAGE_ICON_SET:
|
||||
if (image->data.icon_set.icon_set)
|
||||
gtk_icon_set_unref (image->data.icon_set.icon_set);
|
||||
|
||||
image->data.icon_set.size = 0;
|
||||
image->data.icon_set.icon_set = NULL;
|
||||
break;
|
||||
|
||||
case GTK_IMAGE_ANIMATION:
|
||||
if (image->data.anim.frame_timeout)
|
||||
g_source_remove (image->data.anim.frame_timeout);
|
||||
|
||||
if (image->data.anim.anim)
|
||||
g_object_unref (G_OBJECT (image->data.anim.anim));
|
||||
break;
|
||||
|
||||
case GTK_IMAGE_EMPTY:
|
||||
@ -928,6 +1122,8 @@ gtk_image_clear (GtkImage *image)
|
||||
}
|
||||
|
||||
image->storage_type = GTK_IMAGE_EMPTY;
|
||||
|
||||
memset (&image->data, '\0', sizeof (image->data));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -52,6 +52,7 @@ typedef struct _GtkImageImageData GtkImageImageData;
|
||||
typedef struct _GtkImagePixbufData GtkImagePixbufData;
|
||||
typedef struct _GtkImageStockData GtkImageStockData;
|
||||
typedef struct _GtkImageIconSetData GtkImageIconSetData;
|
||||
typedef struct _GtkImageAnimationData GtkImageAnimationData;
|
||||
|
||||
struct _GtkImagePixmapData
|
||||
{
|
||||
@ -82,6 +83,13 @@ struct _GtkImageIconSetData
|
||||
GtkIconSize size;
|
||||
};
|
||||
|
||||
struct _GtkImageAnimationData
|
||||
{
|
||||
GdkPixbufAnimation *anim;
|
||||
GdkPixbufAnimationIter *iter;
|
||||
guint frame_timeout;
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GTK_IMAGE_EMPTY,
|
||||
@ -89,7 +97,8 @@ typedef enum
|
||||
GTK_IMAGE_IMAGE,
|
||||
GTK_IMAGE_PIXBUF,
|
||||
GTK_IMAGE_STOCK,
|
||||
GTK_IMAGE_ICON_SET
|
||||
GTK_IMAGE_ICON_SET,
|
||||
GTK_IMAGE_ANIMATION
|
||||
} GtkImageType;
|
||||
|
||||
struct _GtkImage
|
||||
@ -105,6 +114,7 @@ struct _GtkImage
|
||||
GtkImagePixbufData pixbuf;
|
||||
GtkImageStockData stock;
|
||||
GtkImageIconSetData icon_set;
|
||||
GtkImageAnimationData anim;
|
||||
} data;
|
||||
};
|
||||
|
||||
@ -125,6 +135,7 @@ GtkWidget* gtk_image_new_from_stock (const gchar *stock_id,
|
||||
GtkIconSize size);
|
||||
GtkWidget* gtk_image_new_from_icon_set (GtkIconSet *icon_set,
|
||||
GtkIconSize size);
|
||||
GtkWidget* gtk_image_new_from_animation (GdkPixbufAnimation *animation);
|
||||
|
||||
void gtk_image_set_from_pixmap (GtkImage *image,
|
||||
GdkPixmap *pixmap,
|
||||
@ -142,6 +153,8 @@ void gtk_image_set_from_stock (GtkImage *image,
|
||||
void gtk_image_set_from_icon_set (GtkImage *image,
|
||||
GtkIconSet *icon_set,
|
||||
GtkIconSize size);
|
||||
void gtk_image_set_from_animation (GtkImage *image,
|
||||
GdkPixbufAnimation *animation);
|
||||
|
||||
GtkImageType gtk_image_get_storage_type (GtkImage *image);
|
||||
|
||||
@ -158,6 +171,7 @@ void gtk_image_get_stock (GtkImage *image,
|
||||
void gtk_image_get_icon_set (GtkImage *image,
|
||||
GtkIconSet **icon_set,
|
||||
GtkIconSize *size);
|
||||
GdkPixbufAnimation* gtk_image_get_animation (GtkImage *image);
|
||||
|
||||
|
||||
#ifndef GTK_DISABLE_DEPRECATED
|
||||
|
@ -36,6 +36,7 @@ NONE:INT,INT
|
||||
NONE:NONE
|
||||
NONE:POINTER
|
||||
NONE:STRING,INT,POINTER
|
||||
STRING:DOUBLE
|
||||
VOID:BOOLEAN
|
||||
VOID:BOXED
|
||||
VOID:BOXED,BOXED
|
||||
|
@ -36,6 +36,7 @@ NONE:INT,INT
|
||||
NONE:NONE
|
||||
NONE:POINTER
|
||||
NONE:STRING,INT,POINTER
|
||||
STRING:DOUBLE
|
||||
VOID:BOOLEAN
|
||||
VOID:BOXED
|
||||
VOID:BOXED,BOXED
|
||||
|
@ -98,6 +98,7 @@ struct _GtkRangeClass
|
||||
GtkTroughType trough);
|
||||
|
||||
/* Completely broken virtual functions, please ignore */
|
||||
|
||||
void (* draw_background) (GtkRange *range);
|
||||
void (* clear_background) (GtkRange *range);
|
||||
void (* draw_trough) (GtkRange *range);
|
||||
|
109
gtk/gtkscale.c
109
gtk/gtkscale.c
@ -27,6 +27,7 @@
|
||||
#include <math.h>
|
||||
#include "gtkintl.h"
|
||||
#include "gtkscale.h"
|
||||
#include "gtkmarshal.h"
|
||||
|
||||
enum {
|
||||
ARG_0,
|
||||
@ -35,6 +36,12 @@ enum {
|
||||
ARG_VALUE_POS
|
||||
};
|
||||
|
||||
enum {
|
||||
FORMAT_VALUE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL];
|
||||
|
||||
static void gtk_scale_class_init (GtkScaleClass *klass);
|
||||
static void gtk_scale_init (GtkScale *scale);
|
||||
@ -78,6 +85,22 @@ gtk_scale_get_type (void)
|
||||
return scale_type;
|
||||
}
|
||||
|
||||
gboolean
|
||||
single_string_accumulator (GSignalInvocationHint *ihint,
|
||||
GValue *return_accu,
|
||||
const GValue *handler_return,
|
||||
gpointer dummy)
|
||||
{
|
||||
gboolean continue_emission;
|
||||
gchar *str;
|
||||
|
||||
str = g_value_get_string (handler_return);
|
||||
g_value_set_string (return_accu, str);
|
||||
continue_emission = str == NULL;
|
||||
|
||||
return continue_emission;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_scale_class_init (GtkScaleClass *class)
|
||||
{
|
||||
@ -104,6 +127,16 @@ gtk_scale_class_init (GtkScaleClass *class)
|
||||
GTK_ARG_READWRITE,
|
||||
ARG_VALUE_POS);
|
||||
|
||||
signals[FORMAT_VALUE] =
|
||||
g_signal_newc ("format_value",
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkScaleClass, format_value),
|
||||
single_string_accumulator, NULL,
|
||||
gtk_marshal_STRING__DOUBLE,
|
||||
G_TYPE_STRING, 1,
|
||||
G_TYPE_DOUBLE);
|
||||
|
||||
object_class->set_arg = gtk_scale_set_arg;
|
||||
object_class->get_arg = gtk_scale_get_arg;
|
||||
|
||||
@ -280,58 +313,27 @@ gtk_scale_get_value_size (GtkScale *scale,
|
||||
{
|
||||
PangoLayout *layout;
|
||||
PangoRectangle logical_rect;
|
||||
gchar buffer[128];
|
||||
gdouble value;
|
||||
gint digits;
|
||||
gint i, j;
|
||||
gchar *txt;
|
||||
|
||||
range = GTK_RANGE (scale);
|
||||
|
||||
layout = gtk_widget_create_pango_layout (GTK_WIDGET (scale), NULL);
|
||||
|
||||
value = ABS (range->adjustment->lower);
|
||||
if (value == 0) value = 1;
|
||||
digits = log10 (value) + 1;
|
||||
if (digits > 13)
|
||||
digits = 13;
|
||||
txt = _gtk_scale_format_value (scale, range->adjustment->lower);
|
||||
pango_layout_set_text (layout, txt, -1);
|
||||
g_free (txt);
|
||||
|
||||
i = 0;
|
||||
if (range->adjustment->lower < 0)
|
||||
buffer[i++] = '-';
|
||||
for (j = 0; j < digits; j++)
|
||||
buffer[i++] = '0';
|
||||
if (GTK_RANGE (scale)->digits)
|
||||
buffer[i++] = '.';
|
||||
for (j = 0; j < GTK_RANGE (scale)->digits; j++)
|
||||
buffer[i++] = '0';
|
||||
buffer[i] = '\0';
|
||||
|
||||
pango_layout_set_text (layout, buffer, i);
|
||||
pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
|
||||
|
||||
if (width)
|
||||
*width = logical_rect.width;
|
||||
if (height)
|
||||
*height = logical_rect.width;
|
||||
*height = logical_rect.height;
|
||||
|
||||
value = ABS (range->adjustment->upper);
|
||||
if (value == 0) value = 1;
|
||||
digits = log10 (value) + 1;
|
||||
if (digits > 13)
|
||||
digits = 13;
|
||||
txt = _gtk_scale_format_value (scale, range->adjustment->upper);
|
||||
pango_layout_set_text (layout, txt, -1);
|
||||
g_free (txt);
|
||||
|
||||
i = 0;
|
||||
if (range->adjustment->upper < 0)
|
||||
buffer[i++] = '-';
|
||||
for (j = 0; j < digits; j++)
|
||||
buffer[i++] = '0';
|
||||
if (GTK_RANGE (scale)->digits)
|
||||
buffer[i++] = '.';
|
||||
for (j = 0; j < GTK_RANGE (scale)->digits; j++)
|
||||
buffer[i++] = '0';
|
||||
buffer[i] = '\0';
|
||||
|
||||
pango_layout_set_text (layout, buffer, i);
|
||||
pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
|
||||
|
||||
if (width)
|
||||
@ -383,3 +385,32 @@ gtk_scale_draw_background (GtkRange *range)
|
||||
|
||||
gtk_scale_draw_value (GTK_SCALE (range));
|
||||
}
|
||||
|
||||
/**
|
||||
* _gtk_scale_format_value:
|
||||
* @scale: a #GtkScale
|
||||
* @value: adjustment value
|
||||
*
|
||||
* Emits "format_value" signal to format the value, if no user
|
||||
* signal handlers, falls back to a default format.
|
||||
*
|
||||
* Return value: formatted value
|
||||
**/
|
||||
gchar*
|
||||
_gtk_scale_format_value (GtkScale *scale,
|
||||
gdouble value)
|
||||
{
|
||||
gchar *fmt = NULL;
|
||||
|
||||
g_signal_emit (G_OBJECT (scale),
|
||||
signals[FORMAT_VALUE],
|
||||
0,
|
||||
value,
|
||||
&fmt);
|
||||
|
||||
if (fmt)
|
||||
return fmt;
|
||||
else
|
||||
return g_strdup_printf ("%0.*f", GTK_RANGE (scale)->digits,
|
||||
value);
|
||||
}
|
||||
|
@ -62,6 +62,9 @@ struct _GtkScaleClass
|
||||
|
||||
gint value_spacing;
|
||||
|
||||
gchar* (* format_value) (GtkRange *range,
|
||||
gdouble value);
|
||||
|
||||
void (* draw_value) (GtkScale *scale);
|
||||
};
|
||||
|
||||
@ -79,6 +82,9 @@ void gtk_scale_get_value_size (GtkScale *scale,
|
||||
|
||||
void gtk_scale_draw_value (GtkScale *scale);
|
||||
|
||||
gchar *_gtk_scale_format_value (GtkScale *scale,
|
||||
gdouble value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
@ -2106,6 +2106,127 @@ gtk_text_buffer_remove_tag_by_name (GtkTextBuffer *buffer,
|
||||
gtk_text_buffer_emit_tag (buffer, tag, FALSE, start, end);
|
||||
}
|
||||
|
||||
static gint
|
||||
pointer_cmp (gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
if (a < b)
|
||||
return -1;
|
||||
else if (a > b)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_buffer_remove_all_tags:
|
||||
* @buffer: a #GtkTextBuffer
|
||||
* @start: one bound of range to be untagged
|
||||
* @end: other bound of range to be untagged
|
||||
*
|
||||
* Removes all tags in the range between @start and @end. Be careful
|
||||
* with this function; it could remove tags added in code unrelated to
|
||||
* the code you're currently writing. That is, using this function is
|
||||
* probably a bad idea if you have two or more unrelated code sections
|
||||
* that add tags.
|
||||
**/
|
||||
void
|
||||
gtk_text_buffer_remove_all_tags (GtkTextBuffer *buffer,
|
||||
const GtkTextIter *start,
|
||||
const GtkTextIter *end)
|
||||
{
|
||||
GtkTextIter first, second, tmp;
|
||||
GSList *tags;
|
||||
GSList *tmp_list;
|
||||
GSList *prev;
|
||||
GtkTextTag *tag;
|
||||
|
||||
g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
|
||||
g_return_if_fail (start != NULL);
|
||||
g_return_if_fail (end != NULL);
|
||||
|
||||
first = *start;
|
||||
second = *end;
|
||||
|
||||
gtk_text_iter_reorder (&first, &second);
|
||||
|
||||
/* Get all tags turned on at the start */
|
||||
tags = gtk_text_iter_get_tags (&first);
|
||||
|
||||
/* Find any that are toggled on within the range */
|
||||
tmp = first;
|
||||
while (gtk_text_iter_forward_to_tag_toggle (&tmp, NULL))
|
||||
{
|
||||
GSList *toggled;
|
||||
GSList *tmp_list2;
|
||||
|
||||
if (gtk_text_iter_compare (&tmp, &second) >= 0)
|
||||
break; /* past the end of the range */
|
||||
|
||||
toggled = gtk_text_iter_get_toggled_tags (&tmp, TRUE);
|
||||
|
||||
/* We could end up with a really big-ass list here.
|
||||
* Fix it someday.
|
||||
*/
|
||||
tmp_list2 = toggled;
|
||||
while (tmp_list2 != NULL)
|
||||
{
|
||||
tags = g_slist_prepend (tags, tmp_list2->data);
|
||||
|
||||
tmp_list2 = g_slist_next (tmp_list2);
|
||||
}
|
||||
|
||||
g_slist_free (toggled);
|
||||
}
|
||||
|
||||
/* Sort the list */
|
||||
tags = g_slist_sort (tags, pointer_cmp);
|
||||
|
||||
/* Strip duplicates */
|
||||
tag = NULL;
|
||||
prev = NULL;
|
||||
tmp_list = tags;
|
||||
while (tmp_list != NULL)
|
||||
{
|
||||
if (tag == tmp_list->data)
|
||||
{
|
||||
/* duplicate */
|
||||
if (prev)
|
||||
prev->next = tmp_list->next;
|
||||
|
||||
tmp_list->next = NULL;
|
||||
|
||||
g_slist_free (tmp_list);
|
||||
|
||||
tmp_list = prev->next;
|
||||
/* prev is unchanged */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* not a duplicate */
|
||||
tag = GTK_TEXT_TAG (tmp_list->data);
|
||||
prev = tmp_list;
|
||||
tmp_list = tmp_list->next;
|
||||
}
|
||||
}
|
||||
|
||||
g_list_foreach (tags, (GFunc) g_object_ref, NULL);
|
||||
|
||||
tmp_list = tags;
|
||||
while (tmp_list != NULL)
|
||||
{
|
||||
tag = GTK_TEXT_TAG (tmp_list->data);
|
||||
|
||||
gtk_text_buffer_remove_tag (buffer, tag, &first, &second);
|
||||
|
||||
tmp_list = tmp_list->next;
|
||||
}
|
||||
|
||||
g_list_foreach (tags, (GFunc) g_object_unref, NULL);
|
||||
|
||||
g_slist_free (tags);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Obtain various iterators
|
||||
|
@ -266,6 +266,9 @@ void gtk_text_buffer_remove_tag_by_name (GtkTextBuffer *buffer,
|
||||
const gchar *name,
|
||||
const GtkTextIter *start,
|
||||
const GtkTextIter *end);
|
||||
void gtk_text_buffer_remove_all_tags (GtkTextBuffer *buffer,
|
||||
const GtkTextIter *start,
|
||||
const GtkTextIter *end);
|
||||
|
||||
|
||||
/* You can either ignore the return value, or use it to
|
||||
|
@ -1511,7 +1511,7 @@ gtk_text_iter_is_end (const GtkTextIter *iter)
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_iter_is_first:
|
||||
* gtk_text_iter_is_start:
|
||||
* @iter: an iterator
|
||||
*
|
||||
* Returns TRUE if @iter is the first iterator in the buffer, that is
|
||||
@ -1520,7 +1520,7 @@ gtk_text_iter_is_end (const GtkTextIter *iter)
|
||||
* Return value: whether @iter is the first in the buffer
|
||||
**/
|
||||
gboolean
|
||||
gtk_text_iter_is_first (const GtkTextIter *iter)
|
||||
gtk_text_iter_is_start (const GtkTextIter *iter)
|
||||
{
|
||||
return gtk_text_iter_get_offset (iter) == 0;
|
||||
}
|
||||
@ -4253,7 +4253,7 @@ lines_window_init (LinesWindow *win,
|
||||
/* If we start on line 1, there are 2 lines to search (0 and 1), so
|
||||
* n_lines can be 2.
|
||||
*/
|
||||
if (gtk_text_iter_is_first (start) ||
|
||||
if (gtk_text_iter_is_start (start) ||
|
||||
gtk_text_iter_get_line (start) + 1 < win->n_lines)
|
||||
{
|
||||
/* Already at the end, or not enough lines to match */
|
||||
|
@ -108,7 +108,8 @@ GSList * gtk_text_iter_get_marks (const GtkTextIter *iter);
|
||||
GtkTextChildAnchor* gtk_text_iter_get_child_anchor (const GtkTextIter *iter);
|
||||
|
||||
/* Return list of tags toggled at this point (toggled_on determines
|
||||
whether the list is of on-toggles or off-toggles) */
|
||||
* whether the list is of on-toggles or off-toggles)
|
||||
*/
|
||||
GSList *gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
|
||||
gboolean toggled_on);
|
||||
|
||||
@ -145,7 +146,7 @@ gboolean gtk_text_iter_get_attributes (const GtkTextIter *iter,
|
||||
GtkTextAttributes *values);
|
||||
gchar* gtk_text_iter_get_language (const GtkTextIter *iter);
|
||||
gboolean gtk_text_iter_is_end (const GtkTextIter *iter);
|
||||
gboolean gtk_text_iter_is_first (const GtkTextIter *iter);
|
||||
gboolean gtk_text_iter_is_start (const GtkTextIter *iter);
|
||||
|
||||
/*
|
||||
* Moving around the buffer
|
||||
|
@ -1280,6 +1280,16 @@ add_text_attrs (GtkTextLayout *layout,
|
||||
attr->end_index = start + byte_count;
|
||||
|
||||
pango_attr_list_insert (attrs, attr);
|
||||
|
||||
if (style->font_scale != 1.0)
|
||||
{
|
||||
attr = pango_attr_scale_new (style->font_scale);
|
||||
|
||||
attr->start_index = start;
|
||||
attr->end_index = start + byte_count;
|
||||
|
||||
pango_attr_list_insert (attrs, attr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -85,6 +85,7 @@ enum {
|
||||
PROP_STRETCH,
|
||||
PROP_SIZE,
|
||||
PROP_SIZE_POINTS,
|
||||
PROP_SCALE,
|
||||
PROP_PIXELS_ABOVE_LINES,
|
||||
PROP_PIXELS_BELOW_LINES,
|
||||
PROP_PIXELS_INSIDE_WRAP,
|
||||
@ -114,6 +115,7 @@ enum {
|
||||
PROP_WEIGHT_SET,
|
||||
PROP_STRETCH_SET,
|
||||
PROP_SIZE_SET,
|
||||
PROP_SCALE_SET,
|
||||
PROP_PIXELS_ABOVE_LINES_SET,
|
||||
PROP_PIXELS_BELOW_LINES_SET,
|
||||
PROP_PIXELS_INSIDE_WRAP_SET,
|
||||
@ -349,6 +351,16 @@ gtk_text_tag_class_init (GtkTextTagClass *klass)
|
||||
0,
|
||||
G_PARAM_READABLE | G_PARAM_WRITABLE));
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_SCALE,
|
||||
g_param_spec_double ("scale",
|
||||
_("Font scale"),
|
||||
_("Font scale"),
|
||||
0.0,
|
||||
G_MAXDOUBLE,
|
||||
1.0,
|
||||
G_PARAM_READABLE | G_PARAM_WRITABLE));
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_SIZE_POINTS,
|
||||
g_param_spec_double ("size_points",
|
||||
@ -543,6 +555,10 @@ gtk_text_tag_class_init (GtkTextTagClass *klass)
|
||||
_("Font size set"),
|
||||
_("Whether this tag affects the font size"));
|
||||
|
||||
ADD_SET_PROP ("scale_set", PROP_SCALE_SET,
|
||||
_("Font scale set"),
|
||||
_("Whether this tag scales the font size by a factor"));
|
||||
|
||||
ADD_SET_PROP ("justification_set", PROP_JUSTIFICATION_SET,
|
||||
_("Justification set"),
|
||||
_("Whether this tag affects paragraph justification"));
|
||||
@ -963,6 +979,12 @@ gtk_text_tag_set_property (GObject *object,
|
||||
size_changed = TRUE;
|
||||
break;
|
||||
|
||||
case PROP_SCALE:
|
||||
text_tag->values->font_scale = g_value_get_double (value);
|
||||
text_tag->scale_set = TRUE;
|
||||
size_changed = TRUE;
|
||||
break;
|
||||
|
||||
case PROP_SIZE_POINTS:
|
||||
text_tag->values->font.size = g_value_get_double (value) * PANGO_SCALE;
|
||||
text_tag->size_set = TRUE;
|
||||
@ -1152,6 +1174,11 @@ gtk_text_tag_set_property (GObject *object,
|
||||
size_changed = TRUE;
|
||||
break;
|
||||
|
||||
case PROP_SCALE_SET:
|
||||
text_tag->scale_set = g_value_get_boolean (value);
|
||||
size_changed = TRUE;
|
||||
break;
|
||||
|
||||
case PROP_PIXELS_ABOVE_LINES_SET:
|
||||
text_tag->pixels_above_lines_set = g_value_get_boolean (value);
|
||||
size_changed = TRUE;
|
||||
@ -1337,6 +1364,10 @@ gtk_text_tag_get_property (GObject *object,
|
||||
g_value_set_double (value, ((double)tag->values->font.size) / (double)PANGO_SCALE);
|
||||
break;
|
||||
|
||||
case PROP_SCALE:
|
||||
g_value_set_double (value, tag->values->font_scale);
|
||||
break;
|
||||
|
||||
case PROP_PIXELS_ABOVE_LINES:
|
||||
g_value_set_int (value, tag->values->pixels_above_lines);
|
||||
break;
|
||||
@ -1446,6 +1477,10 @@ gtk_text_tag_get_property (GObject *object,
|
||||
g_value_set_boolean (value, tag->size_set);
|
||||
break;
|
||||
|
||||
case PROP_SCALE_SET:
|
||||
g_value_set_boolean (value, tag->scale_set);
|
||||
break;
|
||||
|
||||
case PROP_PIXELS_ABOVE_LINES_SET:
|
||||
g_value_set_boolean (value, tag->pixels_above_lines_set);
|
||||
break;
|
||||
@ -1724,6 +1759,8 @@ gtk_text_attributes_new (void)
|
||||
|
||||
values->language = gtk_get_default_language ();
|
||||
|
||||
values->font_scale = 1.0;
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
@ -1965,6 +2002,10 @@ _gtk_text_attributes_fill_from_tags (GtkTextAttributes *dest,
|
||||
if (tag->size_set)
|
||||
dest->font.size = vals->font.size;
|
||||
|
||||
/* multiply all the scales together to get a composite */
|
||||
if (tag->scale_set)
|
||||
dest->font_scale *= vals->font_scale;
|
||||
|
||||
if (tag->justification_set)
|
||||
dest->justification = vals->justification;
|
||||
|
||||
@ -2038,6 +2079,7 @@ _gtk_text_tag_affects_size (GtkTextTag *tag)
|
||||
tag->variant_set ||
|
||||
tag->weight_set ||
|
||||
tag->size_set ||
|
||||
tag->scale_set ||
|
||||
tag->stretch_set ||
|
||||
tag->justification_set ||
|
||||
tag->left_margin_set ||
|
||||
|
@ -60,6 +60,7 @@ struct _GtkTextTag
|
||||
guint weight_set : 1;
|
||||
guint stretch_set : 1;
|
||||
guint size_set : 1;
|
||||
guint scale_set : 1;
|
||||
guint fg_stipple_set : 1;
|
||||
guint justification_set : 1;
|
||||
guint left_margin_set : 1;
|
||||
@ -148,6 +149,8 @@ struct _GtkTextAttributes
|
||||
/* Individual chunks of this can be set/unset as a group */
|
||||
PangoFontDescription font;
|
||||
|
||||
gdouble font_scale;
|
||||
|
||||
gint left_margin;
|
||||
|
||||
gint indent;
|
||||
|
@ -506,6 +506,7 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
|
||||
GTK_ARG_READWRITE, ARG_PIXELS_INSIDE_WRAP);
|
||||
gtk_object_add_arg_type ("GtkTextView::editable", GTK_TYPE_BOOL,
|
||||
GTK_ARG_READWRITE, ARG_EDITABLE);
|
||||
|
||||
gtk_object_add_arg_type ("GtkTextView::wrap_mode", GTK_TYPE_WRAP_MODE,
|
||||
GTK_ARG_READWRITE, ARG_WRAP_MODE);
|
||||
gtk_object_add_arg_type ("GtkTextView::justify", GTK_TYPE_JUSTIFICATION,
|
||||
|
@ -532,7 +532,6 @@ gtk_vscale_draw_value (GtkScale *scale)
|
||||
{
|
||||
GtkStateType state_type;
|
||||
GtkWidget *widget;
|
||||
gchar buffer[32];
|
||||
gint width, height;
|
||||
gint x, y;
|
||||
|
||||
@ -545,10 +544,14 @@ gtk_vscale_draw_value (GtkScale *scale)
|
||||
{
|
||||
PangoLayout *layout;
|
||||
PangoRectangle logical_rect;
|
||||
gchar *txt;
|
||||
|
||||
sprintf (buffer, "%0.*f", GTK_RANGE (scale)->digits, GTK_RANGE (scale)->adjustment->value);
|
||||
txt = _gtk_scale_format_value (scale,
|
||||
GTK_RANGE (scale)->adjustment->value);
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, txt);
|
||||
g_free (txt);
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, buffer);
|
||||
pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
|
||||
|
||||
switch (scale->value_pos)
|
||||
|
@ -6511,6 +6511,13 @@ create_event_watcher (void)
|
||||
* GtkRange
|
||||
*/
|
||||
|
||||
static gchar*
|
||||
reformat_value (GtkScale *scale,
|
||||
gdouble value)
|
||||
{
|
||||
return g_strdup_printf ("-->%g<--", value);
|
||||
}
|
||||
|
||||
static void
|
||||
create_range_controls (void)
|
||||
{
|
||||
@ -6563,6 +6570,15 @@ create_range_controls (void)
|
||||
gtk_box_pack_start (GTK_BOX (box2), scrollbar, TRUE, TRUE, 0);
|
||||
gtk_widget_show (scrollbar);
|
||||
|
||||
scale = gtk_hscale_new (GTK_ADJUSTMENT (adjustment));
|
||||
gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE);
|
||||
gtk_signal_connect (GTK_OBJECT (scale),
|
||||
"format_value",
|
||||
GTK_SIGNAL_FUNC (reformat_value),
|
||||
NULL);
|
||||
gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
|
||||
gtk_widget_show (scale);
|
||||
|
||||
hbox = gtk_hbox_new (FALSE, 0);
|
||||
|
||||
scale = gtk_vscale_new (GTK_ADJUSTMENT (adjustment));
|
||||
@ -6580,6 +6596,16 @@ create_range_controls (void)
|
||||
gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
|
||||
gtk_widget_show (scale);
|
||||
|
||||
scale = gtk_vscale_new (GTK_ADJUSTMENT (adjustment));
|
||||
gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE);
|
||||
gtk_signal_connect (GTK_OBJECT (scale),
|
||||
"format_value",
|
||||
GTK_SIGNAL_FUNC (reformat_value),
|
||||
NULL);
|
||||
gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
|
||||
gtk_widget_show (scale);
|
||||
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (box2), hbox, TRUE, TRUE, 0);
|
||||
gtk_widget_show (hbox);
|
||||
|
||||
@ -8159,8 +8185,13 @@ configure_event_callback (GtkWidget *widget,
|
||||
gchar *msg;
|
||||
gint x, y;
|
||||
|
||||
x = widget->allocation.x;
|
||||
y = widget->allocation.y;
|
||||
#if 0
|
||||
/* FIXME */
|
||||
gtk_window_get_location (GTK_WINDOW (widget), &x, &y);
|
||||
#else
|
||||
x = 0;
|
||||
y = 0;
|
||||
#endif
|
||||
|
||||
msg = g_strdup_printf ("event: %d,%d %d x %d\n"
|
||||
"location: %d, %d",
|
||||
@ -8235,6 +8266,26 @@ set_location_callback (GtkWidget *widget,
|
||||
gtk_widget_set_uposition (g_object_get_data (data, "target"), x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
set_geometry_callback (GtkWidget *entry,
|
||||
gpointer data)
|
||||
{
|
||||
gchar *text;
|
||||
GtkWindow *target;
|
||||
|
||||
target = GTK_WINDOW (g_object_get_data (G_OBJECT (data), "target"));
|
||||
|
||||
text = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
|
||||
|
||||
#if 0
|
||||
/* FIXME */
|
||||
if (!gtk_window_parse_geometry (target, text))
|
||||
g_print ("Bad geometry string '%s'\n", text);
|
||||
#endif
|
||||
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
static void
|
||||
allow_shrink_callback (GtkWidget *widget,
|
||||
gpointer data)
|
||||
@ -8282,6 +8333,7 @@ window_controls (GtkWidget *window)
|
||||
GtkWidget *button;
|
||||
GtkWidget *spin;
|
||||
GtkAdjustment *adj;
|
||||
GtkWidget *entry;
|
||||
GtkWidget *om;
|
||||
GtkWidget *menu;
|
||||
gint i;
|
||||
@ -8327,6 +8379,13 @@ window_controls (GtkWidget *window)
|
||||
|
||||
g_object_set_data (G_OBJECT (control_window), "spin2", spin);
|
||||
|
||||
entry = gtk_entry_new ();
|
||||
gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
|
||||
|
||||
gtk_signal_connect (GTK_OBJECT (entry), "changed",
|
||||
GTK_SIGNAL_FUNC (set_geometry_callback),
|
||||
control_window);
|
||||
|
||||
button = gtk_button_new_with_label ("Queue resize");
|
||||
gtk_signal_connect_object (GTK_OBJECT (button),
|
||||
"clicked",
|
||||
@ -8386,6 +8445,20 @@ window_controls (GtkWidget *window)
|
||||
GTK_OBJECT (control_window));
|
||||
gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
||||
|
||||
button = gtk_button_new_with_mnemonic ("_Show");
|
||||
gtk_signal_connect_object (GTK_OBJECT (button),
|
||||
"clicked",
|
||||
GTK_SIGNAL_FUNC (gtk_widget_show),
|
||||
GTK_OBJECT (window));
|
||||
gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
||||
|
||||
button = gtk_button_new_with_mnemonic ("_Hide");
|
||||
gtk_signal_connect_object (GTK_OBJECT (button),
|
||||
"clicked",
|
||||
GTK_SIGNAL_FUNC (gtk_widget_hide),
|
||||
GTK_OBJECT (window));
|
||||
gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
||||
|
||||
menu = gtk_menu_new ();
|
||||
|
||||
i = 0;
|
||||
|
@ -1063,6 +1063,23 @@ do_apply_colors (gpointer callback_data,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_remove_tags (gpointer callback_data,
|
||||
guint callback_action,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
View *view = view_from_widget (widget);
|
||||
GtkTextIter start;
|
||||
GtkTextIter end;
|
||||
|
||||
if (gtk_text_buffer_get_selection_bounds (view->buffer->buffer,
|
||||
&start, &end))
|
||||
{
|
||||
gtk_text_buffer_remove_all_tags (view->buffer->buffer,
|
||||
&start, &end);
|
||||
}
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
RESPONSE_FORWARD,
|
||||
@ -1235,6 +1252,7 @@ static GtkItemFactoryEntry menu_items[] =
|
||||
{ "/Attributes/Default tabs", NULL, do_apply_tabs, TRUE, NULL },
|
||||
{ "/Attributes/Color cycles", NULL, do_apply_colors, TRUE, NULL },
|
||||
{ "/Attributes/No colors", NULL, do_apply_colors, FALSE, NULL },
|
||||
{ "/Attributes/Remove all tags", NULL, do_remove_tags, 0, NULL },
|
||||
{ "/_Test", NULL, 0, 0, "<Branch>" },
|
||||
{ "/Test/_Example", NULL, do_example, 0, NULL },
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user