summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2001-05-07 15:58:47 +0000
committerHavoc Pennington <hp@src.gnome.org>2001-05-07 15:58:47 +0000
commitb4e4a0ed9d66132efad0539bc5901b35ea262d88 (patch)
tree7eea37afc0c2f32334112872547373758ac7d6b6
parent607ac1e1b31dc21598830a22930bcc39a77cb5c3 (diff)
downloadgdk-pixbuf-b4e4a0ed9d66132efad0539bc5901b35ea262d88.tar.gz
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.
-rw-r--r--ChangeLog43
-rw-r--r--ChangeLog.pre-2-043
-rw-r--r--ChangeLog.pre-2-1043
-rw-r--r--ChangeLog.pre-2-243
-rw-r--r--ChangeLog.pre-2-443
-rw-r--r--ChangeLog.pre-2-643
-rw-r--r--ChangeLog.pre-2-843
-rw-r--r--configure.in8
-rw-r--r--demos/gtk-demo/Makefile.am4
-rw-r--r--demos/gtk-demo/alphatest.pngbin0 -> 26529 bytes
-rw-r--r--demos/gtk-demo/floppybuddy.gifbin0 -> 5216 bytes
-rw-r--r--demos/gtk-demo/images.c49
-rw-r--r--demos/gtk-demo/main.c12
-rw-r--r--demos/gtk-demo/textview.c19
-rw-r--r--demos/testanimation.c814
-rw-r--r--docs/reference/ChangeLog6
-rw-r--r--docs/reference/gdk-pixbuf/tmpl/animation.sgml126
-rw-r--r--docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-loader.sgml21
-rw-r--r--docs/reference/gdk-pixbuf/tmpl/module_interface.sgml19
-rw-r--r--docs/reference/gtk/gtk-sections.txt2
-rw-r--r--docs/reference/gtk/tmpl/gtk-unused.sgml16
-rw-r--r--docs/reference/gtk/tmpl/gtkimage.sgml18
-rw-r--r--docs/reference/gtk/tmpl/gtkrc.sgml2
-rw-r--r--docs/reference/gtk/tmpl/gtkscale.sgml13
-rw-r--r--docs/reference/gtk/tmpl/gtksignal.sgml36
-rw-r--r--docs/reference/gtk/tmpl/gtkstyle.sgml4
-rw-r--r--docs/reference/gtk/tmpl/gtktextiter.sgml9
-rw-r--r--docs/reference/gtk/tmpl/gtktexttag.sgml11
-rw-r--r--docs/reference/gtk/tmpl/gtktypeutils.sgml8
-rw-r--r--docs/reference/gtk/tmpl/gtkwindow.sgml18
-rw-r--r--gdk-pixbuf/ChangeLog29
-rw-r--r--gdk-pixbuf/Makefile.am4
-rw-r--r--gdk-pixbuf/gdk-pixbuf-animation.c655
-rw-r--r--gdk-pixbuf/gdk-pixbuf-io.h21
-rw-r--r--gdk-pixbuf/gdk-pixbuf-loader.c157
-rw-r--r--gdk-pixbuf/gdk-pixbuf-loader.h24
-rw-r--r--gdk-pixbuf/gdk-pixbuf-private.h63
-rw-r--r--gdk-pixbuf/gdk-pixbuf-util.c2
-rw-r--r--gdk-pixbuf/gdk-pixbuf.c4
-rw-r--r--gdk-pixbuf/gdk-pixbuf.h34
-rw-r--r--gdk-pixbuf/io-bmp.c12
-rw-r--r--gdk-pixbuf/io-gif-animation.c557
-rw-r--r--gdk-pixbuf/io-gif-animation.h169
-rw-r--r--gdk-pixbuf/io-gif.c514
-rw-r--r--gdk-pixbuf/io-ico.c9
-rw-r--r--gdk-pixbuf/io-jpeg.c5
-rw-r--r--gdk-pixbuf/io-png.c4
-rw-r--r--gdk-pixbuf/io-pnm.c5
-rw-r--r--gdk-pixbuf/io-ras.c8
-rw-r--r--gdk-pixbuf/io-tiff.c4
-rw-r--r--gdk-pixbuf/io-wbmp.c12
-rw-r--r--gdk-pixbuf/io-xbm.c4
-rw-r--r--gdk-pixbuf/io-xpm.c6
-rw-r--r--gdk-pixbuf/pixops/pixops.c45
-rw-r--r--gtk/gtkcellrenderertext.c50
-rw-r--r--gtk/gtkcellrenderertext.h3
-rw-r--r--gtk/gtkcheckbutton.c6
-rw-r--r--gtk/gtkcolorsel.c2
-rw-r--r--gtk/gtkhscale.c10
-rw-r--r--gtk/gtkimage.c246
-rw-r--r--gtk/gtkimage.h70
-rw-r--r--gtk/gtkmarshal.list1
-rw-r--r--gtk/gtkmarshalers.list1
-rw-r--r--gtk/gtkrange.h3
-rw-r--r--gtk/gtkscale.c113
-rw-r--r--gtk/gtkscale.h6
-rw-r--r--gtk/gtktextbuffer.c121
-rw-r--r--gtk/gtktextbuffer.h3
-rw-r--r--gtk/gtktextiter.c6
-rw-r--r--gtk/gtktextiter.h7
-rw-r--r--gtk/gtktextlayout.c10
-rw-r--r--gtk/gtktexttag.c44
-rw-r--r--gtk/gtktexttag.h3
-rw-r--r--gtk/gtktextview.c1
-rw-r--r--gtk/gtkvscale.c11
-rw-r--r--tests/testgtk.c81
-rw-r--r--tests/testtext.c18
77 files changed, 3303 insertions, 1376 deletions
diff --git a/ChangeLog b/ChangeLog
index 2e672970f..924440869 100644
--- a/ChangeLog
+++ b/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
diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0
index 2e672970f..924440869 100644
--- a/ChangeLog.pre-2-0
+++ b/ChangeLog.pre-2-0
@@ -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
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index 2e672970f..924440869 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -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
diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2
index 2e672970f..924440869 100644
--- a/ChangeLog.pre-2-2
+++ b/ChangeLog.pre-2-2
@@ -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
diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4
index 2e672970f..924440869 100644
--- a/ChangeLog.pre-2-4
+++ b/ChangeLog.pre-2-4
@@ -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
diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6
index 2e672970f..924440869 100644
--- a/ChangeLog.pre-2-6
+++ b/ChangeLog.pre-2-6
@@ -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
diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8
index 2e672970f..924440869 100644
--- a/ChangeLog.pre-2-8
+++ b/ChangeLog.pre-2-8
@@ -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
diff --git a/configure.in b/configure.in
index 026edc156..590460ff1 100644
--- a/configure.in
+++ b/configure.in
@@ -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
diff --git a/demos/gtk-demo/Makefile.am b/demos/gtk-demo/Makefile.am
index 3cb530503..7d199e09c 100644
--- a/demos/gtk-demo/Makefile.am
+++ b/demos/gtk-demo/Makefile.am
@@ -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 \
diff --git a/demos/gtk-demo/alphatest.png b/demos/gtk-demo/alphatest.png
new file mode 100644
index 000000000..eb5885f89
--- /dev/null
+++ b/demos/gtk-demo/alphatest.png
Binary files differ
diff --git a/demos/gtk-demo/floppybuddy.gif b/demos/gtk-demo/floppybuddy.gif
new file mode 100644
index 000000000..ac986c8ed
--- /dev/null
+++ b/demos/gtk-demo/floppybuddy.gif
Binary files differ
diff --git a/demos/gtk-demo/images.c b/demos/gtk-demo/images.c
index 353cb4c8c..7faeb53cc 100644
--- a/demos/gtk-demo/images.c
+++ b/demos/gtk-demo/images.c
@@ -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>");
diff --git a/demos/gtk-demo/main.c b/demos/gtk-demo/main.c
index fabf898d4..83a27b362 100644
--- a/demos/gtk-demo/main.c
+++ b/demos/gtk-demo/main.c
@@ -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);
diff --git a/demos/gtk-demo/textview.c b/demos/gtk-demo/textview.c
index 928df9073..2fc970bfd 100644
--- a/demos/gtk-demo/textview.c
+++ b/demos/gtk-demo/textview.c
@@ -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,8 +205,17 @@ 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);
diff --git a/demos/testanimation.c b/demos/testanimation.c
index a823249b4..82b932c2d 100644
--- a/demos/testanimation.c
+++ b/demos/testanimation.c
@@ -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;
-
-} 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
+
+typedef struct _LoadContext LoadContext;
+
+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 void
-expose_func (GtkWidget *drawing_area, GdkEventExpose *event, gpointer data)
+static LoadContext*
+get_load_context (GtkWidget *image)
{
- GdkPixbuf *pixbuf;
-
- pixbuf = (GdkPixbuf *)gtk_object_get_data(GTK_OBJECT(drawing_area), "pixbuf");
-
- 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));
- }
+ 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
-config_func (GtkWidget *drawing_area, GdkEventConfigure *event, gpointer data)
+progressive_prepared_callback (GdkPixbufLoader* loader,
+ gpointer data)
{
- GdkPixbuf *pixbuf;
-
- pixbuf = (GdkPixbuf *)gtk_object_get_data(GTK_OBJECT(drawing_area), "pixbuf");
+ GdkPixbuf* pixbuf;
+ GtkWidget* image;
-#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
+ image = GTK_WIDGET (data);
+
+ 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 GtkWidget*
-new_testrgb_window (GdkPixbuf *pixbuf, gchar *title)
+static void
+progressive_updated_callback (GdkPixbufLoader* loader,
+ gint x, gint y, gint width, gint height,
+ gpointer data)
{
- GtkWidget *window;
- GtkWidget *vbox;
- GtkWidget *temp_box;
- GtkWidget *button;
- GtkWidget *drawing_area;
- gint w, h;
-
- w = gdk_pixbuf_get_width (pixbuf);
- h = gdk_pixbuf_get_height (pixbuf);
-
- 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_add (GTK_CONTAINER (window), vbox);
- gtk_widget_show_all (vbox);
-
- gtk_widget_show (window);
-
- return window;
+ GtkWidget* image;
+
+ image = GTK_WIDGET (data);
+
+ /* 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);
}
-#if 0
-
static gint
-update_timeout(gpointer data)
+progressive_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);
- }
+ 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);
- return !done;
+ 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
-progressive_prepared_callback(GdkPixbufLoader* loader, gpointer data)
+start_progressive_loading (GtkWidget *image)
{
- GtkWidget** retloc = data;
- GdkPixbuf* pixbuf;
-
- pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
- g_assert(pixbuf != NULL);
-
- gdk_pixbuf_ref(pixbuf); /* for the RGB window */
-
- *retloc = new_testrgb_window(pixbuf, "Progressive");
-
- return;
+ 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 *
+do_image (const char *filename)
+{
+ GtkWidget *frame;
+ GtkWidget *vbox;
+ GtkWidget *image;
+ GtkWidget *label;
+ GtkWidget *align;
+ GtkWidget *window;
+ gchar *str, *escaped;
+ LoadContext *lc;
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), "Image Loading");
+
+ 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);
+
+ 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;
+}
static void
-progressive_updated_callback(GdkPixbufLoader* loader, guint x, guint y, guint width, guint height, gpointer data)
+do_nonprogressive (const gchar *filename)
{
- 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;
+ GtkWidget *frame;
+ GtkWidget *vbox;
+ GtkWidget *image;
+ GtkWidget *label;
+ GtkWidget *align;
+ GtkWidget *window;
+ gchar *str, *escaped;
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), "Animation");
+
+ 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);
+
+ 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);
}
-#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 ();
-
- 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;
+ gint i;
+
+ gtk_init (&argc, &argv);
+
+ i = 1;
+ while (i < argc)
+ {
+ do_image (argv[i]);
+ do_nonprogressive (argv[i]);
+
+ ++i;
+ }
+
+ gtk_main ();
+
+ return 0;
+}
- 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
- {
- GtkWidget* rgb_window = NULL;
- ProgressFileStatus status;
- GdkPixbufLoader *pixbuf_loader;
-
- 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
- }
-
- if (found_valid)
- gtk_main ();
-
- return 0;
-}
diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog
index 9d2956317..d59095b69 100644
--- a/docs/reference/ChangeLog
+++ b/docs/reference/ChangeLog
@@ -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
diff --git a/docs/reference/gdk-pixbuf/tmpl/animation.sgml b/docs/reference/gdk-pixbuf/tmpl/animation.sgml
index 9e9d4b2ff..f13b066ac 100644
--- a/docs/reference/gdk-pixbuf/tmpl/animation.sgml
+++ b/docs/reference/gdk-pixbuf/tmpl/animation.sgml
@@ -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:
--->
-
-
diff --git a/docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-loader.sgml b/docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-loader.sgml
index b2f07bd0e..acdebe537 100644
--- a/docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-loader.sgml
+++ b/docs/reference/gdk-pixbuf/tmpl/gdk-pixbuf-loader.sgml
@@ -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.
-
diff --git a/docs/reference/gdk-pixbuf/tmpl/module_interface.sgml b/docs/reference/gdk-pixbuf/tmpl/module_interface.sgml
index 563fabb57..139ee467d 100644
--- a/docs/reference/gdk-pixbuf/tmpl/module_interface.sgml
+++ b/docs/reference/gdk-pixbuf/tmpl/module_interface.sgml
@@ -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>
diff --git a/docs/reference/gtk/gtk-sections.txt b/docs/reference/gtk/gtk-sections.txt
index ddd6cd94f..4e5b743ff 100644
--- a/docs/reference/gtk/gtk-sections.txt
+++ b/docs/reference/gtk/gtk-sections.txt
@@ -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>
diff --git a/docs/reference/gtk/tmpl/gtk-unused.sgml b/docs/reference/gtk/tmpl/gtk-unused.sgml
index 4cb131d8c..20397f167 100644
--- a/docs/reference/gtk/tmpl/gtk-unused.sgml
+++ b/docs/reference/gtk/tmpl/gtk-unused.sgml
@@ -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:
-
diff --git a/docs/reference/gtk/tmpl/gtkimage.sgml b/docs/reference/gtk/tmpl/gtkimage.sgml
index 6f8bfdd02..67e5d22ae 100644
--- a/docs/reference/gtk/tmpl/gtkimage.sgml
+++ b/docs/reference/gtk/tmpl/gtkimage.sgml
@@ -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>
diff --git a/docs/reference/gtk/tmpl/gtkrc.sgml b/docs/reference/gtk/tmpl/gtkrc.sgml
index 178b40392..88a0a4a50 100644
--- a/docs/reference/gtk/tmpl/gtkrc.sgml
+++ b/docs/reference/gtk/tmpl/gtkrc.sgml
@@ -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:
diff --git a/docs/reference/gtk/tmpl/gtkscale.sgml b/docs/reference/gtk/tmpl/gtkscale.sgml
index 877a40d09..3df953067 100644
--- a/docs/reference/gtk/tmpl/gtkscale.sgml
+++ b/docs/reference/gtk/tmpl/gtkscale.sgml
@@ -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.
diff --git a/docs/reference/gtk/tmpl/gtksignal.sgml b/docs/reference/gtk/tmpl/gtksignal.sgml
index 1a5a4f3e2..52c116c26 100644
--- a/docs/reference/gtk/tmpl/gtksignal.sgml
+++ b/docs/reference/gtk/tmpl/gtksignal.sgml
@@ -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.
diff --git a/docs/reference/gtk/tmpl/gtkstyle.sgml b/docs/reference/gtk/tmpl/gtkstyle.sgml
index a78f5ec00..73abe4c49 100644
--- a/docs/reference/gtk/tmpl/gtkstyle.sgml
+++ b/docs/reference/gtk/tmpl/gtkstyle.sgml
@@ -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:
diff --git a/docs/reference/gtk/tmpl/gtktextiter.sgml b/docs/reference/gtk/tmpl/gtktextiter.sgml
index 161516563..a7d68099e 100644
--- a/docs/reference/gtk/tmpl/gtktextiter.sgml
+++ b/docs/reference/gtk/tmpl/gtktextiter.sgml
@@ -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>
diff --git a/docs/reference/gtk/tmpl/gtktexttag.sgml b/docs/reference/gtk/tmpl/gtktexttag.sgml
index be71c7e39..7cff611ab 100644
--- a/docs/reference/gtk/tmpl/gtktexttag.sgml
+++ b/docs/reference/gtk/tmpl/gtktexttag.sgml
@@ -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>
diff --git a/docs/reference/gtk/tmpl/gtktypeutils.sgml b/docs/reference/gtk/tmpl/gtktypeutils.sgml
index 6295e2dfa..e6a3ad7ab 100644
--- a/docs/reference/gtk/tmpl/gtktypeutils.sgml
+++ b/docs/reference/gtk/tmpl/gtktypeutils.sgml
@@ -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.
diff --git a/docs/reference/gtk/tmpl/gtkwindow.sgml b/docs/reference/gtk/tmpl/gtkwindow.sgml
index 6f4ab3766..adab57e9f 100644
--- a/docs/reference/gtk/tmpl/gtkwindow.sgml
+++ b/docs/reference/gtk/tmpl/gtkwindow.sgml
@@ -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>
diff --git a/gdk-pixbuf/ChangeLog b/gdk-pixbuf/ChangeLog
index 9dea2a36a..f00bda8f6 100644
--- a/gdk-pixbuf/ChangeLog
+++ b/gdk-pixbuf/ChangeLog
@@ -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).
diff --git a/gdk-pixbuf/Makefile.am b/gdk-pixbuf/Makefile.am
index c8ba6e088..b006435cc 100644
--- a/gdk-pixbuf/Makefile.am
+++ b/gdk-pixbuf/Makefile.am
@@ -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 =
diff --git a/gdk-pixbuf/gdk-pixbuf-animation.c b/gdk-pixbuf/gdk-pixbuf-animation.c
index cc3255904..274813c50 100644
--- a/gdk-pixbuf/gdk-pixbuf-animation.c
+++ b/gdk-pixbuf/gdk-pixbuf-animation.c
@@ -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);
@@ -262,6 +269,46 @@ gdk_pixbuf_animation_unref (GdkPixbufAnimation *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;
+
+ 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 animation->width;
+ 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);
-
- return animation->height;
-}
+ int height;
+
+ g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), 0);
-/**
- * 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);
+ height = 0;
+ GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_size (animation,
+ NULL, &height);
+
- return animation->n_frames;
+ return height;
}
+
/**
- * gdk_pixbuf_animation_get_frames:
- * @animation: An animation.
+ * gdk_pixbuf_animation_get_iter:
+ * @animation: a #GdkPixbufAnimation
+ * @start_time: time when the animation starts playing
+ *
+ * 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().
+ *
+ * @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.
*
- * Queries the list of frames of an animation.
+ * 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: List of frames in the animation; this is a #GList of
- * #GdkPixbufFrame structures.
+ * 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;
+
+ g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
+
- return animation->frames;
+ if (start_time)
+ val = *start_time;
+ else
+ g_get_current_time (&val);
+
+ return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_iter (animation, &val);
}
-/**
- * gdk_pixbuf_frame_get_pixbuf:
- * @frame: A pixbuf animation frame.
- *
- * Queries the pixbuf of an animation frame.
- *
- * Return value: A pixbuf.
- **/
-GdkPixbuf *
-gdk_pixbuf_frame_get_pixbuf (GdkPixbufFrame *frame)
+GType
+gdk_pixbuf_animation_iter_get_type (void)
{
- g_return_val_if_fail (frame != NULL, NULL);
+ static GType object_type = 0;
- return frame->pixbuf;
+ 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_x_offset:
- * @frame: A pixbuf animation frame.
+ * gdk_pixbuf_animation_iter_get_delay_time:
+ * @iter: an animation iterator
*
- * Queries the X offset of an animation frame.
- *
- * Return value: X offset from the top left corner of the animation.
+ * 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: delay time in milliseconds (thousandths of a second)
**/
int
-gdk_pixbuf_frame_get_x_offset (GdkPixbufFrame *frame)
+gdk_pixbuf_animation_iter_get_delay_time (GdkPixbufAnimationIter *iter)
{
- g_return_val_if_fail (frame != NULL, -1);
-
- return frame->x_offset;
+ 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_frame_get_y_offset:
- * @frame: A pixbuf animation frame.
+ * gdk_pixbuf_animation_iter_get_pixbuf:
+ * @iter: an animation iterator
*
- * Queries the Y offset of an animation frame.
- *
- * Return value: Y offset from the top left corner of the animation.
+ * 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
**/
-int
-gdk_pixbuf_frame_get_y_offset (GdkPixbufFrame *frame)
+GdkPixbuf*
+gdk_pixbuf_animation_iter_get_pixbuf (GdkPixbufAnimationIter *iter)
{
- g_return_val_if_fail (frame != NULL, -1);
-
- return frame->y_offset;
+ g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), NULL);
+
+ return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_pixbuf (iter);
}
/**
- * gdk_pixbuf_frame_get_delay_time:
- * @frame: A pixbuf animation frame.
- *
- * Queries the delay time in milliseconds of an animation frame.
+ * gdk_pixbuf_animation_iter_on_currently_loading_frame:
+ * @iter: a #GdkPixbufAnimationIter
+ *
+ * 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: Delay time in milliseconds.
+ * Return value: %TRUE if the frame we're on is partially loaded, or the last frame
**/
-int
-gdk_pixbuf_frame_get_delay_time (GdkPixbufFrame *frame)
+gboolean
+gdk_pixbuf_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter)
{
- g_return_val_if_fail (frame != NULL, -1);
-
- return frame->delay_time;
+ g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), FALSE);
+
+ return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->on_currently_loading_frame (iter);
}
/**
- * gdk_pixbuf_frame_get_action:
- * @frame: A pixbuf animation frame.
+ * gdk_pixbuf_animation_iter_advance:
+ * @iter: a #GdkPixbufAnimationIter
+ * @current_time: current time
+ *
+ * Possibly advances an animation to a new frame. Chooses the frame based
+ * on the start time passed to gdk_pixbuf_animation_get_iter().
*
- * Queries the overlay action of an animation frame.
+ * @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: Overlay action for this frame.
**/
-GdkPixbufFrameAction
-gdk_pixbuf_frame_get_action (GdkPixbufFrame *frame)
+gboolean
+gdk_pixbuf_animation_iter_advance (GdkPixbufAnimationIter *iter,
+ const GTimeVal *current_time)
{
- g_return_val_if_fail (frame != NULL, GDK_PIXBUF_FRAME_RETAIN);
+ GTimeVal val;
+
+ g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), FALSE);
- return frame->action;
+ 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_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)
+
+
+static void gdk_pixbuf_non_anim_class_init (GdkPixbufNonAnimClass *klass);
+static void gdk_pixbuf_non_anim_finalize (GObject *object);
+
+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);
+
+
+
+
+
+static gpointer non_parent_class;
+
+GType
+gdk_pixbuf_non_anim_get_type (void)
{
- 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;
+ static GType object_type = 0;
+
+ 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,
+ };
+
+ object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION,
+ "GdkPixbufNonAnim",
+ &object_info, 0);
+ }
+
+ return object_type;
}
-/**
- * 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)
+static void
+gdk_pixbuf_non_anim_class_init (GdkPixbufNonAnimClass *klass)
{
- g_return_if_fail (frame != NULL);
+ 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));
- g_object_unref (G_OBJECT (frame->pixbuf));
- g_free (frame);
+ 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_frame_get_type (void)
+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)
{
- static GType our_type = 0;
+ GdkPixbufNonAnimIter *iter = GDK_PIXBUF_NON_ANIM_ITER (object);
- if (our_type == 0)
- our_type = g_boxed_type_register_static ("GdkPixbufFrame",
- NULL,
- gdk_pixbuf_frame_copy,
- gdk_pixbuf_frame_free,
- FALSE);
+ 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 */
+}
- return our_type;
+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;
+}
+
diff --git a/gdk-pixbuf/gdk-pixbuf-io.h b/gdk-pixbuf/gdk-pixbuf-io.h
index d4cf389fd..b66bcaf08 100644
--- a/gdk-pixbuf/gdk-pixbuf-io.h
+++ b/gdk-pixbuf/gdk-pixbuf-io.h
@@ -39,16 +39,15 @@ extern "C" {
-typedef void (* ModulePreparedNotifyFunc) (GdkPixbuf *pixbuf, 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,
- gpointer user_data);
+typedef void (* ModulePreparedNotifyFunc) (GdkPixbuf *pixbuf,
+ GdkPixbufAnimation *anim,
+ gpointer user_data);
+typedef void (* ModuleUpdatedNotifyFunc) (GdkPixbuf *pixbuf,
+ int x,
+ int y,
+ int width,
+ int height,
+ gpointer user_data);
typedef struct _GdkPixbufModule GdkPixbufModule;
struct _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,
diff --git a/gdk-pixbuf/gdk-pixbuf-loader.c b/gdk-pixbuf/gdk-pixbuf-loader.c
index 2a8d2658e..a9148d7fd 100644
--- a/gdk-pixbuf/gdk-pixbuf-loader.c
+++ b/gdk-pixbuf/gdk-pixbuf-loader.c
@@ -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),
@@ -188,9 +166,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);
@@ -198,26 +173,30 @@ gdk_pixbuf_loader_finalize (GObject *object)
}
static void
-gdk_pixbuf_loader_prepare (GdkPixbuf *pixbuf,
- gpointer loader)
+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);
@@ -450,7 +353,7 @@ gdk_pixbuf_loader_write (GdkPixbufLoader *loader,
{
gint eaten;
- eaten = gdk_pixbuf_loader_eat_header_write(loader, buf, count, error);
+ eaten = gdk_pixbuf_loader_eat_header_write (loader, buf, count, error);
if (eaten <= 0)
return FALSE;
@@ -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.
diff --git a/gdk-pixbuf/gdk-pixbuf-loader.h b/gdk-pixbuf/gdk-pixbuf-loader.h
index 9c47478a2..eea72f30d 100644
--- a/gdk-pixbuf/gdk-pixbuf-loader.h
+++ b/gdk-pixbuf/gdk-pixbuf-loader.h
@@ -51,21 +51,21 @@ typedef struct _GdkPixbufLoaderClass GdkPixbufLoaderClass;
struct _GdkPixbufLoaderClass
{
GObjectClass parent_class;
-
- void (*area_prepared) (GdkPixbufLoader *loader);
- 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);
- void (*closed) (GdkPixbufLoader *loader);
+
+ void (*area_prepared) (GdkPixbufLoader *loader);
+
+ /* Last known frame needs a redraw for x, y, width, height */
+ void (*area_updated) (GdkPixbufLoader *loader,
+ int x,
+ int y,
+ int width,
+ int height);
+
+ void (*closed) (GdkPixbufLoader *loader);
};
-GType gdk_pixbuf_loader_get_type (void) G_GNUC_CONST;
+GType gdk_pixbuf_loader_get_type (void) G_GNUC_CONST;
GdkPixbufLoader * gdk_pixbuf_loader_new (void);
GdkPixbufLoader * gdk_pixbuf_loader_new_with_type (const char *image_type,
GError **error);
diff --git a/gdk-pixbuf/gdk-pixbuf-private.h b/gdk-pixbuf/gdk-pixbuf-private.h
index e8eb7248a..0bdae8715 100644
--- a/gdk-pixbuf/gdk-pixbuf-private.h
+++ b/gdk-pixbuf/gdk-pixbuf-private.h
@@ -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,22 +84,50 @@ 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);
+};
+
#define GDK_PIXBUF_INLINE_MAGIC_NUMBER 0x47646B50 /* 'GdkP' */
@@ -125,6 +138,8 @@ typedef enum
GDK_PIXBUF_INLINE_RLE = 1
} GdkPixbufInlineFormat;
+
+GdkPixbufAnimation* gdk_pixbuf_non_anim_new (GdkPixbuf *pixbuf);
#endif
diff --git a/gdk-pixbuf/gdk-pixbuf-util.c b/gdk-pixbuf/gdk-pixbuf-util.c
index bee4fb5bb..0f869b947 100644
--- a/gdk-pixbuf/gdk-pixbuf-util.c
+++ b/gdk-pixbuf/gdk-pixbuf-util.c
@@ -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,
diff --git a/gdk-pixbuf/gdk-pixbuf.c b/gdk-pixbuf/gdk-pixbuf.c
index 12b8e6144..cfc0bb323 100644
--- a/gdk-pixbuf/gdk-pixbuf.c
+++ b/gdk-pixbuf/gdk-pixbuf.c
@@ -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;
diff --git a/gdk-pixbuf/gdk-pixbuf.h b/gdk-pixbuf/gdk-pixbuf.h
index b8b5a03af..46ff3533c 100644
--- a/gdk-pixbuf/gdk-pixbuf.h
+++ b/gdk-pixbuf/gdk-pixbuf.h
@@ -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,21 +269,20 @@ 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);
-/* Frame accessors */
+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);
-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>
diff --git a/gdk-pixbuf/io-bmp.c b/gdk-pixbuf/io-bmp.c
index c5108bcc1..ce112f85a 100644
--- a/gdk-pixbuf/io-bmp.c
+++ b/gdk-pixbuf/io-bmp.c
@@ -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;
diff --git a/gdk-pixbuf/io-gif-animation.c b/gdk-pixbuf/io-gif-animation.c
new file mode 100644
index 000000000..fe164a095
--- /dev/null
+++ b/gdk-pixbuf/io-gif-animation.c
@@ -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;
+}
diff --git a/gdk-pixbuf/io-gif-animation.h b/gdk-pixbuf/io-gif-animation.h
new file mode 100644
index 000000000..ce1ebaa6f
--- /dev/null
+++ b/gdk-pixbuf/io-gif-animation.h
@@ -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
diff --git a/gdk-pixbuf/io-gif.c b/gdk-pixbuf/io-gif.c
index 5be68023f..c3c1b8728 100644
--- a/gdk-pixbuf/io-gif.c
+++ b/gdk-pixbuf/io-gif.c
@@ -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;
- CMap frame_color_map;
- unsigned int bit_pixel;
- unsigned int color_resolution;
- unsigned int background;
+
+ 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;
+ 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;
@@ -207,7 +210,14 @@ gif_read (GifContext *context, guchar *buffer, size_t len)
count += len;
g_print ("Fsize :%d\tcount :%d\t", len, count);
#endif
- retval = (fread(buffer, len, 1, context->file) != 0);
+ 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))) {
+ return -1;
+ }
+
+ 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];
+
+ 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))) {
- /*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->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->colormap_flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]);
- context->colormap_index ++;
+ 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,80 +723,123 @@ 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,
- 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;
- switch (context->gif89.disposal) {
- case 0:
- case 1:
- context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
- break;
- case 2:
- context->frame->action = GDK_PIXBUF_FRAME_DISPOSE;
- break;
- case 3:
- context->frame->action = GDK_PIXBUF_FRAME_REVERT;
- break;
- default:
- context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
- break;
- }
- context->frame->pixbuf = context->pixbuf;
- if (context->animation) {
- 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);
- if (w > context->animation->width)
- context->animation->width = w;
- if (h > context->animation->height)
- context->animation->height = h;
- }
- }
- }
- dest = gdk_pixbuf_get_pixels (context->pixbuf);
+ 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);
+
+ context->frame->x_offset = context->x_offset;
+ 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:
+ context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
+ break;
+ case 2:
+ context->frame->action = GDK_PIXBUF_FRAME_DISPOSE;
+ break;
+ case 3:
+ context->frame->action = GDK_PIXBUF_FRAME_REVERT;
+ break;
+ default:
+ context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
+ break;
+ }
+
+ 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 = 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->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);
context->draw_xpos++;
-
+
if (context->draw_xpos == context->frame_len) {
context->draw_xpos = 0;
if (context->frame_interlace) {
@@ -796,7 +880,7 @@ gif_get_lzw (GifContext *context)
lower_bound = 0;
upper_bound = context->frame_height;
} else {
-
+
}
} else
upper_bound = context->draw_ypos;
@@ -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;
+
+ context->state = GIF_GET_NEXT_STEP;
+
+ 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 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,
- _("GIF animation contained a frame with an incorrect size"));
+ _("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 = gdk_pixbuf_animation_get_static_image (GDK_PIXBUF_ANIMATION (context->animation));
- pixbuf = context->pixbuf;
+ 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;
-
- /* FIXME: free the animation data */
+ gboolean retval = TRUE;
- /* FIXME this thing needs to report errors if
- * we have unused image data
- */
+ if (context->state != GIF_DONE) {
+ g_set_error (error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ _("GIF image was truncated or incomplete."));
+
+ 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;
}
diff --git a/gdk-pixbuf/io-ico.c b/gdk-pixbuf/io-ico.c
index dc6dadb2f..6a2ca4884 100644
--- a/gdk-pixbuf/io-ico.c
+++ b/gdk-pixbuf/io-ico.c
@@ -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)
{
diff --git a/gdk-pixbuf/io-jpeg.c b/gdk-pixbuf/io-jpeg.c
index 2c295131d..c707d347a 100644
--- a/gdk-pixbuf/io-jpeg.c
+++ b/gdk-pixbuf/io-jpeg.c
@@ -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) {
diff --git a/gdk-pixbuf/io-png.c b/gdk-pixbuf/io-png.c
index 9ece35d40..21b1d4b29 100644
--- a/gdk-pixbuf/io-png.c
+++ b/gdk-pixbuf/io-png.c
@@ -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;
}
diff --git a/gdk-pixbuf/io-pnm.c b/gdk-pixbuf/io-pnm.c
index 87c392db5..cd7dd9d9b 100644
--- a/gdk-pixbuf/io-pnm.c
+++ b/gdk-pixbuf/io-pnm.c
@@ -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);
}
diff --git a/gdk-pixbuf/io-ras.c b/gdk-pixbuf/io-ras.c
index 25a3c0b7a..84b7c27f9 100644
--- a/gdk-pixbuf/io-ras.c
+++ b/gdk-pixbuf/io-ras.c
@@ -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)
{
diff --git a/gdk-pixbuf/io-tiff.c b/gdk-pixbuf/io-tiff.c
index 9b23f5d71..51040dcda 100644
--- a/gdk-pixbuf/io-tiff.c
+++ b/gdk-pixbuf/io-tiff.c
@@ -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)
{
diff --git a/gdk-pixbuf/io-wbmp.c b/gdk-pixbuf/io-wbmp.c
index 1b7784b13..1537d83d6 100644
--- a/gdk-pixbuf/io-wbmp.c
+++ b/gdk-pixbuf/io-wbmp.c
@@ -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)
diff --git a/gdk-pixbuf/io-xbm.c b/gdk-pixbuf/io-xbm.c
index 05d8f994a..0041488eb 100644
--- a/gdk-pixbuf/io-xbm.c
+++ b/gdk-pixbuf/io-xbm.c
@@ -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)
{
diff --git a/gdk-pixbuf/io-xpm.c b/gdk-pixbuf/io-xpm.c
index 0ddc3c234..1f99088c3 100644
--- a/gdk-pixbuf/io-xpm.c
+++ b/gdk-pixbuf/io-xpm.c
@@ -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);
diff --git a/gdk-pixbuf/pixops/pixops.c b/gdk-pixbuf/pixops/pixops.c
index ea1960715..7a13e043b 100644
--- a/gdk-pixbuf/pixops/pixops.c
+++ b/gdk-pixbuf/pixops/pixops.c
@@ -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,25 +275,39 @@ 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 (((j + check_x) >> check_shift) & 1)
+ if (a0 == 255)
{
- 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);
+ dest[0] = p[0];
+ dest[1] = p[1];
+ dest[2] = p[2];
}
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);
- }
+ if (((j + check_x) >> check_shift) & 1)
+ {
+ 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
+ {
+ 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)
dest[3] = 0xff;
@@ -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)
diff --git a/gtk/gtkcellrenderertext.c b/gtk/gtkcellrenderertext.c
index 9a6f65cbf..706fffd2c 100644
--- a/gtk/gtkcellrenderertext.c
+++ b/gtk/gtkcellrenderertext.c
@@ -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,
@@ -282,6 +284,16 @@ gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class)
G_MAXDOUBLE,
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,
@@ -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
diff --git a/gtk/gtkcellrenderertext.h b/gtk/gtkcellrenderertext.h
index fd906a335..3ec185228 100644
--- a/gtk/gtkcellrenderertext.h
+++ b/gtk/gtkcellrenderertext.h
@@ -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;
diff --git a/gtk/gtkcheckbutton.c b/gtk/gtkcheckbutton.c
index 802b85e01..f888e6511 100644
--- a/gtk/gtkcheckbutton.c
+++ b/gtk/gtkcheckbutton.c
@@ -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))
@@ -255,7 +255,7 @@ gtk_check_button_size_request (GtkWidget *widget,
GtkRequisition child_requisition;
gtk_widget_size_request (child, &child_requisition);
-
+
requisition->width += child_requisition.width;
requisition->height += child_requisition.height;
}
diff --git a/gtk/gtkcolorsel.c b/gtk/gtkcolorsel.c
index a894e9fc5..4f1e61ac4 100644
--- a/gtk/gtkcolorsel.c
+++ b/gtk/gtkcolorsel.c
@@ -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;
}
diff --git a/gtk/gtkhscale.c b/gtk/gtkhscale.c
index 0fa644b68..29f6321fb 100644
--- a/gtk/gtkhscale.c
+++ b/gtk/gtkhscale.c
@@ -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)
diff --git a/gtk/gtkimage.c b/gtk/gtkimage.c
index 81f0debc1..e5890a16c 100644
--- a/gtk/gtkimage.c
+++ b/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
**/
@@ -269,6 +283,31 @@ gtk_image_new_from_icon_set (GtkIconSet *icon_set,
}
/**
+ * 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
* @pixmap: a #GdkPixmap or %NULL
@@ -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));
}
/**
@@ -501,6 +553,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,
@@ -777,6 +940,24 @@ gtk_image_expose (GtkWidget *widget,
image_bound.height = gdk_pixbuf_get_height (stock_pixbuf);
}
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,27 +1093,27 @@ 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:
default:
@@ -928,6 +1122,8 @@ gtk_image_clear (GtkImage *image)
}
image->storage_type = GTK_IMAGE_EMPTY;
+
+ memset (&image->data, '\0', sizeof (image->data));
}
static void
diff --git a/gtk/gtkimage.h b/gtk/gtkimage.h
index bc1a0c0a6..71c80dfd0 100644
--- a/gtk/gtkimage.h
+++ b/gtk/gtkimage.h
@@ -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;
};
@@ -115,33 +125,36 @@ struct _GtkImageClass
GtkType gtk_image_get_type (void) G_GNUC_CONST;
-GtkWidget* gtk_image_new_from_pixmap (GdkPixmap *pixmap,
- GdkBitmap *mask);
-GtkWidget* gtk_image_new_from_image (GdkImage *image,
- GdkBitmap *mask);
-GtkWidget* gtk_image_new_from_file (const gchar *filename);
-GtkWidget* gtk_image_new_from_pixbuf (GdkPixbuf *pixbuf);
-GtkWidget* gtk_image_new_from_stock (const gchar *stock_id,
- GtkIconSize size);
-GtkWidget* gtk_image_new_from_icon_set (GtkIconSet *icon_set,
- GtkIconSize size);
-
-void gtk_image_set_from_pixmap (GtkImage *image,
- GdkPixmap *pixmap,
- GdkBitmap *mask);
-void gtk_image_set_from_image (GtkImage *image,
- GdkImage *gdk_image,
- GdkBitmap *mask);
-void gtk_image_set_from_file (GtkImage *image,
- const gchar *filename);
-void gtk_image_set_from_pixbuf (GtkImage *image,
- GdkPixbuf *pixbuf);
-void gtk_image_set_from_stock (GtkImage *image,
- const gchar *stock_id,
- GtkIconSize size);
-void gtk_image_set_from_icon_set (GtkImage *image,
- GtkIconSet *icon_set,
- GtkIconSize size);
+GtkWidget* gtk_image_new_from_pixmap (GdkPixmap *pixmap,
+ GdkBitmap *mask);
+GtkWidget* gtk_image_new_from_image (GdkImage *image,
+ GdkBitmap *mask);
+GtkWidget* gtk_image_new_from_file (const gchar *filename);
+GtkWidget* gtk_image_new_from_pixbuf (GdkPixbuf *pixbuf);
+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,
+ GdkBitmap *mask);
+void gtk_image_set_from_image (GtkImage *image,
+ GdkImage *gdk_image,
+ GdkBitmap *mask);
+void gtk_image_set_from_file (GtkImage *image,
+ const gchar *filename);
+void gtk_image_set_from_pixbuf (GtkImage *image,
+ GdkPixbuf *pixbuf);
+void gtk_image_set_from_stock (GtkImage *image,
+ const gchar *stock_id,
+ GtkIconSize size);
+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
diff --git a/gtk/gtkmarshal.list b/gtk/gtkmarshal.list
index 12ec4108d..cb656a25c 100644
--- a/gtk/gtkmarshal.list
+++ b/gtk/gtkmarshal.list
@@ -36,6 +36,7 @@ NONE:INT,INT
NONE:NONE
NONE:POINTER
NONE:STRING,INT,POINTER
+STRING:DOUBLE
VOID:BOOLEAN
VOID:BOXED
VOID:BOXED,BOXED
diff --git a/gtk/gtkmarshalers.list b/gtk/gtkmarshalers.list
index 12ec4108d..cb656a25c 100644
--- a/gtk/gtkmarshalers.list
+++ b/gtk/gtkmarshalers.list
@@ -36,6 +36,7 @@ NONE:INT,INT
NONE:NONE
NONE:POINTER
NONE:STRING,INT,POINTER
+STRING:DOUBLE
VOID:BOOLEAN
VOID:BOXED
VOID:BOXED,BOXED
diff --git a/gtk/gtkrange.h b/gtk/gtkrange.h
index b9c27307b..58fb89a38 100644
--- a/gtk/gtkrange.h
+++ b/gtk/gtkrange.h
@@ -91,13 +91,14 @@ struct _GtkRangeClass
guint8 slider;
guint8 step_forw;
guint8 step_back;
-
+
/* action signals for keybindings */
void (* move_slider) (GtkRange *range,
GtkScrollType scroll,
GtkTroughType trough);
/* Completely broken virtual functions, please ignore */
+
void (* draw_background) (GtkRange *range);
void (* clear_background) (GtkRange *range);
void (* draw_trough) (GtkRange *range);
diff --git a/gtk/gtkscale.c b/gtk/gtkscale.c
index a2769b285..992cdfe41 100644
--- a/gtk/gtkscale.c
+++ b/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;
-
- 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);
+ txt = _gtk_scale_format_value (scale, range->adjustment->lower);
+ pango_layout_set_text (layout, txt, -1);
+ g_free (txt);
+
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;
+
+ txt = _gtk_scale_format_value (scale, range->adjustment->upper);
+ pango_layout_set_text (layout, txt, -1);
+ g_free (txt);
- value = ABS (range->adjustment->upper);
- if (value == 0) value = 1;
- digits = log10 (value) + 1;
- if (digits > 13)
- digits = 13;
-
- 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);
+}
diff --git a/gtk/gtkscale.h b/gtk/gtkscale.h
index fd9e97446..b6cd71954 100644
--- a/gtk/gtkscale.h
+++ b/gtk/gtkscale.h
@@ -61,6 +61,9 @@ struct _GtkScaleClass
GtkRangeClass parent_class;
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 */
diff --git a/gtk/gtktextbuffer.c b/gtk/gtktextbuffer.c
index 1074ca0f9..2e30d026a 100644
--- a/gtk/gtktextbuffer.c
+++ b/gtk/gtktextbuffer.c
@@ -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
diff --git a/gtk/gtktextbuffer.h b/gtk/gtktextbuffer.h
index b6f801f11..4368d242a 100644
--- a/gtk/gtktextbuffer.h
+++ b/gtk/gtktextbuffer.h
@@ -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
diff --git a/gtk/gtktextiter.c b/gtk/gtktextiter.c
index 241529d38..1d5303214 100644
--- a/gtk/gtktextiter.c
+++ b/gtk/gtktextiter.c
@@ -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 */
diff --git a/gtk/gtktextiter.h b/gtk/gtktextiter.h
index 00285e287..8a883f9b2 100644
--- a/gtk/gtktextiter.h
+++ b/gtk/gtktextiter.h
@@ -108,9 +108,10 @@ 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);
+ gboolean toggled_on);
gboolean gtk_text_iter_begins_tag (const GtkTextIter *iter,
GtkTextTag *tag);
@@ -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
diff --git a/gtk/gtktextlayout.c b/gtk/gtktextlayout.c
index 1355ef8ff..208fa8c0e 100644
--- a/gtk/gtktextlayout.c
+++ b/gtk/gtktextlayout.c
@@ -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
diff --git a/gtk/gtktexttag.c b/gtk/gtktexttag.c
index a65243230..c149c4eda 100644
--- a/gtk/gtktexttag.c
+++ b/gtk/gtktexttag.c
@@ -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,
@@ -350,6 +352,16 @@ gtk_text_tag_class_init (GtkTextTagClass *klass)
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",
_("Font 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;
@@ -1151,6 +1173,11 @@ gtk_text_tag_set_property (GObject *object,
text_tag->size_set = g_value_get_boolean (value);
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);
@@ -1332,10 +1359,14 @@ gtk_text_tag_get_property (GObject *object,
case PROP_SIZE:
g_value_set_int (value, tag->values->font.size);
break;
-
+
case PROP_SIZE_POINTS:
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);
@@ -1445,6 +1476,10 @@ gtk_text_tag_get_property (GObject *object,
case PROP_SIZE_SET:
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);
@@ -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 ||
diff --git a/gtk/gtktexttag.h b/gtk/gtktexttag.h
index ea30059b7..f75a1760b 100644
--- a/gtk/gtktexttag.h
+++ b/gtk/gtktexttag.h
@@ -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;
diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c
index 26aa7c698..8bb7314b4 100644
--- a/gtk/gtktextview.c
+++ b/gtk/gtktextview.c
@@ -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,
diff --git a/gtk/gtkvscale.c b/gtk/gtkvscale.c
index 72b8b209a..be31ec337 100644
--- a/gtk/gtkvscale.c
+++ b/gtk/gtkvscale.c
@@ -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;
+
+ 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)
diff --git a/tests/testgtk.c b/tests/testgtk.c
index 5cd9117aa..084ad2ae5 100644
--- a/tests/testgtk.c
+++ b/tests/testgtk.c
@@ -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));
@@ -6579,10 +6595,20 @@ create_range_controls (void)
gtk_range_set_inverted (GTK_RANGE (scale), TRUE);
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);
-
+
separator = gtk_hseparator_new ();
gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
gtk_widget_show (separator);
@@ -8158,9 +8184,14 @@ configure_event_callback (GtkWidget *widget,
GtkWidget *label = data;
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",
@@ -8236,6 +8267,26 @@ set_location_callback (GtkWidget *widget,
}
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;
diff --git a/tests/testtext.c b/tests/testtext.c
index a473837cd..175e4f1c4 100644
--- a/tests/testtext.c
+++ b/tests/testtext.c
@@ -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 },
};