fix some shell typos

2001-05-04  Havoc Pennington  <hp@redhat.com>

	* configure.in: fix some shell typos

	* gtk/gtkcolorsel.c (gtk_color_selection_destroy): warning fix

	* gtk/gtkimage.c: handle animations

	* gtk/gtkcheckbutton.c (gtk_check_button_size_request): request
	border_width * 2, not just border_width

	* gtk/gtkscale.c: add "format_value" signal to allow people
	to override the way values are drawn.
	(gtk_scale_get_value_size): fix width/height mistake,
	and compute size from actual displayed text, not
	from made-up text.

	* gtk/gtktexttag.c (gtk_text_tag_class_init): fix return type in
	signal registration

	* tests/testtext.c: Add "Remove all tags" menu item for testing

	* gtk/gtktextbuffer.c (gtk_text_buffer_remove_all_tags): implement

	* demos/gtk-demo/main.c (main): add hack so we can find modules
	without installing gtk

	* demos/gtk-demo/textview.c (insert_text): demo font scaling

	* gtk/gtkcellrenderertext.c: Add "scale" property (font scaling
	factor)
	(gtk_cell_renderer_text_set_property): remove some bogus
	g_object_notify

	* gtk/gtktexttag.c: add "scale" property which is a font scaling
	factor

	* gtk/gtktextlayout.c (add_text_attrs): add font scale attribute
	to layout

	* gtk/gtktextiter.c (gtk_text_iter_is_start): rename from
	gtk_text_iter_is_first

2001-05-04  Havoc Pennington  <hp@redhat.com>

	* pixops/pixops.c (pixops_process): merge fix from stable: Patch
	 from hoshem@mel.comcen.com.au to fix nonzero X offsets.  Fixes
	 bug #50371.

        * gdk-pixbuf/pixops/pixops.c (pixops_composite_nearest): merge
	from stable: Patch from OKADA Mitsuru <m-okada@fjb.co.jp> to fix
	confusion of using "src" instead of "p".
        (pixops_composite_color_nearest): Use a more accurate (and
	correct, to begin with) compositing method.  This cures checks
	showing through on images with no alpha.

	* gdk-pixbuf.c (gdk_pixbuf_fill): fix bug that left some trailing
	bytes unfilled.

	* gdk-pixbuf-io.h: fix UpdatedNotifyFunc to use signed ints

	* gdk-pixbuf-loader.h (struct _GdkPixbufLoaderClass): Change
	area_updated signal to use signed ints.  Removed animation-related
	signals.

	* io-gif.c, io-gif-animation.h, io-gif-animation.c: Massive
	rewrite action

	* gdk-pixbuf-animation.c: Add GdkPixbufAnimationIter to abstract
	all the pesky details. Remove old frame-based API. Make
	GdkPixbufAnimation an abstract base class, derived by the loaders.
This commit is contained in:
Havoc Pennington 2001-05-07 15:58:47 +00:00 committed by Havoc Pennington
parent 607ac1e1b3
commit b4e4a0ed9d
77 changed files with 3318 additions and 1391 deletions

View File

@ -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> 2001-01-06 Hans Breuer <hans@breuer.org>
* gdk/gdk.def : updated exports * gdk/gdk.def : updated exports

View File

@ -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> 2001-01-06 Hans Breuer <hans@breuer.org>
* gdk/gdk.def : updated exports * gdk/gdk.def : updated exports

View File

@ -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> 2001-01-06 Hans Breuer <hans@breuer.org>
* gdk/gdk.def : updated exports * gdk/gdk.def : updated exports

View File

@ -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> 2001-01-06 Hans Breuer <hans@breuer.org>
* gdk/gdk.def : updated exports * gdk/gdk.def : updated exports

View File

@ -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> 2001-01-06 Hans Breuer <hans@breuer.org>
* gdk/gdk.def : updated exports * gdk/gdk.def : updated exports

View File

@ -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> 2001-01-06 Hans Breuer <hans@breuer.org>
* gdk/gdk.def : updated exports * gdk/gdk.def : updated exports

View File

@ -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> 2001-01-06 Hans Breuer <hans@breuer.org>
* gdk/gdk.def : updated exports * gdk/gdk.def : updated exports

View File

@ -563,18 +563,18 @@ AM_CONDITIONAL(HAVE_TIFF, test "x$LIBTIFF" != x)
AM_CONDITIONAL(HAVE_PNG, test "x$LIBPNG" != x) AM_CONDITIONAL(HAVE_PNG, test "x$LIBPNG" != x)
AM_CONDITIONAL(HAVE_JPEG, test "x$LIBJPEG" != x) AM_CONDITIONAL(HAVE_JPEG, test "x$LIBJPEG" != x)
if test $dynworks = no ; then if $dynworks ; then
STATIC_LIB_DEPS="$LIBTIFF $LIBJPEG $LIBPNG" STATIC_LIB_DEPS="$LIBTIFF $LIBJPEG $LIBPNG"
else else
STATIC_LIB_DEPS= STATIC_LIB_DEPS=
if echo "$included_loaders" | grep "\(^\|\,\)tiff\(\$\|\,\)" > /dev/null; then if echo "$included_loaders" | grep "\(^\|\,\)tiff\(\$\|\,\)" > /dev/null; then
STATIC_LIB_DEPS="STATIC_LIB_DEPS $LIBTIFF" STATIC_LIB_DEPS="$STATIC_LIB_DEPS $LIBTIFF"
fi fi
if echo "$included_loaders" | grep "\(^\|\,\)jpeg\(\$\|\,\)" > /dev/null; then if echo "$included_loaders" | grep "\(^\|\,\)jpeg\(\$\|\,\)" > /dev/null; then
STATIC_LIB_DEPS="STATIC_LIB_DEPS $LIBJPEG" STATIC_LIB_DEPS="$STATIC_LIB_DEPS $LIBJPEG"
fi fi
if echo "$included_loaders" | grep "\(^\|\,\)png\(\$\|\,\)" > /dev/null; then 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
fi fi

View File

@ -59,8 +59,10 @@ gtk_demo_SOURCES = \
gtk_demo_DEPENDENCIES = $(DEPS) gtk_demo_DEPENDENCIES = $(DEPS)
gtk_demo_LDADD = $(LDADDS) gtk_demo_LDADD = $(LDADDS)
IMAGEFILES= apple-red.png \ IMAGEFILES= alphatest.png \
apple-red.png \
background.jpg \ background.jpg \
floppybuddy.gif \
gnome-applets.png \ gnome-applets.png \
gnome-calendar.png \ gnome-calendar.png \
gnome-foot.png \ gnome-foot.png \

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -8,6 +8,8 @@
* *
* If you want to put image data in your program as a C variable, * If you want to put image data in your program as a C variable,
* use the make-inline-pixbuf program that comes with GTK+. * 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> #include <gtk/gtk.h>
@ -39,14 +41,14 @@ progressive_prepared_callback (GdkPixbufLoader* loader, gpointer data)
static void static void
progressive_updated_callback (GdkPixbufLoader* loader, progressive_updated_callback (GdkPixbufLoader* loader,
guint x, guint y, guint width, guint height, gint x, gint y, gint width, gint height,
gpointer data) gpointer data)
{ {
GtkWidget* image; GtkWidget* image;
image = GTK_WIDGET (data); 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 * itself doesn't know this; so queue a redraw. If we wanted to be
* really efficient, we could use a drawing area or something * really efficient, we could use a drawing area or something
* instead of a GtkImage, so we could control the exact position of * 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_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR, GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE, GTK_BUTTONS_CLOSE,
"Failure reading image file 'gtk-logo-rgb.gif': %s", "Failure reading image file 'alphatest.png': %s",
g_strerror (errno)); g_strerror (errno));
gtk_signal_connect (GTK_OBJECT (dialog), gtk_signal_connect (GTK_OBJECT (dialog),
@ -180,10 +182,10 @@ progressive_timeout (gpointer data)
{ {
const gchar *filename; const gchar *filename;
if (g_file_test ("./gtk-logo-rgb.gif", G_FILE_TEST_EXISTS)) if (g_file_test ("./alphatest.png", G_FILE_TEST_EXISTS))
filename = "./gtk-logo-rgb.gif"; filename = "./alphatest.png";
else else
filename = DEMOCODEDIR"/gtk-logo-rgb.gif"; filename = DEMOCODEDIR"/alphatest.png";
image_stream = fopen (filename, "r"); image_stream = fopen (filename, "r");
@ -195,7 +197,7 @@ progressive_timeout (gpointer data)
GTK_DIALOG_DESTROY_WITH_PARENT, GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR, GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE, GTK_BUTTONS_CLOSE,
"Unable to open image file 'gtk-logo-rgb.gif': %s", "Unable to open image file 'alphatest.png': %s",
g_strerror (errno)); g_strerror (errno));
gtk_signal_connect (GTK_OBJECT (dialog), 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 * The timeout simply simulates a slow data source by inserting
* pauses in the reading process. * pauses in the reading process.
*/ */
load_timeout = g_timeout_add (300, load_timeout = g_timeout_add (150,
progressive_timeout, progressive_timeout,
image); image);
} }
@ -359,6 +361,37 @@ do_images (void)
gtk_container_add (GTK_CONTAINER (frame), image); 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); label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label), gtk_label_set_markup (GTK_LABEL (label),
"<u>Progressive image loading</u>"); "<u>Progressive image loading</u>");

View File

@ -465,6 +465,18 @@ main (int argc, char **argv)
GtkWidget *tree; GtkWidget *tree;
GtkTextTag *tag; 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); gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL); window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

View File

@ -84,6 +84,12 @@ create_tags (GtkTextBuffer *buffer)
/* points times the PANGO_SCALE factor */ /* points times the PANGO_SCALE factor */
"size", 30 * PANGO_SCALE, NULL); "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", gtk_text_buffer_create_tag (buffer, "monospace",
"family", "monospace", NULL); "family", "monospace", NULL);
@ -199,7 +205,16 @@ insert_text (GtkTextBuffer *buffer)
gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
"big", -1, "big", -1,
"big", NULL); "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, gtk_text_buffer_insert_with_tags_by_name (buffer, &iter, "Colors. ", -1,
"heading", NULL); "heading", NULL);

View File

@ -23,466 +23,426 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf-loader.h>
typedef struct { typedef struct _LoadContext LoadContext;
FILE *imagefile;
GdkPixbufLoader *loader;
GtkWidget **rgbwin;
guchar *buf;
guint timeout;
guint readlen;
} ProgressFileStatus; struct _LoadContext
{
gchar *filename;
#define DEFAULT_WIDTH 24 GtkWidget *window;
#define DEFAULT_HEIGHT 24 GdkPixbufLoader *pixbuf_loader;
guint load_timeout;
static const unsigned char default_image[] = { FILE* image_stream;
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
0xff, 0x00, 0xff, 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
}; };
static void static void
quit_func (GtkWidget *widget, gpointer dummy) destroy_context (gpointer data)
{ {
gtk_main_quit (); LoadContext *lc = data;
g_free (lc->filename);
if (lc->load_timeout)
g_source_remove (lc->load_timeout);
if (lc->image_stream)
fclose (lc->image_stream);
if (lc->pixbuf_loader)
{
gdk_pixbuf_loader_close (lc->pixbuf_loader, NULL);
g_object_unref (G_OBJECT (lc->pixbuf_loader));
}
g_free (lc);
}
static LoadContext*
get_load_context (GtkWidget *image)
{
LoadContext *lc;
lc = g_object_get_data (G_OBJECT (image), "lc");
if (lc == NULL)
{
lc = g_new0 (LoadContext, 1);
g_object_set_data_full (G_OBJECT (image),
"lc",
lc,
destroy_context);
}
return lc;
} }
static void static void
expose_func (GtkWidget *drawing_area, GdkEventExpose *event, gpointer data) progressive_prepared_callback (GdkPixbufLoader* loader,
gpointer data)
{ {
GdkPixbuf* pixbuf; GdkPixbuf* pixbuf;
GtkWidget* image;
pixbuf = (GdkPixbuf *)gtk_object_get_data(GTK_OBJECT(drawing_area), "pixbuf"); image = GTK_WIDGET (data);
if (gdk_pixbuf_get_has_alpha (pixbuf)) { pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
gdk_draw_rgb_32_image (drawing_area->window,
drawing_area->style->black_gc, /* Avoid displaying random memory contents, since the pixbuf
event->area.x, event->area.y, * isn't filled in yet.
event->area.width, */
event->area.height, gdk_pixbuf_fill (pixbuf, 0xaaaaaaff);
GDK_RGB_DITHER_MAX,
gdk_pixbuf_get_pixels (pixbuf) /* Could set the pixbuf instead, if we only wanted to display
+ (event->area.y * gdk_pixbuf_get_rowstride (pixbuf)) * static images.
+ (event->area.x * gdk_pixbuf_get_n_channels (pixbuf)), */
gdk_pixbuf_get_rowstride (pixbuf)); gtk_image_set_from_animation (GTK_IMAGE (image),
} else { gdk_pixbuf_loader_get_animation (loader));
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));
}
} }
static void static void
config_func (GtkWidget *drawing_area, GdkEventConfigure *event, gpointer data) progressive_updated_callback (GdkPixbufLoader* loader,
gint x, gint y, gint width, gint height,
gpointer data)
{ {
GdkPixbuf *pixbuf; GtkWidget* image;
pixbuf = (GdkPixbuf *)gtk_object_get_data(GTK_OBJECT(drawing_area), "pixbuf"); image = GTK_WIDGET (data);
#if 0 /* We know the pixbuf inside the GtkImage has changed, but the image
if (((event->width) != gdk_pixbuf_get_width (pixbuf)) || * itself doesn't know this; so queue a redraw. If we wanted to be
((event->height) != gdk_pixbuf_get_height (pixbuf))) * really efficient, we could use a drawing area or something
gdk_pixbuf_scale(pixbuf, event->width, event->height); * instead of a GtkImage, so we could control the exact position of
#endif * the pixbuf on the display, then we could queue a draw for only
* the updated area of the image.
*/
/* We only really need to redraw if the image's animation iterator
* is gdk_pixbuf_animation_iter_on_currently_loading_frame(), but
* who cares.
*/
gtk_widget_queue_draw (image);
}
static gint
progressive_timeout (gpointer data)
{
GtkWidget *image;
LoadContext *lc;
image = GTK_WIDGET (data);
lc = get_load_context (image);
/* This shows off fully-paranoid error handling, so looks scary.
* You could factor out the error handling code into a nice separate
* function to make things nicer.
*/
if (lc->image_stream)
{
size_t bytes_read;
guchar buf[256];
GError *error = NULL;
bytes_read = fread (buf, 1, 256, lc->image_stream);
if (ferror (lc->image_stream))
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"Failure reading image file 'alphatest.png': %s",
g_strerror (errno));
gtk_signal_connect (GTK_OBJECT (dialog),
"response",
GTK_SIGNAL_FUNC (gtk_widget_destroy),
NULL);
fclose (lc->image_stream);
lc->image_stream = NULL;
gtk_widget_show (dialog);
lc->load_timeout = 0;
return FALSE; /* uninstall the timeout */
}
if (!gdk_pixbuf_loader_write (lc->pixbuf_loader,
buf, bytes_read,
&error))
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"Failed to load image: %s",
error->message);
g_error_free (error);
gtk_signal_connect (GTK_OBJECT (dialog),
"response",
GTK_SIGNAL_FUNC (gtk_widget_destroy),
NULL);
fclose (lc->image_stream);
lc->image_stream = NULL;
gtk_widget_show (dialog);
lc->load_timeout = 0;
return FALSE; /* uninstall the timeout */
}
if (feof (lc->image_stream))
{
fclose (lc->image_stream);
lc->image_stream = NULL;
/* Errors can happen on close, e.g. if the image
* file was truncated we'll know on close that
* it was incomplete.
*/
error = NULL;
if (!gdk_pixbuf_loader_close (lc->pixbuf_loader,
&error))
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"Failed to load image: %s",
error->message);
g_error_free (error);
gtk_signal_connect (GTK_OBJECT (dialog),
"response",
GTK_SIGNAL_FUNC (gtk_widget_destroy),
NULL);
gtk_widget_show (dialog);
g_object_unref (G_OBJECT (lc->pixbuf_loader));
lc->pixbuf_loader = NULL;
lc->load_timeout = 0;
return FALSE; /* uninstall the timeout */
}
g_object_unref (G_OBJECT (lc->pixbuf_loader));
lc->pixbuf_loader = NULL;
}
}
else
{
lc->image_stream = fopen (lc->filename, "r");
if (lc->image_stream == NULL)
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"Unable to open image file '%s': %s",
lc->filename,
g_strerror (errno));
gtk_signal_connect (GTK_OBJECT (dialog),
"response",
GTK_SIGNAL_FUNC (gtk_widget_destroy),
NULL);
gtk_widget_show (dialog);
lc->load_timeout = 0;
return FALSE; /* uninstall the timeout */
}
if (lc->pixbuf_loader)
{
gdk_pixbuf_loader_close (lc->pixbuf_loader, NULL);
g_object_unref (G_OBJECT (lc->pixbuf_loader));
lc->pixbuf_loader = NULL;
}
lc->pixbuf_loader = gdk_pixbuf_loader_new ();
g_signal_connect_data (G_OBJECT (lc->pixbuf_loader),
"area_prepared",
G_CALLBACK (progressive_prepared_callback),
image,
NULL, FALSE, FALSE);
g_signal_connect_data (G_OBJECT (lc->pixbuf_loader),
"area_updated",
G_CALLBACK (progressive_updated_callback),
image,
NULL, FALSE, FALSE);
}
/* leave timeout installed */
return TRUE;
}
static void
start_progressive_loading (GtkWidget *image)
{
LoadContext *lc;
lc = get_load_context (image);
/* This is obviously totally contrived (we slow down loading
* on purpose to show how incremental loading works).
* The real purpose of incremental loading is the case where
* you are reading data from a slow source such as the network.
* The timeout simply simulates a slow data source by inserting
* pauses in the reading process.
*/
lc->load_timeout = g_timeout_add (100,
progressive_timeout,
image);
} }
static GtkWidget * static GtkWidget *
new_testrgb_window (GdkPixbuf *pixbuf, gchar *title) do_image (const char *filename)
{ {
GtkWidget *window; GtkWidget *frame;
GtkWidget *vbox; GtkWidget *vbox;
GtkWidget *temp_box; GtkWidget *image;
GtkWidget *button; GtkWidget *label;
GtkWidget *drawing_area; GtkWidget *align;
gint w, h; GtkWidget *window;
gchar *str, *escaped;
LoadContext *lc;
w = gdk_pixbuf_get_width (pixbuf); window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
h = gdk_pixbuf_get_height (pixbuf); gtk_window_set_title (GTK_WINDOW (window), "Image Loading");
window = gtk_widget_new (gtk_window_get_type (), gtk_container_set_border_width (GTK_CONTAINER (window), 8);
"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);
vbox = gtk_vbox_new (FALSE, 8);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
gtk_container_add (GTK_CONTAINER (window), vbox); gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_widget_show_all (vbox);
gtk_widget_show (window); label = gtk_label_new (NULL);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
escaped = g_markup_escape_text (filename, -1);
str = g_strdup_printf ("Progressively loading: <b>%s</b>", escaped);
gtk_label_set_markup (GTK_LABEL (label),
str);
g_free (escaped);
g_free (str);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
/* The alignment keeps the frame from growing when users resize
* the window
*/
align = gtk_alignment_new (0.5, 0.5, 0, 0);
gtk_container_add (GTK_CONTAINER (align), frame);
gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
image = gtk_image_new_from_pixbuf (NULL);
gtk_container_add (GTK_CONTAINER (frame), image);
lc = get_load_context (image);
lc->window = window;
lc->filename = g_strdup (filename);
start_progressive_loading (image);
gtk_widget_show_all (window);
return window; return window;
} }
#if 0
static gint
update_timeout(gpointer data)
{
ProgressFileStatus *status = data;
gboolean done;
done = TRUE;
if (!feof(status->imagefile)) {
gint nbytes;
nbytes = fread(status->buf, 1, status->readlen,
status->imagefile);
done = !gdk_pixbuf_loader_write (GDK_PIXBUF_LOADER (status->loader), status->buf, nbytes);
}
if (done) {
gtk_widget_queue_draw(*status->rgbwin);
gdk_pixbuf_loader_close (GDK_PIXBUF_LOADER (status->loader));
g_object_destroy (G_OBJECT(status->loader));
fclose (status->imagefile);
g_free (status->buf);
}
return !done;
}
static void static void
progressive_prepared_callback(GdkPixbufLoader* loader, gpointer data) do_nonprogressive (const gchar *filename)
{ {
GtkWidget** retloc = data; GtkWidget *frame;
GdkPixbuf* pixbuf; GtkWidget *vbox;
GtkWidget *image;
GtkWidget *label;
GtkWidget *align;
GtkWidget *window;
gchar *str, *escaped;
pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_assert(pixbuf != NULL); gtk_window_set_title (GTK_WINDOW (window), "Animation");
gdk_pixbuf_ref(pixbuf); /* for the RGB window */ gtk_container_set_border_width (GTK_CONTAINER (window), 8);
*retloc = new_testrgb_window(pixbuf, "Progressive"); vbox = gtk_vbox_new (FALSE, 8);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
gtk_container_add (GTK_CONTAINER (window), vbox);
return; label = gtk_label_new (NULL);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
escaped = g_markup_escape_text (filename, -1);
str = g_strdup_printf ("Loaded from file: <b>%s</b>", escaped);
gtk_label_set_markup (GTK_LABEL (label),
str);
g_free (escaped);
g_free (str);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
/* The alignment keeps the frame from growing when users resize
* the window
*/
align = gtk_alignment_new (0.5, 0.5, 0, 0);
gtk_container_add (GTK_CONTAINER (align), frame);
gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
image = gtk_image_new_from_file (filename);
gtk_container_add (GTK_CONTAINER (frame), image);
gtk_widget_show_all (window);
} }
static void
progressive_updated_callback(GdkPixbufLoader* loader, guint x, guint y, guint width, guint height, gpointer data)
{
GtkWidget** window_loc = data;
/* g_print ("progressive_updated_callback:\n\t%d\t%d\t%d\t%d\n", x, y, width, height); */
if (*window_loc != NULL)
gtk_widget_queue_draw_area(*window_loc,
x, y, width, height);
return;
}
#endif
static int readlen = 4096;
extern void pixbuf_init();
int int
main (int argc, char **argv) main (int argc,
char **argv)
{ {
int i; gint i;
int found_valid = FALSE;
GdkPixbufAnimation *animation;
pixbuf_init ();
gtk_init (&argc, &argv); 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; i = 1;
if (argc == 1) { while (i < argc)
g_print ("USAGE: testanimation FILE1 ...\n");
return 0;
} else {
for (i = 1; i < argc; i++) {
GError *error;
error = NULL;
animation = gdk_pixbuf_animation_new_from_file (argv[i],
&error);
if (animation == NULL) {
g_warning ("Failed to load animation: %s",
error->message);
g_error_free (error);
}
if (animation) {
gint i = 0;
GList *listptr;
for (listptr = gdk_pixbuf_animation_get_frames (animation);
listptr;
listptr = listptr->next) {
GdkPixbufFrame *frame;
GdkPixbuf *pixbuf;
gchar *title;
frame = listptr->data;
pixbuf = gdk_pixbuf_frame_get_pixbuf (frame);
title = g_strdup_printf ("Frame %d", i);
g_print ("Frame %d x:%d y:%d width:%d height:%d\n",
i,
gdk_pixbuf_frame_get_x_offset (frame),
gdk_pixbuf_frame_get_y_offset (frame),
gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf));
new_testrgb_window (pixbuf, title);
g_free (title);
i++;
}
found_valid = TRUE;
}
}
#if 0
{ {
GtkWidget* rgb_window = NULL; do_image (argv[i]);
ProgressFileStatus status; do_nonprogressive (argv[i]);
GdkPixbufLoader *pixbuf_loader;
pixbuf_loader = gdk_pixbuf_loader_new (); ++i;
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 (); gtk_main ();
return 0; return 0;
} }

View File

@ -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 * gdk/tmpl/images.sgml: add warning about gtk_image_new_bitmap

View File

@ -2,15 +2,17 @@
Animations Animations
<!-- ##### SECTION Short_Description ##### --> <!-- ##### SECTION Short_Description ##### -->
Animations as multi-frame structures. Animated images.
<!-- ##### SECTION Long_Description ##### --> <!-- ##### SECTION Long_Description ##### -->
<para> <para>
The &gdk-pixbuf; library provides a simple mechanism to load and The &gdk-pixbuf; library provides a simple mechanism to load and represent
represent animations, primarily animated GIF files. Animations animations. An animation is conceptually a series of frames to be displayed
are represented as lists of #GdkPixbufFrame structures. Each over time. Each frame is the same size. The animation may not be represented
frame structure contains a #GdkPixbuf structure and information as a series of frames internally; for example, it may be stored as a
about the frame's overlay mode and duration. 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> </para>
<!-- ##### SECTION See_Also ##### --> <!-- ##### SECTION See_Also ##### -->
@ -18,34 +20,9 @@ Animations as multi-frame structures.
#GdkPixbufLoader #GdkPixbufLoader
</para> </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 ##### --> <!-- ##### STRUCT GdkPixbufAnimation ##### -->
<para> <para>
This structure describes an animation, which is represented as a This object describes an animation.
list of #GdkPixbufFrame structures.
</para> </para>
@ -76,15 +53,6 @@ frame.
@animation: @animation:
<!-- ##### FUNCTION gdk_pixbuf_animation_get_frames ##### -->
<para>
</para>
@animation:
@Returns:
<!-- ##### FUNCTION gdk_pixbuf_animation_get_width ##### --> <!-- ##### FUNCTION gdk_pixbuf_animation_get_width ##### -->
<para> <para>
@ -94,15 +62,6 @@ frame.
@Returns: @Returns:
<!-- ##### FUNCTION gdk_pixbuf_animation_get_num_frames ##### -->
<para>
</para>
@animation:
@Returns:
<!-- ##### FUNCTION gdk_pixbuf_animation_get_height ##### --> <!-- ##### FUNCTION gdk_pixbuf_animation_get_height ##### -->
<para> <para>
@ -112,70 +71,3 @@ frame.
@Returns: @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:
-->

View File

@ -132,15 +132,6 @@ Application-driven progressive image loading.
@Returns: @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 ##### --> <!-- ##### SIGNAL GdkPixbufLoader::area-prepared ##### -->
<para> <para>
This signal is emitted when the pixbuf loader has been fed the 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: 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.

View File

@ -28,6 +28,7 @@ Module Interface
</para> </para>
@pixbuf: @pixbuf:
@anim:
@user_data: @user_data:
@ -44,24 +45,6 @@ Module Interface
@user_data: @user_data:
<!-- ##### USER_FUNCTION ModuleFrameDoneNotifyFunc ##### -->
<para>
</para>
@frame:
@user_data:
<!-- ##### USER_FUNCTION ModuleAnimationDoneNotifyFunc ##### -->
<para>
</para>
@pixbuf:
@user_data:
<!-- ##### STRUCT GdkPixbufModule ##### --> <!-- ##### STRUCT GdkPixbufModule ##### -->
<para> <para>

View File

@ -967,6 +967,7 @@ GTK_HSEPARATOR_GET_CLASS
<FILE>gtkimage</FILE> <FILE>gtkimage</FILE>
<TITLE>GtkImage</TITLE> <TITLE>GtkImage</TITLE>
GtkImage GtkImage
GtkImageType
gtk_image_get_icon_set gtk_image_get_icon_set
gtk_image_get_image gtk_image_get_image
gtk_image_get_pixbuf gtk_image_get_pixbuf
@ -1002,7 +1003,6 @@ GtkImageImageData
GtkImagePixbufData GtkImagePixbufData
GtkImagePixmapData GtkImagePixmapData
GtkImageStockData GtkImageStockData
GtkImageType
</SECTION> </SECTION>
<SECTION> <SECTION>

View File

@ -1621,19 +1621,3 @@ fundamental type.
@window: @window:
@Returns: @Returns:
<!-- ##### FUNCTION gtk_window_set_decorations_hint ##### -->
<para>
</para>
@window:
@decorations:
<!-- ##### FUNCTION gtk_window_set_functions_hint ##### -->
<para>
</para>
@window:
@functions:

View File

@ -28,6 +28,24 @@ below.
</para> </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 ##### --> <!-- ##### FUNCTION gtk_image_get_icon_set ##### -->
<para> <para>

View File

@ -387,7 +387,6 @@ can define other sizes.
<para> <para>
It's also possible to use custom icons for a given state, for example: 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> <programlisting>
stock["my-stock-item"] = stock["my-stock-item"] =
{ {
@ -496,6 +495,7 @@ This can later be composited together with other
#GtkRcStyle structures to form a #GtkStyle. #GtkRcStyle structures to form a #GtkStyle.
</para> </para>
@parent_instance:
@name: @name:
@bg_pixmap_name: @bg_pixmap_name:
@font_desc: @font_desc:

View File

@ -43,7 +43,9 @@ slider.</entry>
<!-- ##### FUNCTION gtk_scale_set_digits ##### --> <!-- ##### FUNCTION gtk_scale_set_digits ##### -->
<para> <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> </para>
@scale: a #GtkScale. @scale: a #GtkScale.
@ -80,6 +82,15 @@ string.
@Returns: the maximum width needed to display the value 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 ##### --> <!-- ##### ARG GtkScale:digits ##### -->
<para> <para>
The number of decimal places that are displayed in the value. The number of decimal places that are displayed in the value.

View File

@ -289,7 +289,7 @@ you don't want a return value.
the callbacks. the callbacks.
<!-- ##### FUNCTION gtk_signal_lookup ##### --> <!-- ##### MACRO gtk_signal_lookup ##### -->
<para> <para>
Given the name of the signal and the type of object it connects Given the name of the signal and the type of object it connects
to, get the signal's identifying integer. Emitting the signal 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. @Returns: the signal's identifying number, or 0 if no signal was found.
<!-- ##### FUNCTION gtk_signal_name ##### --> <!-- ##### MACRO gtk_signal_name ##### -->
<para> <para>
Given the signal's identifier, find its name. Given the signal's identifier, find its name.
</para> </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. followed by one which is a pointer to the return type.
<!-- ##### FUNCTION gtk_signal_emit_stop ##### --> <!-- ##### MACRO gtk_signal_emit_stop ##### -->
<para> <para>
This function aborts a signal's current emission. This function aborts a signal's current emission.
</para> </para>
@ -415,7 +415,7 @@ except it will lookup the signal id for you.
@name: the name of the signal you wish to stop. @name: the name of the signal you wish to stop.
<!-- ##### FUNCTION gtk_signal_connect ##### --> <!-- ##### MACRO gtk_signal_connect ##### -->
<para> <para>
Attach a function pointer and user data to a signal for Attach a function pointer and user data to a signal for
a particular object. a particular object.
@ -467,7 +467,7 @@ is getting pressed, this is that button.
@d: @d:
<!-- ##### FUNCTION gtk_signal_connect_after ##### --> <!-- ##### MACRO gtk_signal_connect_after ##### -->
<para> <para>
Attach a function pointer and user data to a signal Attach a function pointer and user data to a signal
so that this handler will be called after the other handlers. 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: @d:
<!-- ##### FUNCTION gtk_signal_connect_object ##### --> <!-- ##### MACRO gtk_signal_connect_object ##### -->
<para> <para>
This function is for registering a callback that will This function is for registering a callback that will
call another object's callback. That is, call another object's callback. That is,
@ -520,7 +520,7 @@ really pass any gpointer as the #slot_object .)
@d: @d:
<!-- ##### FUNCTION gtk_signal_connect_object_after ##### --> <!-- ##### MACRO gtk_signal_connect_object_after ##### -->
<para> <para>
Attach a signal hook to a signal, passing in an alternate Attach a signal hook to a signal, passing in an alternate
object as the first parameter, and guaranteeing object as the first parameter, and guaranteeing
@ -626,7 +626,7 @@ should signal the removal of this signal.
@name: name of the signal. @name: name of the signal.
<!-- ##### FUNCTION gtk_signal_disconnect ##### --> <!-- ##### MACRO gtk_signal_disconnect ##### -->
<para> <para>
Destroy a user-defined handler connection. Destroy a user-defined handler connection.
</para> </para>
@ -635,7 +635,7 @@ Destroy a user-defined handler connection.
@handler_id: the connection id. @handler_id: the connection id.
<!-- ##### FUNCTION gtk_signal_disconnect_by_func ##### --> <!-- ##### MACRO gtk_signal_disconnect_by_func ##### -->
<para> <para>
Destroy all connections for a particular object, with Destroy all connections for a particular object, with
the given function-pointer and user-data. the given function-pointer and user-data.
@ -650,7 +650,7 @@ the given function-pointer and user-data.
@d: @d:
<!-- ##### FUNCTION gtk_signal_disconnect_by_data ##### --> <!-- ##### MACRO gtk_signal_disconnect_by_data ##### -->
<para> <para>
Destroy all connections for a particular object, with Destroy all connections for a particular object, with
the given user-data. the given user-data.
@ -663,7 +663,7 @@ the given user-data.
@d: @d:
<!-- ##### FUNCTION gtk_signal_handler_block ##### --> <!-- ##### MACRO gtk_signal_handler_block ##### -->
<para> <para>
Prevent an user-defined handler from being invoked. All other Prevent an user-defined handler from being invoked. All other
signal processing will go on as normal, but this particular signal processing will go on as normal, but this particular
@ -674,7 +674,7 @@ handler will ignore it.
@handler_id: the connection id. @handler_id: the connection id.
<!-- ##### FUNCTION gtk_signal_handler_block_by_func ##### --> <!-- ##### MACRO gtk_signal_handler_block_by_func ##### -->
<para> <para>
Prevent a user-defined handler from being invoked, by reference to 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 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: @d:
<!-- ##### FUNCTION gtk_signal_handler_block_by_data ##### --> <!-- ##### MACRO gtk_signal_handler_block_by_data ##### -->
<para> <para>
Prevent all user-defined handlers with a certain user data from being invoked. Prevent all user-defined handlers with a certain user data from being invoked.
</para> </para>
@ -702,7 +702,7 @@ Prevent all user-defined handlers with a certain user data from being invoked.
@d: @d:
<!-- ##### FUNCTION gtk_signal_handler_unblock ##### --> <!-- ##### MACRO gtk_signal_handler_unblock ##### -->
<para> <para>
Undo a block, by connection id. Note that undoing a block doesn't Undo a block, by connection id. Note that undoing a block doesn't
necessarily make the hook callable, because if you block a 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. gtk_signal_connect(), etc.
<!-- ##### FUNCTION gtk_signal_handler_unblock_by_func ##### --> <!-- ##### MACRO gtk_signal_handler_unblock_by_func ##### -->
<para> <para>
Undo a block, by function pointer and data. Undo a block, by function pointer and data.
Note that undoing a block doesn't Note that undoing a block doesn't
@ -731,7 +731,7 @@ hook twice, you must unblock it twice.
@d: @d:
<!-- ##### FUNCTION gtk_signal_handler_unblock_by_data ##### --> <!-- ##### MACRO gtk_signal_handler_unblock_by_data ##### -->
<para> <para>
Undo block(s), to all signals for a particular object Undo block(s), to all signals for a particular object
with a particular user-data pointer with a particular user-data pointer
@ -744,7 +744,7 @@ with a particular user-data pointer
@d: @d:
<!-- ##### FUNCTION gtk_signal_handler_pending ##### --> <!-- ##### MACRO gtk_signal_handler_pending ##### -->
<para> <para>
Returns a connection id corresponding to a given signal id and object. Returns a connection id corresponding to a given signal id and object.
</para> </para>
@ -766,7 +766,7 @@ handler.
@b: @b:
<!-- ##### FUNCTION gtk_signal_handler_pending_by_func ##### --> <!-- ##### MACRO gtk_signal_handler_pending_by_func ##### -->
<para> <para>
Returns a connection id corresponding to a given signal id, object, function Returns a connection id corresponding to a given signal id, object, function
pointer and user data. pointer and user data.

View File

@ -41,6 +41,7 @@ Styles
@mid: @mid:
@text: @text:
@base: @base:
@text_aa:
@black: @black:
@white: @white:
@font: @font:
@ -54,6 +55,7 @@ Styles
@mid_gc: @mid_gc:
@text_gc: @text_gc:
@base_gc: @base_gc:
@text_aa_gc:
@black_gc: @black_gc:
@white_gc: @white_gc:
@bg_pixmap: @bg_pixmap:
@ -504,6 +506,7 @@ Styles
@style: @style:
@window: @window:
@state_type: @state_type:
@use_text:
@x: @x:
@y: @y:
@layout: @layout:
@ -874,6 +877,7 @@ Styles
@style: @style:
@window: @window:
@state_type: @state_type:
@use_text:
@area: @area:
@widget: @widget:
@detail: @detail:

View File

@ -378,15 +378,6 @@ types related to the text widget and how they work together.
@Returns: @Returns:
<!-- ##### FUNCTION gtk_text_iter_is_first ##### -->
<para>
</para>
@iter:
@Returns:
<!-- ##### FUNCTION gtk_text_iter_forward_char ##### --> <!-- ##### FUNCTION gtk_text_iter_forward_char ##### -->
<para> <para>

View File

@ -58,6 +58,7 @@ Describes a type of line wrapping.
@justification: @justification:
@direction: @direction:
@font: @font:
@font_scale:
@left_margin: @left_margin:
@indent: @indent:
@right_margin: @right_margin:
@ -279,6 +280,11 @@ Font as a #PangoFontDescription.
</para> </para>
<!-- ##### ARG GtkTextTag:scale ##### -->
<para>
</para>
<!-- ##### ARG GtkTextTag:size-points ##### --> <!-- ##### ARG GtkTextTag:size-points ##### -->
<para> <para>
@ -419,6 +425,11 @@ applies to the first character in a paragraph.
</para> </para>
<!-- ##### ARG GtkTextTag:scale-set ##### -->
<para>
</para>
<!-- ##### ARG GtkTextTag:justification-set ##### --> <!-- ##### ARG GtkTextTag:justification-set ##### -->
<para> <para>

View File

@ -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. @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>
</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. @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> <para>
Get the internal representation of a type given its name. Get the internal representation of a type given its name.
</para> </para>
@ -577,7 +577,7 @@ Get the internal representation of a type given its name.
@Returns: a GtkType @Returns: a GtkType
<!-- ##### FUNCTION gtk_type_parent ##### --> <!-- ##### MACRO gtk_type_parent ##### -->
<para> <para>
</para> </para>
@ -608,7 +608,7 @@ has all the proper initializers called.
@Returns: gpointer to a GtkTypeObject @Returns: gpointer to a GtkTypeObject
<!-- ##### FUNCTION gtk_type_is_a ##### --> <!-- ##### MACRO gtk_type_is_a ##### -->
<para> <para>
Look in the type hierarchy to see if @type has @is_a_type among its 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. ancestors. Do so with a simple lookup, not a loop.

View File

@ -393,6 +393,15 @@ it's larger
@setting: @setting:
<!-- ##### FUNCTION gtk_window_set_decorations_hint ##### -->
<para>
</para>
@window:
@decorations:
<!-- ##### FUNCTION gtk_window_set_frame_dimensions ##### --> <!-- ##### FUNCTION gtk_window_set_frame_dimensions ##### -->
<para> <para>
@ -405,6 +414,15 @@ it's larger
@bottom: @bottom:
<!-- ##### FUNCTION gtk_window_set_functions_hint ##### -->
<para>
</para>
@window:
@functions:
<!-- ##### FUNCTION gtk_window_set_has_frame ##### --> <!-- ##### FUNCTION gtk_window_set_has_frame ##### -->
<para> <para>

View File

@ -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> Sun Apr 22 15:51:32 2001 Owen Taylor <otaylor@redhat.com>
* Makefile.am (LDADDS): Add $(MATH_LIB). * Makefile.am (LDADDS): Add $(MATH_LIB).

View File

@ -32,8 +32,8 @@ libpixbufloader_xpm_la_LIBADD =
# #
# The GIF loader # The GIF loader
# #
libpixbufloader_static_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 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_LDFLAGS = -avoid-version -module
libpixbufloader_gif_la_LIBADD = libpixbufloader_gif_la_LIBADD =

View File

@ -1,3 +1,4 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
/* GdkPixbuf library - Simple animation support /* GdkPixbuf library - Simple animation support
* *
* Copyright (C) 1999 The Free Software Foundation * Copyright (C) 1999 The Free Software Foundation
@ -26,12 +27,59 @@
#include "gdk-pixbuf-io.h" #include "gdk-pixbuf-io.h"
#include "gdk-pixbuf-private.h" #include "gdk-pixbuf-private.h"
static void gdk_pixbuf_animation_class_init (GdkPixbufAnimationClass *klass); typedef struct _GdkPixbufNonAnim GdkPixbufNonAnim;
static void gdk_pixbuf_animation_finalize (GObject *object); 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 GType
gdk_pixbuf_animation_get_type (void) gdk_pixbuf_animation_get_type (void)
@ -43,7 +91,7 @@ gdk_pixbuf_animation_get_type (void)
sizeof (GdkPixbufAnimationClass), sizeof (GdkPixbufAnimationClass),
(GBaseInitFunc) NULL, (GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL, (GBaseFinalizeFunc) NULL,
(GClassInitFunc) gdk_pixbuf_animation_class_init, (GClassInitFunc) NULL,
NULL, /* class_finalize */ NULL, /* class_finalize */
NULL, /* class_data */ NULL, /* class_data */
sizeof (GdkPixbufAnimation), sizeof (GdkPixbufAnimation),
@ -59,35 +107,6 @@ gdk_pixbuf_animation_get_type (void)
return object_type; 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) { if (image_module->load_animation == NULL) {
GdkPixbuf *pixbuf; GdkPixbuf *pixbuf;
GdkPixbufFrame *frame;
/* Keep this logic in sync with gdk_pixbuf_new_from_file() */ /* 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) if (pixbuf == NULL)
return NULL; return NULL;
frame = g_new (GdkPixbufFrame, 1); animation = gdk_pixbuf_non_anim_new (pixbuf);
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 = g_object_new (GDK_TYPE_PIXBUF_ANIMATION, NULL); g_object_unref (G_OBJECT (pixbuf));
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);
} else { } else {
fseek (f, 0, SEEK_SET); fseek (f, 0, SEEK_SET);
animation = (* image_module->load_animation) (f, error); animation = (* image_module->load_animation) (f, error);
@ -261,6 +268,46 @@ gdk_pixbuf_animation_unref (GdkPixbufAnimation *animation)
g_object_unref (G_OBJECT (animation)); g_object_unref (G_OBJECT (animation));
} }
/**
* gdk_pixbuf_animation_is_static_image:
* @animation: a #GdkPixbufAnimation
*
* If you load a file with gdk_pixbuf_animation_new_from_file() and it turns
* out to be a plain, unanimated image, then this function will return
* %TRUE. Use gdk_pixbuf_animation_get_static_image() to retrieve
* the image.
*
* Return value: %TRUE if the "animation" was really just an image
**/
gboolean
gdk_pixbuf_animation_is_static_image (GdkPixbufAnimation *animation)
{
g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), FALSE);
return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->is_static_image (animation);
}
/**
* gdk_pixbuf_animation_get_static_image:
* @animation: a #GdkPixbufAnimation
*
* If an animation is really just a plain image (has only one frame),
* this function returns that image. If the animation is an animation,
* this function returns a reasonable thing to display as a static
* unanimated image, which might be the first frame, or something more
* sophisticated. If an animation hasn't loaded any frames yet, this
* function will return %NULL.
*
* Return value: unanimated image representing the animation
**/
GdkPixbuf*
gdk_pixbuf_animation_get_static_image (GdkPixbufAnimation *animation)
{
g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_static_image (animation);
}
/** /**
* gdk_pixbuf_animation_get_width: * gdk_pixbuf_animation_get_width:
* @animation: An animation. * @animation: An animation.
@ -272,9 +319,16 @@ gdk_pixbuf_animation_unref (GdkPixbufAnimation *animation)
int int
gdk_pixbuf_animation_get_width (GdkPixbufAnimation *animation) gdk_pixbuf_animation_get_width (GdkPixbufAnimation *animation)
{ {
g_return_val_if_fail (animation != NULL, -1); int width;
return animation->width; g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), 0);
width = 0;
GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_size (animation,
&width, NULL);
return width;
} }
/** /**
@ -288,179 +342,444 @@ gdk_pixbuf_animation_get_width (GdkPixbufAnimation *animation)
int int
gdk_pixbuf_animation_get_height (GdkPixbufAnimation *animation) gdk_pixbuf_animation_get_height (GdkPixbufAnimation *animation)
{ {
g_return_val_if_fail (animation != NULL, -1); int height;
return animation->height; g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), 0);
height = 0;
GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_size (animation,
NULL, &height);
return height;
} }
/**
* gdk_pixbuf_animation_get_num_frames:
* @animation: An animation.
*
* Queries the number of frames in a pixbuf animation.
*
* Return value: Number of frames in the animation.
**/
int
gdk_pixbuf_animation_get_num_frames (GdkPixbufAnimation *animation)
{
g_return_val_if_fail (animation != NULL, -1);
return animation->n_frames;
}
/** /**
* gdk_pixbuf_animation_get_frames: * gdk_pixbuf_animation_get_iter:
* @animation: An animation. * @animation: a #GdkPixbufAnimation
* @start_time: time when the animation starts playing
* *
* Queries the list of frames of an animation. * Get an iterator for displaying an animation. The iterator provides
* the frames that should be displayed at a given time.
* It should be freed after use with g_object_unref().
* *
* Return value: List of frames in the animation; this is a #GList of * @start_time would normally come from g_get_current_time(), and
* #GdkPixbufFrame structures. * marks the beginning of animation playback. After creating an
* iterator, you should immediately display the pixbuf returned by
* gdk_pixbuf_animation_iter_get_pixbuf(). Then, you should install a
* timeout (with g_timeout_add()) or by some other mechanism ensure
* that you'll update the image after
* gdk_pixbuf_animation_iter_get_delay_time() milliseconds. Each time
* the image is updated, you should reinstall the timeout with the new,
* possibly-changed delay time.
*
* As a shortcut, if @start_time is %NULL, the result of
* g_get_current_time() will be used automatically.
*
* To update the image (i.e. possibly change the result of
* gdk_pixbuf_animation_iter_get_pixbuf() to a new frame of the animation),
* call gdk_pixbuf_animation_iter_advance().
*
* If you're using #GdkPixbufLoader, in addition to updating the image
* after the delay time, you should also update it whenever you
* receive the area_updated signal and
* gdk_pixbuf_animation_iter_on_currently_loading_frame() returns
* %TRUE. In this case, the frame currently being fed into the loader
* has received new data, so needs to be refreshed. The delay time for
* a frame may also be modified after an area_updated signal, for
* example if the delay time for a frame is encoded in the data after
* the frame itself. So your timeout should be reinstalled after any
* area_updated signal.
*
* A delay time of -1 is possible, indicating "infinite."
*
* Return value: an iterator to move over the animation
**/ **/
GList * GdkPixbufAnimationIter*
gdk_pixbuf_animation_get_frames (GdkPixbufAnimation *animation) gdk_pixbuf_animation_get_iter (GdkPixbufAnimation *animation,
const GTimeVal *start_time)
{ {
g_return_val_if_fail (animation != NULL, NULL); GTimeVal val;
return animation->frames; g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
if (start_time)
val = *start_time;
else
g_get_current_time (&val);
return GDK_PIXBUF_ANIMATION_GET_CLASS (animation)->get_iter (animation, &val);
} }
GType
gdk_pixbuf_animation_iter_get_type (void)
{
static GType object_type = 0;
if (!object_type) {
static const GTypeInfo object_info = {
sizeof (GdkPixbufAnimationIterClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) NULL,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GdkPixbufAnimationIter),
0, /* n_preallocs */
(GInstanceInitFunc) NULL,
};
object_type = g_type_register_static (G_TYPE_OBJECT,
"GdkPixbufAnimationIter",
&object_info, 0);
}
return object_type;
}
/** /**
* gdk_pixbuf_frame_get_pixbuf: * gdk_pixbuf_animation_iter_get_delay_time:
* @frame: A pixbuf animation frame. * @iter: an animation iterator
* *
* Queries the pixbuf of an animation frame. * Gets the number of milliseconds the current pixbuf should be displayed,
* or -1 if the current pixbuf should be displayed forever. g_timeout_add()
* conveniently takes a timeout in milliseconds, so you can use a timeout
* to schedule the next update.
* *
* Return value: A pixbuf. * Return value: delay time in milliseconds (thousandths of a second)
**/
int
gdk_pixbuf_animation_iter_get_delay_time (GdkPixbufAnimationIter *iter)
{
g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), -1);
return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_delay_time (iter);
}
/**
* gdk_pixbuf_animation_iter_get_pixbuf:
* @iter: an animation iterator
*
* Gets the current pixbuf which should be displayed; the pixbuf will
* be the same size as the animation itself
* (gdk_pixbuf_animation_get_width(),
* gdk_pixbuf_animation_get_height()). This pixbuf should be displayed
* for gdk_pixbuf_animation_get_delay_time() milliseconds. The caller
* of this function does not own a reference to the returned pixbuf;
* the returned pixbuf will become invalid when the iterator advances
* to the next frame, which may happen anytime you call
* gdk_pixbuf_animation_iter_advance(). Copy the pixbuf to keep it
* (don't just add a reference), as it may get recycled as you advance
* the iterator.
*
* Return value: the pixbuf to be displayed
**/ **/
GdkPixbuf* GdkPixbuf*
gdk_pixbuf_frame_get_pixbuf (GdkPixbufFrame *frame) gdk_pixbuf_animation_iter_get_pixbuf (GdkPixbufAnimationIter *iter)
{ {
g_return_val_if_fail (frame != NULL, NULL); g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), NULL);
return frame->pixbuf; return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->get_pixbuf (iter);
} }
/** /**
* gdk_pixbuf_frame_get_x_offset: * gdk_pixbuf_animation_iter_on_currently_loading_frame:
* @frame: A pixbuf animation frame. * @iter: a #GdkPixbufAnimationIter
* *
* Queries the X offset of an animation frame. * Used to determine how to respond to the area_updated signal on
* #GdkPixbufLoader when loading an animation. area_updated is emitted
* for an area of the frame currently streaming in to the loader. So if
* you're on the currently loading frame, you need to redraw the screen for
* the updated area.
* *
* Return value: X offset from the top left corner of the animation. * Return value: %TRUE if the frame we're on is partially loaded, or the last frame
**/ **/
int gboolean
gdk_pixbuf_frame_get_x_offset (GdkPixbufFrame *frame) gdk_pixbuf_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter)
{ {
g_return_val_if_fail (frame != NULL, -1); g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), FALSE);
return frame->x_offset; return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->on_currently_loading_frame (iter);
} }
/** /**
* gdk_pixbuf_frame_get_y_offset: * gdk_pixbuf_animation_iter_advance:
* @frame: A pixbuf animation frame. * @iter: a #GdkPixbufAnimationIter
* @current_time: current time
* *
* Queries the Y offset of an animation frame. * Possibly advances an animation to a new frame. Chooses the frame based
* on the start time passed to gdk_pixbuf_animation_get_iter().
*
* @current_time would normally come from g_get_current_time(), and
* must be greater than or equal to the time passed to
* gdk_pixbuf_animation_get_iter(), and must increase or remain
* unchanged each time gdk_pixbuf_animation_iter_get_pixbuf() is
* called. That is, you can't go backward in time; animations only
* play forward.
*
* As a shortcut, pass %NULL for the current time and g_get_current_time()
* will be invoked on your behalf. So you only need to explicitly pass
* @current_time if you're doing something odd like playing the animation
* at double speed.
*
* If this function returns %FALSE, there's no need to update the animation
* display, assuming the display had been rendered prior to advancing;
* if %TRUE, you need to call gdk_animation_iter_get_pixbuf() and update the
* display with the new pixbuf.
*
* Returns: %TRUE if the image may need updating
* *
* Return value: Y offset from the top left corner of the animation.
**/ **/
int gboolean
gdk_pixbuf_frame_get_y_offset (GdkPixbufFrame *frame) gdk_pixbuf_animation_iter_advance (GdkPixbufAnimationIter *iter,
const GTimeVal *current_time)
{ {
g_return_val_if_fail (frame != NULL, -1); GTimeVal val;
return frame->y_offset; g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (iter), FALSE);
if (current_time)
val = *current_time;
else
g_get_current_time (&val);
return GDK_PIXBUF_ANIMATION_ITER_GET_CLASS (iter)->advance (iter, &val);
} }
/**
* gdk_pixbuf_frame_get_delay_time:
* @frame: A pixbuf animation frame.
*
* Queries the delay time in milliseconds of an animation frame.
*
* Return value: Delay time in milliseconds.
**/
int
gdk_pixbuf_frame_get_delay_time (GdkPixbufFrame *frame)
{
g_return_val_if_fail (frame != NULL, -1);
return frame->delay_time; static void gdk_pixbuf_non_anim_class_init (GdkPixbufNonAnimClass *klass);
} static void gdk_pixbuf_non_anim_finalize (GObject *object);
/** static gboolean gdk_pixbuf_non_anim_is_static_image (GdkPixbufAnimation *animation);
* gdk_pixbuf_frame_get_action: static GdkPixbuf* gdk_pixbuf_non_anim_get_static_image (GdkPixbufAnimation *animation);
* @frame: A pixbuf animation frame. static void gdk_pixbuf_non_anim_get_size (GdkPixbufAnimation *anim,
* int *width,
* Queries the overlay action of an animation frame. int *height);
* static GdkPixbufAnimationIter* gdk_pixbuf_non_anim_get_iter (GdkPixbufAnimation *anim,
* Return value: Overlay action for this frame. const GTimeVal *start_time);
**/
GdkPixbufFrameAction
gdk_pixbuf_frame_get_action (GdkPixbufFrame *frame)
{
g_return_val_if_fail (frame != NULL, GDK_PIXBUF_FRAME_RETAIN);
return frame->action;
}
/**
* gdk_pixbuf_frame_copy:
* @src: a #GdkPixbufFrame to copy
*
* Copies a #GdkPixbufFrame. Free the result
* with gdk_pixbuf_frame_free().
*
* Return value: a new #GdkPixbufFrame
**/
GdkPixbufFrame*
gdk_pixbuf_frame_copy (GdkPixbufFrame *src)
{
GdkPixbufFrame *frame;
frame = g_new (GdkPixbufFrame, 1);
frame->pixbuf = src->pixbuf;
g_object_ref (G_OBJECT (frame->pixbuf));
frame->x_offset = src->x_offset;
frame->y_offset = src->y_offset;
frame->delay_time = src->delay_time;
frame->action = src->action;
return frame; static gpointer non_parent_class;
}
/**
* gdk_pixbuf_frame_free:
* @frame: a #GdkPixbufFrame
*
* Frees a #GdkPixbufFrame. Don't do this with frames you got from
* #GdkPixbufAnimation, usually the animation owns those (it doesn't
* make a copy before returning the frame).
**/
void
gdk_pixbuf_frame_free (GdkPixbufFrame *frame)
{
g_return_if_fail (frame != NULL);
g_object_unref (G_OBJECT (frame->pixbuf));
g_free (frame);
}
GType GType
gdk_pixbuf_frame_get_type (void) gdk_pixbuf_non_anim_get_type (void)
{ {
static GType our_type = 0; static GType object_type = 0;
if (our_type == 0) if (!object_type) {
our_type = g_boxed_type_register_static ("GdkPixbufFrame", static const GTypeInfo object_info = {
NULL, sizeof (GdkPixbufNonAnimClass),
gdk_pixbuf_frame_copy, (GBaseInitFunc) NULL,
gdk_pixbuf_frame_free, (GBaseFinalizeFunc) NULL,
FALSE); (GClassInitFunc) gdk_pixbuf_non_anim_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GdkPixbufNonAnim),
0, /* n_preallocs */
(GInstanceInitFunc) NULL,
};
return our_type; object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION,
"GdkPixbufNonAnim",
&object_info, 0);
} }
return object_type;
}
static void
gdk_pixbuf_non_anim_class_init (GdkPixbufNonAnimClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
non_parent_class = g_type_class_peek_parent (klass);
object_class->finalize = gdk_pixbuf_non_anim_finalize;
anim_class->is_static_image = gdk_pixbuf_non_anim_is_static_image;
anim_class->get_static_image = gdk_pixbuf_non_anim_get_static_image;
anim_class->get_size = gdk_pixbuf_non_anim_get_size;
anim_class->get_iter = gdk_pixbuf_non_anim_get_iter;
}
static void
gdk_pixbuf_non_anim_finalize (GObject *object)
{
GdkPixbufNonAnim *non_anim = GDK_PIXBUF_NON_ANIM (object);
if (non_anim->pixbuf)
g_object_unref (G_OBJECT (non_anim->pixbuf));
G_OBJECT_CLASS (non_parent_class)->finalize (object);
}
GdkPixbufAnimation*
gdk_pixbuf_non_anim_new (GdkPixbuf *pixbuf)
{
GdkPixbufNonAnim *non_anim;
non_anim = g_object_new (GDK_TYPE_PIXBUF_NON_ANIM, NULL);
non_anim->pixbuf = pixbuf;
if (pixbuf)
g_object_ref (G_OBJECT (pixbuf));
return GDK_PIXBUF_ANIMATION (non_anim);
}
static gboolean
gdk_pixbuf_non_anim_is_static_image (GdkPixbufAnimation *animation)
{
return TRUE;
}
static GdkPixbuf*
gdk_pixbuf_non_anim_get_static_image (GdkPixbufAnimation *animation)
{
GdkPixbufNonAnim *non_anim;
non_anim = GDK_PIXBUF_NON_ANIM (animation);
return non_anim->pixbuf;
}
static void
gdk_pixbuf_non_anim_get_size (GdkPixbufAnimation *anim,
int *width,
int *height)
{
GdkPixbufNonAnim *non_anim;
non_anim = GDK_PIXBUF_NON_ANIM (anim);
if (width)
*width = gdk_pixbuf_get_width (non_anim->pixbuf);
if (height)
*height = gdk_pixbuf_get_height (non_anim->pixbuf);
}
static GdkPixbufAnimationIter*
gdk_pixbuf_non_anim_get_iter (GdkPixbufAnimation *anim,
const GTimeVal *start_time)
{
GdkPixbufNonAnimIter *iter;
iter = g_object_new (GDK_TYPE_PIXBUF_NON_ANIM_ITER, NULL);
iter->non_anim = GDK_PIXBUF_NON_ANIM (anim);
g_object_ref (G_OBJECT (iter->non_anim));
return GDK_PIXBUF_ANIMATION_ITER (iter);
}
static void gdk_pixbuf_non_anim_iter_class_init (GdkPixbufNonAnimIterClass *klass);
static void gdk_pixbuf_non_anim_iter_finalize (GObject *object);
static int gdk_pixbuf_non_anim_iter_get_delay_time (GdkPixbufAnimationIter *iter);
static GdkPixbuf* gdk_pixbuf_non_anim_iter_get_pixbuf (GdkPixbufAnimationIter *iter);
static gboolean gdk_pixbuf_non_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
static gboolean gdk_pixbuf_non_anim_iter_advance (GdkPixbufAnimationIter *iter,
const GTimeVal *current_time);
static gpointer non_iter_parent_class;
GType
gdk_pixbuf_non_anim_iter_get_type (void)
{
static GType object_type = 0;
if (!object_type) {
static const GTypeInfo object_info = {
sizeof (GdkPixbufNonAnimIterClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gdk_pixbuf_non_anim_iter_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GdkPixbufNonAnimIter),
0, /* n_preallocs */
(GInstanceInitFunc) NULL,
};
object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION_ITER,
"GdkPixbufNonAnimIter",
&object_info, 0);
}
return object_type;
}
static void
gdk_pixbuf_non_anim_iter_class_init (GdkPixbufNonAnimIterClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdkPixbufAnimationIterClass *anim_iter_class =
GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
non_iter_parent_class = g_type_class_peek_parent (klass);
object_class->finalize = gdk_pixbuf_non_anim_iter_finalize;
anim_iter_class->get_delay_time = gdk_pixbuf_non_anim_iter_get_delay_time;
anim_iter_class->get_pixbuf = gdk_pixbuf_non_anim_iter_get_pixbuf;
anim_iter_class->on_currently_loading_frame = gdk_pixbuf_non_anim_iter_on_currently_loading_frame;
anim_iter_class->advance = gdk_pixbuf_non_anim_iter_advance;
}
static void
gdk_pixbuf_non_anim_iter_finalize (GObject *object)
{
GdkPixbufNonAnimIter *iter = GDK_PIXBUF_NON_ANIM_ITER (object);
g_object_unref (G_OBJECT (iter->non_anim));
G_OBJECT_CLASS (non_iter_parent_class)->finalize (object);
}
static int
gdk_pixbuf_non_anim_iter_get_delay_time (GdkPixbufAnimationIter *iter)
{
return -1; /* show only frame forever */
}
static GdkPixbuf*
gdk_pixbuf_non_anim_iter_get_pixbuf (GdkPixbufAnimationIter *iter)
{
return GDK_PIXBUF_NON_ANIM_ITER (iter)->non_anim->pixbuf;
}
static gboolean
gdk_pixbuf_non_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter)
{
return TRUE;
}
static gboolean
gdk_pixbuf_non_anim_iter_advance (GdkPixbufAnimationIter *iter,
const GTimeVal *current_time)
{
/* Advancing never requires a refresh */
return FALSE;
}

View File

@ -39,15 +39,14 @@ extern "C" {
typedef void (* ModulePreparedNotifyFunc) (GdkPixbuf *pixbuf, gpointer user_data); typedef void (* ModulePreparedNotifyFunc) (GdkPixbuf *pixbuf,
GdkPixbufAnimation *anim,
gpointer user_data);
typedef void (* ModuleUpdatedNotifyFunc) (GdkPixbuf *pixbuf, typedef void (* ModuleUpdatedNotifyFunc) (GdkPixbuf *pixbuf,
guint x, guint y, int x,
guint width, guint height, int y,
gpointer user_data); int width,
/* Needed only for animated images. */ int height,
typedef void (* ModuleFrameDoneNotifyFunc) (GdkPixbufFrame *frame,
gpointer user_data);
typedef void (* ModuleAnimationDoneNotifyFunc) (GdkPixbuf *pixbuf,
gpointer user_data); gpointer user_data);
typedef struct _GdkPixbufModule GdkPixbufModule; typedef struct _GdkPixbufModule GdkPixbufModule;
@ -63,8 +62,6 @@ struct _GdkPixbufModule {
gpointer (* begin_load) (ModulePreparedNotifyFunc prepare_func, gpointer (* begin_load) (ModulePreparedNotifyFunc prepare_func,
ModuleUpdatedNotifyFunc update_func, ModuleUpdatedNotifyFunc update_func,
ModuleFrameDoneNotifyFunc frame_done_func,
ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data, gpointer user_data,
GError **error); GError **error);
gboolean (* stop_load) (gpointer context, gboolean (* stop_load) (gpointer context,

View File

@ -35,8 +35,6 @@
enum { enum {
AREA_UPDATED, AREA_UPDATED,
AREA_PREPARED, AREA_PREPARED,
FRAME_DONE,
ANIMATION_DONE,
CLOSED, CLOSED,
LAST_SIGNAL LAST_SIGNAL
}; };
@ -56,7 +54,6 @@ static guint pixbuf_loader_signals[LAST_SIGNAL] = { 0 };
typedef struct typedef struct
{ {
GdkPixbuf *pixbuf;
GdkPixbufAnimation *animation; GdkPixbufAnimation *animation;
gboolean closed; gboolean closed;
guchar header_buf[LOADER_HEADER_SIZE]; guchar header_buf[LOADER_HEADER_SIZE];
@ -136,25 +133,6 @@ gdk_pixbuf_loader_class_init (GdkPixbufLoaderClass *class)
G_TYPE_INT, G_TYPE_INT,
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] = pixbuf_loader_signals[CLOSED] =
g_signal_newc ("closed", g_signal_newc ("closed",
G_TYPE_FROM_CLASS (object_class), G_TYPE_FROM_CLASS (object_class),
@ -189,9 +167,6 @@ gdk_pixbuf_loader_finalize (GObject *object)
if (priv->animation) if (priv->animation)
gdk_pixbuf_animation_unref (priv->animation); gdk_pixbuf_animation_unref (priv->animation);
if (priv->pixbuf)
gdk_pixbuf_unref (priv->pixbuf);
g_free (priv); g_free (priv);
G_OBJECT_CLASS (parent_class)->finalize (object); G_OBJECT_CLASS (parent_class)->finalize (object);
@ -199,25 +174,29 @@ gdk_pixbuf_loader_finalize (GObject *object)
static void static void
gdk_pixbuf_loader_prepare (GdkPixbuf *pixbuf, gdk_pixbuf_loader_prepare (GdkPixbuf *pixbuf,
GdkPixbufAnimation *anim,
gpointer loader) gpointer loader)
{ {
GdkPixbufLoaderPrivate *priv = NULL; GdkPixbufLoaderPrivate *priv = NULL;
priv = GDK_PIXBUF_LOADER (loader)->priv; 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); g_signal_emit (G_OBJECT (loader), pixbuf_loader_signals[AREA_PREPARED], 0);
} }
static void static void
gdk_pixbuf_loader_update (GdkPixbuf *pixbuf, gdk_pixbuf_loader_update (GdkPixbuf *pixbuf,
guint x, gint x,
guint y, gint y,
guint width, gint width,
guint height, gint height,
gpointer loader) gpointer loader)
{ {
GdkPixbufLoaderPrivate *priv = NULL; GdkPixbufLoaderPrivate *priv = NULL;
@ -229,82 +208,8 @@ gdk_pixbuf_loader_update (GdkPixbuf *pixbuf,
0, 0,
x, y, x, y,
/* sanity check in here. Defend against an errant loader */ /* sanity check in here. Defend against an errant loader */
MIN (width, gdk_pixbuf_get_width (priv->pixbuf)), MIN (width, gdk_pixbuf_animation_get_width (priv->animation)),
MIN (height, gdk_pixbuf_get_height (priv->pixbuf))); MIN (height, gdk_pixbuf_animation_get_height (priv->animation)));
}
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);
} }
static gint static gint
@ -353,8 +258,6 @@ gdk_pixbuf_loader_load_module (GdkPixbufLoader *loader,
priv->context = priv->image_module->begin_load (gdk_pixbuf_loader_prepare, priv->context = priv->image_module->begin_load (gdk_pixbuf_loader_prepare,
gdk_pixbuf_loader_update, gdk_pixbuf_loader_update,
gdk_pixbuf_loader_frame_done,
gdk_pixbuf_loader_animation_done,
loader, loader,
error); error);
@ -540,13 +443,14 @@ gdk_pixbuf_loader_new_with_type (const char *image_type,
* "area_prepared" signal has been emitted by the loader; this means * "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 * 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 * 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, * returned pixbuf will be the same in all future calls to the loader,
* so simply calling gdk_pixbuf_ref() should be sufficient to continue * so simply calling gdk_pixbuf_ref() should be sufficient to continue
* using it. Additionally, if the loader is an animation, it will * 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. * enough data has been read to determine how to create the image buffer.
**/ **/
GdkPixbuf * GdkPixbuf *
@ -560,19 +464,9 @@ gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader)
priv = loader->priv; priv = loader->priv;
if (priv->animation) if (priv->animation)
{ return gdk_pixbuf_animation_get_static_image (priv->animation);
GList *list; else
return NULL;
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;
} }
/** /**
@ -581,8 +475,9 @@ gdk_pixbuf_loader_get_pixbuf (GdkPixbufLoader *loader)
* *
* Queries the GdkPixbufAnimation that a pixbuf loader is currently creating. * Queries the GdkPixbufAnimation that a pixbuf loader is currently creating.
* In general it only makes sense to call this function afer the "area_prepared" * 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, * signal has been emitted by the loader. If the loader doesn't have enough
* then it will return NULL. * 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 * Return value: The GdkPixbufAnimation that the loader is loading, or NULL if
not enough data has been read to determine the information. not enough data has been read to determine the information.

View File

@ -53,14 +53,14 @@ struct _GdkPixbufLoaderClass
GObjectClass parent_class; GObjectClass parent_class;
void (*area_prepared) (GdkPixbufLoader *loader); void (*area_prepared) (GdkPixbufLoader *loader);
/* Last known frame needs a redraw for x, y, width, height */
void (*area_updated) (GdkPixbufLoader *loader, void (*area_updated) (GdkPixbufLoader *loader,
guint x, int x,
guint y, int y,
guint width, int width,
guint height); int height);
void (*frame_done) (GdkPixbufLoader *loader,
GdkPixbufFrame *frame);
void (*animation_done) (GdkPixbufLoader *loader);
void (*closed) (GdkPixbufLoader *loader); void (*closed) (GdkPixbufLoader *loader);
}; };

View File

@ -1,3 +1,4 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
/* GdkPixbuf library - Private declarations /* GdkPixbuf library - Private declarations
* *
* Copyright (C) 1999 The Free Software Foundation * 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; typedef struct _GdkPixbufAnimationClass GdkPixbufAnimationClass;
#define GDK_PIXBUF_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_ANIMATION, GdkPixbufAnimationClass)) #define GDK_PIXBUF_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_ANIMATION, GdkPixbufAnimationClass))
@ -99,20 +84,48 @@ typedef struct _GdkPixbufAnimationClass GdkPixbufAnimationClass;
struct _GdkPixbufAnimation { struct _GdkPixbufAnimation {
GObject parent_instance; GObject parent_instance;
/* Number of frames */
int n_frames;
/* List of GdkPixbufFrame structures */
GList *frames;
/* bounding box size */
int width, height;
}; };
struct _GdkPixbufAnimationClass { struct _GdkPixbufAnimationClass {
GObjectClass parent_class; GObjectClass parent_class;
gboolean (*is_static_image) (GdkPixbufAnimation *anim);
GdkPixbuf* (*get_static_image) (GdkPixbufAnimation *anim);
void (*get_size) (GdkPixbufAnimation *anim,
int *width,
int *height);
GdkPixbufAnimationIter* (*get_iter) (GdkPixbufAnimation *anim,
const GTimeVal *start_time);
};
typedef struct _GdkPixbufAnimationIterClass GdkPixbufAnimationIterClass;
#define GDK_PIXBUF_ANIMATION_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_ANIMATION_ITER, GdkPixbufAnimationIterClass))
#define GDK_IS_PIXBUF_ANIMATION_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_ANIMATION_ITER))
#define GDK_PIXBUF_ANIMATION_ITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_ANIMATION_ITER, GdkPixbufAnimationIterClass))
struct _GdkPixbufAnimationIter {
GObject parent_instance;
};
struct _GdkPixbufAnimationIterClass {
GObjectClass parent_class;
int (*get_delay_time) (GdkPixbufAnimationIter *iter);
GdkPixbuf* (*get_pixbuf) (GdkPixbufAnimationIter *iter);
gboolean (*on_currently_loading_frame) (GdkPixbufAnimationIter *iter);
gboolean (*advance) (GdkPixbufAnimationIter *iter,
const GTimeVal *current_time);
}; };
@ -125,6 +138,8 @@ typedef enum
GDK_PIXBUF_INLINE_RLE = 1 GDK_PIXBUF_INLINE_RLE = 1
} GdkPixbufInlineFormat; } GdkPixbufInlineFormat;
GdkPixbufAnimation* gdk_pixbuf_non_anim_new (GdkPixbuf *pixbuf);
#endif #endif

View File

@ -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_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 (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 */ /* This will perform format conversions automatically */
gdk_pixbuf_scale (src_pixbuf, gdk_pixbuf_scale (src_pixbuf,

View File

@ -412,7 +412,7 @@ gdk_pixbuf_error_quark (void)
/** /**
* gdk_pixbuf_fill: * gdk_pixbuf_fill:
* @pixbuf: a #GdkPixbuf * @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 * 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 * the pixbuf's pixel format. The alpha will be ignored if the pixbuf
@ -454,7 +454,7 @@ gdk_pixbuf_fill (GdkPixbuf *pixbuf,
p = pixels; p = pixels;
end = pixels + pixbuf->rowstride * pixbuf->height; end = pixels + pixbuf->rowstride * pixbuf->height;
end -= (pixbuf->rowstride - pixbuf->width); end -= (pixbuf->rowstride - pixbuf->width * pixbuf->n_channels);
while (p < end) { while (p < end) {
*p++ = r; *p++ = r;

View File

@ -54,6 +54,7 @@ typedef enum {
/* All of these are opaque structures */ /* All of these are opaque structures */
typedef struct _GdkPixbuf GdkPixbuf; typedef struct _GdkPixbuf GdkPixbuf;
typedef struct _GdkPixbufAnimation GdkPixbufAnimation; typedef struct _GdkPixbufAnimation GdkPixbufAnimation;
typedef struct _GdkPixbufAnimationIter GdkPixbufAnimationIter;
typedef struct _GdkPixbufFrame GdkPixbufFrame; typedef struct _GdkPixbufFrame GdkPixbufFrame;
#define GDK_TYPE_PIXBUF (gdk_pixbuf_get_type ()) #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_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_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 */ /* Handler that must free the pixel array */
typedef void (* GdkPixbufDestroyNotify) (guchar *pixels, gpointer data); typedef void (* GdkPixbufDestroyNotify) (guchar *pixels, gpointer data);
@ -255,13 +259,6 @@ GdkPixbuf *gdk_pixbuf_composite_color_simple (const GdkPixbuf *src,
/* Animation support */ /* 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; GType gdk_pixbuf_animation_get_type (void) G_GNUC_CONST;
GdkPixbufAnimation *gdk_pixbuf_animation_new_from_file (const char *filename, GdkPixbufAnimation *gdk_pixbuf_animation_new_from_file (const char *filename,
@ -272,20 +269,19 @@ void gdk_pixbuf_animation_unref (GdkPixbufAnimation *an
int gdk_pixbuf_animation_get_width (GdkPixbufAnimation *animation); int gdk_pixbuf_animation_get_width (GdkPixbufAnimation *animation);
int gdk_pixbuf_animation_get_height (GdkPixbufAnimation *animation); int gdk_pixbuf_animation_get_height (GdkPixbufAnimation *animation);
GList *gdk_pixbuf_animation_get_frames (GdkPixbufAnimation *animation); gboolean gdk_pixbuf_animation_is_static_image (GdkPixbufAnimation *animation);
int gdk_pixbuf_animation_get_num_frames (GdkPixbufAnimation *animation); GdkPixbuf *gdk_pixbuf_animation_get_static_image (GdkPixbufAnimation *animation);
GdkPixbufAnimationIter *gdk_pixbuf_animation_get_iter (GdkPixbufAnimation *animation,
const GTimeVal *start_time);
GType gdk_pixbuf_animation_iter_get_type (void) G_GNUC_CONST;
int gdk_pixbuf_animation_iter_get_delay_time (GdkPixbufAnimationIter *iter);
GdkPixbuf *gdk_pixbuf_animation_iter_get_pixbuf (GdkPixbufAnimationIter *iter);
gboolean gdk_pixbuf_animation_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
gboolean gdk_pixbuf_animation_iter_advance (GdkPixbufAnimationIter *iter,
const GTimeVal *current_time);
/* Frame accessors */
GdkPixbuf *gdk_pixbuf_frame_get_pixbuf (GdkPixbufFrame *frame);
int gdk_pixbuf_frame_get_x_offset (GdkPixbufFrame *frame);
int gdk_pixbuf_frame_get_y_offset (GdkPixbufFrame *frame);
int gdk_pixbuf_frame_get_delay_time (GdkPixbufFrame *frame);
GdkPixbufFrameAction gdk_pixbuf_frame_get_action (GdkPixbufFrame *frame);
GdkPixbufFrame *gdk_pixbuf_frame_copy (GdkPixbufFrame *src);
void gdk_pixbuf_frame_free (GdkPixbufFrame *frame);
GType gdk_pixbuf_frame_get_type (void) G_GNUC_CONST;
#define GDK_TYPE_PIXBUF_FRAME gdk_pixbuf_frame_get_type ()
#include <gdk-pixbuf/gdk-pixbuf-loader.h> #include <gdk-pixbuf/gdk-pixbuf-loader.h>

View File

@ -174,9 +174,7 @@ struct bmp_progressive_state {
static gpointer static gpointer
gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func, gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func, ModuleUpdatedNotifyFunc updated_func,
ModuleFrameDoneNotifyFunc frame_done_func, gpointer user_data,
ModuleAnimationDoneNotifyFunc
anim_done_func, gpointer user_data,
GError **error); GError **error);
static gboolean gdk_pixbuf__bmp_image_stop_load(gpointer 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; GdkPixbuf *pb;
State = State =
gdk_pixbuf__bmp_image_begin_load(NULL, NULL, NULL, NULL, NULL, gdk_pixbuf__bmp_image_begin_load(NULL, NULL, NULL,
error); error);
if (State == NULL) if (State == NULL)
@ -312,7 +310,7 @@ static gboolean DecodeHeader(unsigned char *BFH, unsigned char *BIH,
if (State->prepared_func != NULL) if (State->prepared_func != NULL)
/* Notify the client that we are ready to go */ /* 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 static gpointer
gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func, gdk_pixbuf__bmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func, ModuleUpdatedNotifyFunc updated_func,
ModuleFrameDoneNotifyFunc frame_done_func, gpointer user_data,
ModuleAnimationDoneNotifyFunc
anim_done_func, gpointer user_data,
GError **error) GError **error)
{ {
struct bmp_progressive_state *context; struct bmp_progressive_state *context;

View File

@ -0,0 +1,557 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
/* GdkPixbuf library - animated gif support
*
* Copyright (C) 1999 The Free Software Foundation
*
* Authors: Jonathan Blandford <jrb@redhat.com>
* Havoc Pennington <hp@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include <config.h>
#include <errno.h>
#include "gdk-pixbuf-io.h"
#include "gdk-pixbuf-private.h"
#include "io-gif-animation.h"
static void gdk_pixbuf_gif_anim_class_init (GdkPixbufGifAnimClass *klass);
static void gdk_pixbuf_gif_anim_finalize (GObject *object);
static gboolean gdk_pixbuf_gif_anim_is_static_image (GdkPixbufAnimation *animation);
static GdkPixbuf* gdk_pixbuf_gif_anim_get_static_image (GdkPixbufAnimation *animation);
static void gdk_pixbuf_gif_anim_get_size (GdkPixbufAnimation *anim,
int *width,
int *height);
static GdkPixbufAnimationIter* gdk_pixbuf_gif_anim_get_iter (GdkPixbufAnimation *anim,
const GTimeVal *start_time);
static gpointer parent_class;
GType
gdk_pixbuf_gif_anim_get_type (void)
{
static GType object_type = 0;
if (!object_type) {
static const GTypeInfo object_info = {
sizeof (GdkPixbufGifAnimClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gdk_pixbuf_gif_anim_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GdkPixbufGifAnim),
0, /* n_preallocs */
(GInstanceInitFunc) NULL,
};
object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION,
"GdkPixbufGifAnim",
&object_info, 0);
}
return object_type;
}
static void
gdk_pixbuf_gif_anim_class_init (GdkPixbufGifAnimClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdkPixbufAnimationClass *anim_class = GDK_PIXBUF_ANIMATION_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
object_class->finalize = gdk_pixbuf_gif_anim_finalize;
anim_class->is_static_image = gdk_pixbuf_gif_anim_is_static_image;
anim_class->get_static_image = gdk_pixbuf_gif_anim_get_static_image;
anim_class->get_size = gdk_pixbuf_gif_anim_get_size;
anim_class->get_iter = gdk_pixbuf_gif_anim_get_iter;
}
static void
gdk_pixbuf_gif_anim_finalize (GObject *object)
{
GdkPixbufGifAnim *gif_anim = GDK_PIXBUF_GIF_ANIM (object);
GList *l;
GdkPixbufFrame *frame;
for (l = gif_anim->frames; l; l = l->next) {
frame = l->data;
gdk_pixbuf_unref (frame->pixbuf);
if (frame->composited)
gdk_pixbuf_unref (frame->composited);
if (frame->revert)
gdk_pixbuf_unref (frame->revert);
g_free (frame);
}
g_list_free (gif_anim->frames);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gboolean
gdk_pixbuf_gif_anim_is_static_image (GdkPixbufAnimation *animation)
{
GdkPixbufGifAnim *gif_anim;
gif_anim = GDK_PIXBUF_GIF_ANIM (animation);
return (gif_anim->frames != NULL &&
gif_anim->frames->next == NULL);
}
static GdkPixbuf*
gdk_pixbuf_gif_anim_get_static_image (GdkPixbufAnimation *animation)
{
GdkPixbufGifAnim *gif_anim;
gif_anim = GDK_PIXBUF_GIF_ANIM (animation);
if (gif_anim->frames == NULL)
return NULL;
else
return GDK_PIXBUF (((GdkPixbufFrame*)gif_anim->frames->data)->pixbuf);
}
static void
gdk_pixbuf_gif_anim_get_size (GdkPixbufAnimation *anim,
int *width,
int *height)
{
GdkPixbufGifAnim *gif_anim;
gif_anim = GDK_PIXBUF_GIF_ANIM (anim);
if (width)
*width = gif_anim->width;
if (height)
*height = gif_anim->height;
}
static void
iter_clear (GdkPixbufGifAnimIter *iter)
{
iter->current_frame = NULL;
}
static void
iter_restart (GdkPixbufGifAnimIter *iter)
{
iter_clear (iter);
iter->current_frame = iter->gif_anim->frames;
}
static GdkPixbufAnimationIter*
gdk_pixbuf_gif_anim_get_iter (GdkPixbufAnimation *anim,
const GTimeVal *start_time)
{
GdkPixbufGifAnimIter *iter;
iter = g_object_new (GDK_TYPE_PIXBUF_GIF_ANIM_ITER, NULL);
iter->gif_anim = GDK_PIXBUF_GIF_ANIM (anim);
g_object_ref (G_OBJECT (iter->gif_anim));
iter_restart (iter);
iter->start_time = *start_time;
iter->current_time = *start_time;
return GDK_PIXBUF_ANIMATION_ITER (iter);
}
static void gdk_pixbuf_gif_anim_iter_class_init (GdkPixbufGifAnimIterClass *klass);
static void gdk_pixbuf_gif_anim_iter_finalize (GObject *object);
static int gdk_pixbuf_gif_anim_iter_get_delay_time (GdkPixbufAnimationIter *iter);
static GdkPixbuf* gdk_pixbuf_gif_anim_iter_get_pixbuf (GdkPixbufAnimationIter *iter);
static gboolean gdk_pixbuf_gif_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *iter);
static gboolean gdk_pixbuf_gif_anim_iter_advance (GdkPixbufAnimationIter *iter,
const GTimeVal *current_time);
static gpointer iter_parent_class;
GType
gdk_pixbuf_gif_anim_iter_get_type (void)
{
static GType object_type = 0;
if (!object_type) {
static const GTypeInfo object_info = {
sizeof (GdkPixbufGifAnimIterClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gdk_pixbuf_gif_anim_iter_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GdkPixbufGifAnimIter),
0, /* n_preallocs */
(GInstanceInitFunc) NULL,
};
object_type = g_type_register_static (GDK_TYPE_PIXBUF_ANIMATION_ITER,
"GdkPixbufGifAnimIter",
&object_info, 0);
}
return object_type;
}
static void
gdk_pixbuf_gif_anim_iter_class_init (GdkPixbufGifAnimIterClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GdkPixbufAnimationIterClass *anim_iter_class =
GDK_PIXBUF_ANIMATION_ITER_CLASS (klass);
iter_parent_class = g_type_class_peek_parent (klass);
object_class->finalize = gdk_pixbuf_gif_anim_iter_finalize;
anim_iter_class->get_delay_time = gdk_pixbuf_gif_anim_iter_get_delay_time;
anim_iter_class->get_pixbuf = gdk_pixbuf_gif_anim_iter_get_pixbuf;
anim_iter_class->on_currently_loading_frame = gdk_pixbuf_gif_anim_iter_on_currently_loading_frame;
anim_iter_class->advance = gdk_pixbuf_gif_anim_iter_advance;
}
static void
gdk_pixbuf_gif_anim_iter_finalize (GObject *object)
{
GdkPixbufGifAnimIter *iter = GDK_PIXBUF_GIF_ANIM_ITER (object);
iter_clear (iter);
g_object_unref (G_OBJECT (iter->gif_anim));
G_OBJECT_CLASS (iter_parent_class)->finalize (object);
}
static gboolean
gdk_pixbuf_gif_anim_iter_advance (GdkPixbufAnimationIter *anim_iter,
const GTimeVal *current_time)
{
GdkPixbufGifAnimIter *iter;
gint elapsed;
GList *tmp;
GList *old;
iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
iter->current_time = *current_time;
/* We use milliseconds for all times */
elapsed =
(((iter->current_time.tv_sec - iter->start_time.tv_sec) * G_USEC_PER_SEC +
iter->current_time.tv_usec - iter->start_time.tv_usec)) / 1000;
if (elapsed < 0) {
/* Try to compensate; probably the system clock
* was set backwards
*/
iter->start_time = iter->current_time;
elapsed = 0;
}
/* See how many times we've already played the full animation,
* and subtract time for that.
*/
elapsed = elapsed % iter->gif_anim->total_time;
g_assert (elapsed < iter->gif_anim->total_time);
iter->position = elapsed;
/* Now move to the proper frame */
tmp = iter->gif_anim->frames;
while (tmp != NULL) {
GdkPixbufFrame *frame = tmp->data;
if (iter->position >= frame->elapsed &&
iter->position < (frame->elapsed + frame->delay_time))
break;
tmp = tmp->next;
}
old = iter->current_frame;
iter->current_frame = tmp;
return iter->current_frame != old;
}
int
gdk_pixbuf_gif_anim_iter_get_delay_time (GdkPixbufAnimationIter *anim_iter)
{
GdkPixbufFrame *frame;
GdkPixbufGifAnimIter *iter;
iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
if (iter->current_frame) {
frame = iter->current_frame->data;
#if 0
g_print ("frame start: %d pos: %d frame len: %d frame remaining: %d\n",
frame->elapsed,
iter->position,
frame->delay_time,
frame->delay_time - (iter->position - frame->elapsed));
#endif
return frame->delay_time - (iter->position - frame->elapsed);
} else {
return -1; /* show last frame forever */
}
}
void
gdk_pixbuf_gif_anim_frame_composite (GdkPixbufGifAnim *gif_anim,
GdkPixbufFrame *frame)
{
GList *link;
GList *tmp;
link = g_list_find (gif_anim->frames, frame);
if (frame->need_recomposite || frame->composited == NULL) {
/* For now, to composite we start with the last
* composited frame and composite everything up to
* here.
*/
/* Rewind to last composited frame. */
tmp = link;
while (tmp != NULL) {
GdkPixbufFrame *f = tmp->data;
if (f->need_recomposite) {
if (f->composited) {
g_object_unref (G_OBJECT (f->composited));
f->composited = NULL;
}
}
if (f->composited != NULL)
break;
tmp = tmp->prev;
}
/* Go forward, compositing all frames up to the current frame */
if (tmp == NULL)
tmp = gif_anim->frames;
while (tmp != NULL) {
GdkPixbufFrame *f = tmp->data;
if (f->need_recomposite) {
if (f->composited) {
g_object_unref (G_OBJECT (f->composited));
f->composited = NULL;
}
}
if (f->composited != NULL)
goto next;
if (tmp->prev == NULL) {
/* First frame may be smaller than the whole image;
* if so, we make the area outside it full alpha if the
* image has alpha, and background color otherwise.
* GIF spec doesn't actually say what to do about this.
*/
f->composited = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
TRUE,
8, gif_anim->width, gif_anim->height);
/* alpha gets dumped if f->composited has no alpha */
gdk_pixbuf_fill (f->composited,
(gif_anim->bg_red << 24) |
(gif_anim->bg_green << 16) |
(gif_anim->bg_blue << 8) |
(f->bg_transparent ? 0 : 255));
gdk_pixbuf_composite (f->pixbuf,
f->composited,
f->x_offset,
f->y_offset,
gdk_pixbuf_get_width (f->pixbuf),
gdk_pixbuf_get_height (f->pixbuf),
f->x_offset, f->y_offset,
1.0, 1.0,
GDK_INTERP_BILINEAR,
255);
#if 0
gdk_pixbuf_copy_area (f->pixbuf,
0, 0,
gdk_pixbuf_get_width (f->pixbuf),
gdk_pixbuf_get_height (f->pixbuf),
f->composited,
f->x_offset,
f->y_offset);
#endif
if (f->action == GDK_PIXBUF_FRAME_REVERT)
g_warning ("First frame of GIF has bad dispose mode, GIF loader should not have loaded this image");
f->need_recomposite = FALSE;
} else {
GdkPixbufFrame *prev_frame;
prev_frame = tmp->prev->data;
/* Init f->composited with what we should have after the previous
* frame
*/
if (prev_frame->action == GDK_PIXBUF_FRAME_RETAIN) {
f->composited = gdk_pixbuf_copy (prev_frame->composited);
} else if (prev_frame->action == GDK_PIXBUF_FRAME_DISPOSE) {
GdkPixbuf *area;
f->composited = gdk_pixbuf_copy (prev_frame->composited);
/* Clear area of previous frame to background */
area = gdk_pixbuf_new_subpixbuf (f->composited,
prev_frame->x_offset,
prev_frame->y_offset,
gdk_pixbuf_get_width (prev_frame->pixbuf),
gdk_pixbuf_get_height (prev_frame->pixbuf));
gdk_pixbuf_fill (area,
(gif_anim->bg_red << 24) |
(gif_anim->bg_green << 16) |
(gif_anim->bg_blue << 8) |
prev_frame->bg_transparent ? 0 : 255);
g_object_unref (G_OBJECT (area));
} else if (prev_frame->action == GDK_PIXBUF_FRAME_REVERT) {
f->composited = gdk_pixbuf_copy (prev_frame->composited);
/* Copy in the revert frame */
gdk_pixbuf_copy_area (prev_frame->revert,
0, 0,
gdk_pixbuf_get_width (prev_frame->revert),
gdk_pixbuf_get_height (prev_frame->revert),
f->composited,
prev_frame->x_offset,
prev_frame->y_offset);
} else {
g_warning ("Unknown revert action for GIF frame");
}
if (f->revert == NULL &&
f->action == GDK_PIXBUF_FRAME_REVERT) {
/* We need to save the contents before compositing */
GdkPixbuf *area;
area = gdk_pixbuf_new_subpixbuf (f->composited,
f->x_offset,
f->y_offset,
gdk_pixbuf_get_width (f->pixbuf),
gdk_pixbuf_get_height (f->pixbuf));
f->revert = gdk_pixbuf_copy (area);
g_object_unref (G_OBJECT (area));
}
/* Put current frame onto f->composited */
gdk_pixbuf_composite (f->pixbuf,
f->composited,
f->x_offset,
f->y_offset,
gdk_pixbuf_get_width (f->pixbuf),
gdk_pixbuf_get_height (f->pixbuf),
f->x_offset, f->y_offset,
1.0, 1.0,
GDK_INTERP_NEAREST,
255);
f->need_recomposite = FALSE;
}
next:
if (tmp == link)
break;
tmp = tmp->next;
}
}
g_assert (frame->composited != NULL);
g_assert (gdk_pixbuf_get_width (frame->composited) == gif_anim->width);
g_assert (gdk_pixbuf_get_height (frame->composited) == gif_anim->height);
}
GdkPixbuf*
gdk_pixbuf_gif_anim_iter_get_pixbuf (GdkPixbufAnimationIter *anim_iter)
{
GdkPixbufGifAnimIter *iter;
GdkPixbufFrame *frame;
iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
frame = iter->current_frame ? iter->current_frame->data : NULL;
#if 0
if (FALSE && frame)
g_print ("current frame %d dispose mode %d %d x %d\n",
g_list_index (iter->gif_anim->frames,
frame),
frame->action,
gdk_pixbuf_get_width (frame->pixbuf),
gdk_pixbuf_get_height (frame->pixbuf));
#endif
if (frame == NULL)
return NULL;
gdk_pixbuf_gif_anim_frame_composite (iter->gif_anim, frame);
return frame->composited;
}
static gboolean
gdk_pixbuf_gif_anim_iter_on_currently_loading_frame (GdkPixbufAnimationIter *anim_iter)
{
GdkPixbufGifAnimIter *iter;
iter = GDK_PIXBUF_GIF_ANIM_ITER (anim_iter);
return iter->current_frame == NULL || iter->current_frame->next == NULL;
}

View File

@ -0,0 +1,169 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
/* GdkPixbuf library - GIF loader declarations
*
* Copyright (C) 1999 The Free Software Foundation
*
* Authors: Mark Crichton <crichton@gimp.org>
* Miguel de Icaza <miguel@gnu.org>
* Federico Mena-Quintero <federico@gimp.org>
* Havoc Pennington <hp@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef GDK_PIXBUF_GIF_H
#define GDK_PIXBUF_GIF_H
#include "gdk-pixbuf-private.h"
typedef enum {
/* Keep this frame and composite next frame over it */
/* (GIF disposal method 1) */
GDK_PIXBUF_FRAME_RETAIN,
/* Revert to background color before compositing next frame */
/* (GIF disposal method 2) */
GDK_PIXBUF_FRAME_DISPOSE,
/* Revert to previously-displayed composite image after
* displaying this frame
*/
/* (GIF disposal method 3) */
GDK_PIXBUF_FRAME_REVERT
} GdkPixbufFrameAction;
typedef struct _GdkPixbufGifAnim GdkPixbufGifAnim;
typedef struct _GdkPixbufGifAnimClass GdkPixbufGifAnimClass;
#define GDK_TYPE_PIXBUF_GIF_ANIM (gdk_pixbuf_gif_anim_get_type ())
#define GDK_PIXBUF_GIF_ANIM(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_GIF_ANIM, GdkPixbufGifAnim))
#define GDK_IS_PIXBUF_GIF_ANIM(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_GIF_ANIM))
#define GDK_PIXBUF_GIF_ANIM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_GIF_ANIM, GdkPixbufGifAnimClass))
#define GDK_IS_PIXBUF_GIF_ANIM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_GIF_ANIM))
#define GDK_PIXBUF_GIF_ANIM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_GIF_ANIM, GdkPixbufGifAnimClass))
/* Private part of the GdkPixbufGifAnim structure */
struct _GdkPixbufGifAnim {
GdkPixbufAnimation parent_instance;
/* Number of frames */
int n_frames;
/* Total length of animation */
int total_time;
/* List of GdkPixbufFrame structures */
GList *frames;
/* bounding box size */
int width, height;
guchar bg_red;
guchar bg_green;
guchar bg_blue;
};
struct _GdkPixbufGifAnimClass {
GdkPixbufAnimationClass parent_class;
};
GType gdk_pixbuf_gif_anim_get_type (void) G_GNUC_CONST;
typedef struct _GdkPixbufGifAnimIter GdkPixbufGifAnimIter;
typedef struct _GdkPixbufGifAnimIterClass GdkPixbufGifAnimIterClass;
#define GDK_TYPE_PIXBUF_GIF_ANIM_ITER (gdk_pixbuf_gif_anim_iter_get_type ())
#define GDK_PIXBUF_GIF_ANIM_ITER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_PIXBUF_GIF_ANIM_ITER, GdkPixbufGifAnimIter))
#define GDK_IS_PIXBUF_GIF_ANIM_ITER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_PIXBUF_GIF_ANIM_ITER))
#define GDK_PIXBUF_GIF_ANIM_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIXBUF_GIF_ANIM_ITER, GdkPixbufGifAnimIterClass))
#define GDK_IS_PIXBUF_GIF_ANIM_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIXBUF_GIF_ANIM_ITER))
#define GDK_PIXBUF_GIF_ANIM_ITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIXBUF_GIF_ANIM_ITER, GdkPixbufGifAnimIterClass))
struct _GdkPixbufGifAnimIter {
GdkPixbufAnimationIter parent_instance;
GdkPixbufGifAnim *gif_anim;
GTimeVal start_time;
GTimeVal current_time;
/* Time in milliseconds into this run of the animation */
gint position;
GList *current_frame;
};
struct _GdkPixbufGifAnimIterClass {
GdkPixbufAnimationIterClass parent_class;
};
GType gdk_pixbuf_gif_anim_iter_get_type (void) G_GNUC_CONST;
struct _GdkPixbufFrame {
/* The pixbuf with this frame's image data */
GdkPixbuf *pixbuf;
/* Offsets for overlaying onto the GIF graphic area */
int x_offset;
int y_offset;
/* Frame duration in ms */
int delay_time;
/* Sum of preceding delay times */
int elapsed;
/* Overlay mode */
GdkPixbufFrameAction action;
/* TRUE if the pixbuf has been modified since
* the last frame composite operation
*/
gboolean need_recomposite;
/* TRUE if the background for this frame is transparent */
gboolean bg_transparent;
/* The below reflects the "use hell of a lot of RAM"
* philosophy of coding
*/
/* Cached composite image (the image you actually display
* for this frame)
*/
GdkPixbuf *composited;
/* Cached revert image (the contents of the area
* covered by the frame prior to compositing;
* same size as pixbuf, not as the composite image; only
* used for FRAME_REVERT frames)
*/
GdkPixbuf *revert;
};
void gdk_pixbuf_gif_anim_frame_composite (GdkPixbufGifAnim *gif_anim,
GdkPixbufFrame *frame);
#endif

View File

@ -1,3 +1,4 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
/* GdkPixbuf library - GIF image loader /* GdkPixbuf library - GIF image loader
* *
* Copyright (C) 1999 Mark Crichton * Copyright (C) 1999 Mark Crichton
@ -30,10 +31,6 @@
* in it got a bit messy. Basicly, every function is written to expect a failed * 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. * 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. * Return vals.
* Unless otherwise specified, these are the return vals for most functions: * Unless otherwise specified, these are the return vals for most functions:
* *
@ -59,11 +56,15 @@
#include <config.h> #include <config.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include "gdk-pixbuf-private.h" #include "gdk-pixbuf-private.h"
#include "gdk-pixbuf-io.h" #include "gdk-pixbuf-io.h"
#include "io-gif-animation.h"
#undef DUMP_IMAGE_DETAILS
#define MAXCOLORMAPSIZE 256 #define MAXCOLORMAPSIZE 256
#define MAX_LZW_BITS 12 #define MAX_LZW_BITS 12
@ -88,7 +89,7 @@ enum {
GIF_LZW_FILL_BUFFER, GIF_LZW_FILL_BUFFER,
GIF_LZW_CLEAR_CODE, GIF_LZW_CLEAR_CODE,
GIF_GET_LZW, GIF_GET_LZW,
GIF_DONE, GIF_DONE
}; };
@ -107,19 +108,27 @@ struct _GifContext
int state; /* really only relevant for progressive loading */ int state; /* really only relevant for progressive loading */
unsigned int width; unsigned int width;
unsigned int height; unsigned int height;
CMap color_map;
gboolean has_global_cmap;
CMap global_color_map;
gint global_colormap_size;
unsigned int global_bit_pixel;
unsigned int global_color_resolution;
unsigned int background_index;
gboolean frame_cmap_active;
CMap frame_color_map; CMap frame_color_map;
unsigned int bit_pixel; gint frame_colormap_size;
unsigned int color_resolution; unsigned int frame_bit_pixel;
unsigned int background;
unsigned int aspect_ratio; unsigned int aspect_ratio;
GdkPixbuf *pixbuf; GdkPixbuf *pixbuf;
GdkPixbufAnimation *animation; GdkPixbufGifAnim *animation;
GdkPixbufFrame *frame; GdkPixbufFrame *frame;
Gif89 gif89; Gif89 gif89;
/* stuff per frame. As we only support the first one, not so /* stuff per frame. */
* relevant. But still needed */
int frame_len; int frame_len;
int frame_height; int frame_height;
int frame_interlace; int frame_interlace;
@ -132,18 +141,12 @@ struct _GifContext
/* progressive read, only. */ /* progressive read, only. */
ModulePreparedNotifyFunc prepare_func; ModulePreparedNotifyFunc prepare_func;
ModuleUpdatedNotifyFunc update_func; ModuleUpdatedNotifyFunc update_func;
ModuleFrameDoneNotifyFunc frame_done_func;
ModuleAnimationDoneNotifyFunc anim_done_func;
gpointer user_data; gpointer user_data;
guchar *buf; guchar *buf;
guint ptr; guint ptr;
guint size; guint size;
guint amount_needed; guint amount_needed;
/* colormap context */
gint colormap_index;
gint colormap_flag;
/* extension context */ /* extension context */
guchar extension_label; guchar extension_label;
guchar extension_flag; guchar extension_flag;
@ -208,6 +211,13 @@ gif_read (GifContext *context, guchar *buffer, size_t len)
g_print ("Fsize :%d\tcount :%d\t", len, count); g_print ("Fsize :%d\tcount :%d\t", len, count);
#endif #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 #ifdef IO_GIFDEBUG
if (len < 100) { if (len < 100) {
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
@ -247,16 +257,14 @@ gif_read (GifContext *context, guchar *buffer, size_t len)
static void static void
gif_set_get_colormap (GifContext *context) gif_set_get_colormap (GifContext *context)
{ {
context->colormap_flag = TRUE; context->global_colormap_size = 0;
context->colormap_index = 0;
context->state = GIF_GET_COLORMAP; context->state = GIF_GET_COLORMAP;
} }
static void static void
gif_set_get_colormap2 (GifContext *context) gif_set_get_colormap2 (GifContext *context)
{ {
context->colormap_flag = TRUE; context->frame_colormap_size = 0;
context->colormap_index = 0;
context->state = GIF_GET_COLORMAP2; context->state = GIF_GET_COLORMAP2;
} }
@ -265,18 +273,43 @@ gif_get_colormap (GifContext *context)
{ {
unsigned char rgb[3]; 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))) { if (!gif_read (context, rgb, sizeof (rgb))) {
/*g_message (_("GIF: bad colormap\n"));*/
return -1; return -1;
} }
context->color_map[0][context->colormap_index] = rgb[0]; context->global_color_map[0][context->global_colormap_size] = rgb[0];
context->color_map[1][context->colormap_index] = rgb[1]; context->global_color_map[1][context->global_colormap_size] = rgb[1];
context->color_map[2][context->colormap_index] = rgb[2]; context->global_color_map[2][context->global_colormap_size] = rgb[2];
context->colormap_flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]); if (context->global_colormap_size == context->background_index) {
context->colormap_index ++; context->animation->bg_red = rgb[0];
context->animation->bg_green = rgb[1];
context->animation->bg_blue = rgb[2];
}
context->global_colormap_size ++;
}
return 0;
}
static gint
gif_get_colormap2 (GifContext *context)
{
unsigned char rgb[3];
while (context->frame_colormap_size < context->frame_bit_pixel) {
if (!gif_read (context, rgb, sizeof (rgb))) {
return -1;
}
context->frame_color_map[0][context->frame_colormap_size] = rgb[0];
context->frame_color_map[1][context->frame_colormap_size] = rgb[1];
context->frame_color_map[2][context->frame_colormap_size] = rgb[2];
context->frame_colormap_size ++;
} }
return 0; return 0;
@ -348,9 +381,11 @@ gif_get_extension (GifContext *context)
retval = get_data_block (context, (unsigned char *) context->block_buf, NULL); retval = get_data_block (context, (unsigned char *) context->block_buf, NULL);
if (retval != 0) if (retval != 0)
return retval; return retval;
if (context->pixbuf == NULL) {
if (context->frame == NULL) {
/* I only want to set the transparency if I haven't /* 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.disposal = (context->block_buf[0] >> 2) & 0x7;
context->gif89.input_flag = (context->block_buf[0] >> 1) & 0x1; 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]); 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) gif_fill_in_pixels (GifContext *context, guchar *dest, gint offset, guchar v)
{ {
guchar *pixel = NULL; 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) { if (context->gif89.transparent != -1) {
pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 4; pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 4;
*pixel = context->color_map [0][(guchar) v]; *pixel = cmap [0][(guchar) v];
*(pixel+1) = context->color_map [1][(guchar) v]; *(pixel+1) = cmap [1][(guchar) v];
*(pixel+2) = context->color_map [2][(guchar) v]; *(pixel+2) = cmap [2][(guchar) v];
*(pixel+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 65535); *(pixel+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 255);
} else { } else {
pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 3; pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 3;
*pixel = context->color_map [0][(guchar) v]; *pixel = cmap [0][(guchar) v];
*(pixel+1) = context->color_map [1][(guchar) v]; *(pixel+1) = cmap [1][(guchar) v];
*(pixel+2) = context->color_map [2][(guchar) v]; *(pixel+2) = cmap [2][(guchar) v];
} }
} }
@ -682,20 +723,28 @@ gif_get_lzw (GifContext *context)
gint first_pass; /* bounds for emitting the area_updated signal */ gint first_pass; /* bounds for emitting the area_updated signal */
gint v; gint v;
if (context->pixbuf == NULL) { if (context->frame == NULL) {
context->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, context->frame = g_new (GdkPixbufFrame, 1);
context->gif89.transparent != -1,
context->frame->composited = NULL;
context->frame->revert = NULL;
context->frame->pixbuf =
gdk_pixbuf_new (GDK_COLORSPACE_RGB,
TRUE,
8, 8,
context->frame_len, context->frame_len,
context->frame_height); 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->x_offset = context->x_offset;
context->frame->y_offset = context->y_offset;; context->frame->y_offset = context->y_offset;
context->frame->delay_time = context->gif89.delay_time; 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) { switch (context->gif89.disposal) {
case 0: case 0:
case 1: case 1:
@ -711,45 +760,80 @@ gif_get_lzw (GifContext *context)
context->frame->action = GDK_PIXBUF_FRAME_RETAIN; context->frame->action = GDK_PIXBUF_FRAME_RETAIN;
break; break;
} }
context->frame->pixbuf = context->pixbuf;
if (context->animation) { context->frame->bg_transparent = (context->gif89.transparent == context->background_index);
{
/* Update animation size */
int w, h; int w, h;
context->animation->n_frames ++; context->animation->n_frames ++;
context->animation->frames = g_list_append (context->animation->frames, context->frame); context->animation->frames = g_list_append (context->animation->frames, context->frame);
w = gdk_pixbuf_get_width (context->pixbuf);
h = gdk_pixbuf_get_height (context->pixbuf); w = context->frame->x_offset +
gdk_pixbuf_get_width (context->frame->pixbuf);
h = context->frame->y_offset +
gdk_pixbuf_get_height (context->frame->pixbuf);
if (w > context->animation->width) if (w > context->animation->width)
context->animation->width = w; context->animation->width = w;
if (h > context->animation->height) if (h > context->animation->height)
context->animation->height = h; context->animation->height = h;
} }
/* Only call prepare_func for the first frame */
if (context->animation->frames->next == NULL) {
if (context->prepare_func)
(* context->prepare_func) (context->frame->pixbuf,
GDK_PIXBUF_ANIMATION (context->animation),
context->user_data);
} else {
/* Otherwise init frame with last frame */
GList *link;
GdkPixbufFrame *prev_frame;
link = g_list_find (context->animation->frames, context->frame);
prev_frame = link->prev->data;
gdk_pixbuf_gif_anim_frame_composite (context->animation, prev_frame);
gdk_pixbuf_copy_area (prev_frame->composited,
context->frame->x_offset,
context->frame->y_offset,
gdk_pixbuf_get_width (context->frame->pixbuf),
gdk_pixbuf_get_height (context->frame->pixbuf),
context->frame->pixbuf,
0, 0);
} }
} }
dest = gdk_pixbuf_get_pixels (context->pixbuf);
dest = gdk_pixbuf_get_pixels (context->frame->pixbuf);
bound_flag = FALSE; bound_flag = FALSE;
lower_bound = upper_bound = context->draw_ypos; lower_bound = upper_bound = context->draw_ypos;
first_pass = context->draw_pass; first_pass = context->draw_pass;
while (TRUE) { 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); v = lzw_read_byte (context);
if (v < 0) { if (v < 0) {
goto finished_data; goto finished_data;
} }
bound_flag = TRUE; bound_flag = TRUE;
if (context->gif89.transparent != -1) { g_assert (gdk_pixbuf_get_has_alpha (context->frame->pixbuf));
temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->pixbuf) + context->draw_xpos * 4;
*temp = context->color_map [0][(guchar) v]; temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 4;
*(temp+1) = context->color_map [1][(guchar) v]; *temp = cmap [0][(guchar) v];
*(temp+2) = context->color_map [2][(guchar) v]; *(temp+1) = cmap [1][(guchar) v];
*(temp+3) = (guchar) ((v == context->gif89.transparent) ? 0 : -1); *(temp+2) = cmap [2][(guchar) v];
} else { *(temp+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 255);
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];
}
if (context->prepare_func && context->frame_interlace) if (context->prepare_func && context->frame_interlace)
gif_fill_in_lines (context, dest, v); gif_fill_in_lines (context, dest, v);
@ -804,56 +888,60 @@ gif_get_lzw (GifContext *context)
if (context->draw_ypos >= context->frame_height) if (context->draw_ypos >= context->frame_height)
break; break;
} }
done: 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; context->state = GIF_GET_NEXT_STEP;
} else
context->state = GIF_DONE;
v = 0; v = 0;
finished_data: finished_data:
if (bound_flag)
context->frame->need_recomposite = TRUE;
if (bound_flag && context->update_func) { if (bound_flag && context->update_func) {
if (lower_bound <= upper_bound && first_pass == context->draw_pass) { if (lower_bound <= upper_bound && first_pass == context->draw_pass) {
(* context->update_func) (* context->update_func)
(context->pixbuf, (context->frame->pixbuf,
0, lower_bound, 0, lower_bound,
gdk_pixbuf_get_width (context->pixbuf), gdk_pixbuf_get_width (context->frame->pixbuf),
upper_bound - lower_bound, upper_bound - lower_bound,
context->user_data); context->user_data);
} else { } else {
if (lower_bound <= upper_bound) { if (lower_bound <= upper_bound) {
(* context->update_func) (* context->update_func)
(context->pixbuf, (context->frame->pixbuf,
0, 0, context->frame->x_offset,
gdk_pixbuf_get_width (context->pixbuf), context->frame->y_offset,
gdk_pixbuf_get_height (context->pixbuf), gdk_pixbuf_get_width (context->frame->pixbuf),
gdk_pixbuf_get_height (context->frame->pixbuf),
context->user_data); context->user_data);
} else { } else {
(* context->update_func) (* context->update_func)
(context->pixbuf, (context->frame->pixbuf,
0, 0, context->frame->x_offset,
gdk_pixbuf_get_width (context->pixbuf), context->frame->y_offset,
gdk_pixbuf_get_width (context->frame->pixbuf),
upper_bound, upper_bound,
context->user_data); context->user_data);
(* context->update_func) (* context->update_func)
(context->pixbuf, (context->frame->pixbuf,
0, lower_bound, context->frame->x_offset,
gdk_pixbuf_get_width (context->pixbuf), lower_bound + context->frame->y_offset,
gdk_pixbuf_get_height (context->pixbuf), gdk_pixbuf_get_width (context->frame->pixbuf),
gdk_pixbuf_get_height (context->frame->pixbuf),
context->user_data); context->user_data);
} }
} }
} }
if ((context->animation || context->frame_done_func || context->anim_done_func) if (context->state == GIF_GET_NEXT_STEP) {
&& context->state == GIF_GET_NEXT_STEP) { /* Will be freed with context->animation, we are just
if (context->frame_done_func) * marking that we're done with it (no current frame)
(* context->frame_done_func) (context->frame, */
context->user_data);
if (context->frame_done_func)
gdk_pixbuf_unref (context->pixbuf);
context->pixbuf = NULL;
context->frame = NULL; context->frame = NULL;
context->frame_cmap_active = FALSE;
} }
return v; return v;
@ -943,16 +1031,36 @@ gif_init (GifContext *context)
context->width = LM_to_uint (buf[0], buf[1]); context->width = LM_to_uint (buf[0], buf[1]);
context->height = LM_to_uint (buf[2], buf[3]); context->height = LM_to_uint (buf[2], buf[3]);
context->bit_pixel = 2 << (buf[4] & 0x07); /* The 4th byte is
context->color_resolution = (((buf[4] & 0x70) >> 3) + 1); * high bit: whether to use the background index
context->background = buf[5]; * 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]; 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); gif_set_get_colormap (context);
} else { } else {
context->state = GIF_GET_NEXT_STEP; 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; return 0;
} }
@ -966,38 +1074,81 @@ static gint
gif_get_frame_info (GifContext *context) gif_get_frame_info (GifContext *context)
{ {
unsigned char buf[9]; unsigned char buf[9];
if (!gif_read (context, buf, 9)) { if (!gif_read (context, buf, 9)) {
return -1; return -1;
} }
/* Okay, we got all the info we need. Lets record it */ /* Okay, we got all the info we need. Lets record it */
context->frame_len = LM_to_uint (buf[4], buf[5]); context->frame_len = LM_to_uint (buf[4], buf[5]);
context->frame_height = LM_to_uint (buf[6], buf[7]); context->frame_height = LM_to_uint (buf[6], buf[7]);
context->x_offset = LM_to_uint (buf[0], buf[1]); context->x_offset = LM_to_uint (buf[0], buf[1]);
context->y_offset = LM_to_uint (buf[2], buf[3]); context->y_offset = LM_to_uint (buf[2], buf[3]);
if (context->frame_height > context->height) { if (((context->frame_height + context->y_offset) > context->height) ||
/* we don't want to resize things. So we exit */ ((context->frame_len + context->x_offset) > context->width)) {
/* All frames must fit in the image bounds */
context->state = GIF_DONE; context->state = GIF_DONE;
g_set_error (context->error, g_set_error (context->error,
GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE, GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("GIF animation contained a frame with an incorrect size")); _("GIF image contained a frame appearing outside the image bounds."));
return -2; return -2;
} }
if (context->animation->frames == NULL &&
context->gif89.disposal == 3) {
/* First frame can't have "revert to previous" as its
* dispose mode.
*/
context->state = GIF_DONE;
g_set_error (context->error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("First frame of GIF image had 'revert to previous' as its disposal mode."));
return -2;
}
#ifdef DUMP_IMAGE_DETAILS
g_print (">width: %d height: %d xoffset: %d yoffset: %d disposal: %d delay: %d transparent: %d\n",
context->frame_len, context->frame_height, context->x_offset, context->y_offset,
context->gif89.disposal, context->gif89.delay_time, context->gif89.transparent);
#endif
context->frame_interlace = BitSet (buf[8], INTERLACE); context->frame_interlace = BitSet (buf[8], INTERLACE);
if (BitSet (buf[8], LOCALCOLORMAP)) { if (BitSet (buf[8], LOCALCOLORMAP)) {
#ifdef DUMP_IMAGE_DETAILS
g_print (">has local colormap\n");
#endif
/* Does this frame have it's own colormap. */ /* Does this frame have it's own colormap. */
/* really only relevant when looking at the first frame /* really only relevant when looking at the first frame
* of an animated gif. */ * of an animated gif. */
/* if it does, we need to re-read in the colormap, /* if it does, we need to re-read in the colormap,
* the gray_scale, and the bit_pixel */ * 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); gif_set_get_colormap2 (context);
return 0; 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); gif_set_prepare_lzw (context);
return 0; return 0;
@ -1037,6 +1188,8 @@ gif_get_next_step (GifContext *context)
} }
#define LOG(x)
static gint static gint
gif_main_loop (GifContext *context) gif_main_loop (GifContext *context)
{ {
@ -1045,52 +1198,63 @@ gif_main_loop (GifContext *context)
do { do {
switch (context->state) { switch (context->state) {
case GIF_START: case GIF_START:
LOG("start\n");
retval = gif_init (context); retval = gif_init (context);
break; break;
case GIF_GET_COLORMAP: case GIF_GET_COLORMAP:
LOG("get_colormap\n");
retval = gif_get_colormap (context); retval = gif_get_colormap (context);
if (retval == 0) if (retval == 0)
context->state = GIF_GET_NEXT_STEP; context->state = GIF_GET_NEXT_STEP;
break; break;
case GIF_GET_NEXT_STEP: case GIF_GET_NEXT_STEP:
LOG("next_step\n");
retval = gif_get_next_step (context); retval = gif_get_next_step (context);
break; break;
case GIF_GET_FRAME_INFO: case GIF_GET_FRAME_INFO:
LOG("frame_info\n");
retval = gif_get_frame_info (context); retval = gif_get_frame_info (context);
break; break;
case GIF_GET_EXTENTION: case GIF_GET_EXTENTION:
LOG("get_extension\n");
retval = gif_get_extension (context); retval = gif_get_extension (context);
if (retval == 0) if (retval == 0)
context->state = GIF_GET_NEXT_STEP; context->state = GIF_GET_NEXT_STEP;
break; break;
case GIF_GET_COLORMAP2: case GIF_GET_COLORMAP2:
retval = gif_get_colormap (context); LOG("get_colormap2\n");
retval = gif_get_colormap2 (context);
if (retval == 0) if (retval == 0)
gif_set_prepare_lzw (context); gif_set_prepare_lzw (context);
break; break;
case GIF_PREPARE_LZW: case GIF_PREPARE_LZW:
LOG("prepare_lzw\n");
retval = gif_prepare_lzw (context); retval = gif_prepare_lzw (context);
break; break;
case GIF_LZW_FILL_BUFFER: case GIF_LZW_FILL_BUFFER:
LOG("fill_buffer\n");
retval = gif_lzw_fill_buffer (context); retval = gif_lzw_fill_buffer (context);
break; break;
case GIF_LZW_CLEAR_CODE: case GIF_LZW_CLEAR_CODE:
LOG("clear_code\n");
retval = gif_lzw_clear_code (context); retval = gif_lzw_clear_code (context);
break; break;
case GIF_GET_LZW: case GIF_GET_LZW:
LOG("get_lzw\n");
retval = gif_get_lzw (context); retval = gif_get_lzw (context);
break; break;
case GIF_DONE: case GIF_DONE:
LOG("done\n");
default: default:
retval = 0; retval = 0;
goto done; goto done;
@ -1107,13 +1271,12 @@ new_context (void)
context = g_new0 (GifContext, 1); 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->file = NULL;
context->state = GIF_START; context->state = GIF_START;
context->prepare_func = NULL; context->prepare_func = NULL;
context->update_func = NULL; context->update_func = NULL;
context->frame_done_func = NULL;
context->anim_done_func = NULL;
context->user_data = NULL; context->user_data = NULL;
context->buf = NULL; context->buf = NULL;
context->amount_needed = 0; context->amount_needed = 0;
@ -1137,9 +1300,22 @@ gdk_pixbuf__gif_image_load (FILE *file, GError **error)
context->file = file; context->file = file;
context->error = error; context->error = error;
gif_main_loop (context); if (gif_main_loop (context) == -1 || context->animation->frames == NULL) {
if (context->error && *(context->error) == NULL)
g_set_error (context->error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("GIF file was missing some data (perhaps it was truncated somehow?)"));
}
pixbuf = context->pixbuf; pixbuf = gdk_pixbuf_animation_get_static_image (GDK_PIXBUF_ANIMATION (context->animation));
if (pixbuf)
g_object_ref (G_OBJECT (pixbuf));
g_object_unref (G_OBJECT (context->animation));
g_free (context->buf);
g_free (context); g_free (context);
return pixbuf; return pixbuf;
@ -1148,8 +1324,6 @@ gdk_pixbuf__gif_image_load (FILE *file, GError **error)
static gpointer static gpointer
gdk_pixbuf__gif_image_begin_load (ModulePreparedNotifyFunc prepare_func, gdk_pixbuf__gif_image_begin_load (ModulePreparedNotifyFunc prepare_func,
ModuleUpdatedNotifyFunc update_func, ModuleUpdatedNotifyFunc update_func,
ModuleFrameDoneNotifyFunc frame_done_func,
ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data, gpointer user_data,
GError **error) GError **error)
{ {
@ -1162,8 +1336,6 @@ gdk_pixbuf__gif_image_begin_load (ModulePreparedNotifyFunc prepare_func,
context->error = error; context->error = error;
context->prepare_func = prepare_func; context->prepare_func = prepare_func;
context->update_func = update_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; context->user_data = user_data;
return (gpointer) context; return (gpointer) context;
@ -1173,21 +1345,23 @@ static gboolean
gdk_pixbuf__gif_image_stop_load (gpointer data, GError **error) gdk_pixbuf__gif_image_stop_load (gpointer data, GError **error)
{ {
GifContext *context = (GifContext *) data; GifContext *context = (GifContext *) data;
gboolean retval = TRUE;
/* FIXME: free the animation data */ if (context->state != GIF_DONE) {
g_set_error (error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
_("GIF image was truncated or incomplete."));
/* FIXME this thing needs to report errors if retval = FALSE;
* we have unused image data }
*/
if (context->pixbuf) g_object_unref (G_OBJECT (context->animation));
gdk_pixbuf_unref (context->pixbuf);
if (context->animation) g_free (context->buf);
gdk_pixbuf_animation_unref (context->animation);
/* g_free (context->buf);*/
g_free (context); g_free (context);
return TRUE; return retval;
} }
static gboolean static gboolean
@ -1264,18 +1438,28 @@ gdk_pixbuf__gif_image_load_animation (FILE *file,
context = new_context (); context = new_context ();
context->error = error; 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; 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); g_free (context);
return animation; return animation;
} }

View File

@ -156,8 +156,6 @@ struct ico_progressive_state {
static gpointer static gpointer
gdk_pixbuf__ico_image_begin_load(ModulePreparedNotifyFunc prepared_func, gdk_pixbuf__ico_image_begin_load(ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func, ModuleUpdatedNotifyFunc updated_func,
ModuleFrameDoneNotifyFunc frame_done_func,
ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data, gpointer user_data,
GError **error); GError **error);
static gboolean gdk_pixbuf__ico_image_stop_load(gpointer 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; GdkPixbuf *pb;
State = gdk_pixbuf__ico_image_begin_load(NULL, NULL, NULL, State = gdk_pixbuf__ico_image_begin_load(NULL, NULL, NULL, error);
NULL, NULL, error);
if (State == NULL) if (State == NULL)
return NULL; return NULL;
@ -363,6 +361,7 @@ static void DecodeHeader(guchar *Data, gint Bytes,
if (State->prepared_func != NULL) if (State->prepared_func != NULL)
/* Notify the client that we are ready to go */ /* Notify the client that we are ready to go */
(*State->prepared_func) (State->pixbuf, (*State->prepared_func) (State->pixbuf,
NULL,
State->user_data); State->user_data);
} }
@ -378,8 +377,6 @@ static void DecodeHeader(guchar *Data, gint Bytes,
static gpointer static gpointer
gdk_pixbuf__ico_image_begin_load(ModulePreparedNotifyFunc prepared_func, gdk_pixbuf__ico_image_begin_load(ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func, ModuleUpdatedNotifyFunc updated_func,
ModuleFrameDoneNotifyFunc frame_done_func,
ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data, gpointer user_data,
GError **error) GError **error)
{ {

View File

@ -96,8 +96,6 @@ typedef struct {
static GdkPixbuf *gdk_pixbuf__jpeg_image_load (FILE *f, GError **error); static GdkPixbuf *gdk_pixbuf__jpeg_image_load (FILE *f, GError **error);
static gpointer gdk_pixbuf__jpeg_image_begin_load (ModulePreparedNotifyFunc func, static gpointer gdk_pixbuf__jpeg_image_begin_load (ModulePreparedNotifyFunc func,
ModuleUpdatedNotifyFunc func2, ModuleUpdatedNotifyFunc func2,
ModuleFrameDoneNotifyFunc func3,
ModuleAnimationDoneNotifyFunc func4,
gpointer user_data, gpointer user_data,
GError **error); GError **error);
static gboolean gdk_pixbuf__jpeg_image_stop_load (gpointer context, 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 gpointer
gdk_pixbuf__jpeg_image_begin_load (ModulePreparedNotifyFunc prepared_func, gdk_pixbuf__jpeg_image_begin_load (ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func, ModuleUpdatedNotifyFunc updated_func,
ModuleFrameDoneNotifyFunc frame_func,
ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data, gpointer user_data,
GError **error) GError **error)
{ {
@ -539,6 +535,7 @@ gdk_pixbuf__jpeg_image_load_increment (gpointer data,
/* Notify the client that we are ready to go */ /* Notify the client that we are ready to go */
(* context->prepared_func) (context->pixbuf, (* context->prepared_func) (context->pixbuf,
NULL,
context->user_data); context->user_data);
} else if (!context->did_prescan) { } else if (!context->did_prescan) {

View File

@ -324,8 +324,6 @@ struct _LoadContext {
static gpointer static gpointer
gdk_pixbuf__png_image_begin_load (ModulePreparedNotifyFunc prepare_func, gdk_pixbuf__png_image_begin_load (ModulePreparedNotifyFunc prepare_func,
ModuleUpdatedNotifyFunc update_func, ModuleUpdatedNotifyFunc update_func,
ModuleFrameDoneNotifyFunc frame_done_func,
ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data, gpointer user_data,
GError **error) GError **error)
{ {
@ -540,7 +538,7 @@ png_info_callback (png_structp png_read_ptr,
/* Notify the client that we are ready to go */ /* Notify the client that we are ready to go */
if (lc->prepare_func) if (lc->prepare_func)
(* lc->prepare_func) (lc->pixbuf, lc->notify_user_data); (* lc->prepare_func) (lc->pixbuf, NULL, lc->notify_user_data);
return; return;
} }

View File

@ -84,8 +84,6 @@ typedef struct {
static GdkPixbuf *gdk_pixbuf__pnm_image_load (FILE *f, GError **error); static GdkPixbuf *gdk_pixbuf__pnm_image_load (FILE *f, GError **error);
static gpointer gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc func, static gpointer gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc func,
ModuleUpdatedNotifyFunc func2, ModuleUpdatedNotifyFunc func2,
ModuleFrameDoneNotifyFunc frame_done_func,
ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data, gpointer user_data,
GError **error); GError **error);
static gboolean gdk_pixbuf__pnm_image_stop_load (gpointer context, 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 static gpointer
gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc prepared_func, gdk_pixbuf__pnm_image_begin_load (ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func, ModuleUpdatedNotifyFunc updated_func,
ModuleFrameDoneNotifyFunc frame_done_func,
ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data, gpointer user_data,
GError **error) GError **error)
{ {
@ -923,6 +919,7 @@ gdk_pixbuf__pnm_image_load_increment (gpointer data,
/* Notify the client that we are ready to go */ /* Notify the client that we are ready to go */
(* context->prepared_func) (context->pixbuf, (* context->prepared_func) (context->pixbuf,
NULL,
context->user_data); context->user_data);
} }

View File

@ -96,8 +96,6 @@ struct ras_progressive_state {
static gpointer static gpointer
gdk_pixbuf__ras_image_begin_load(ModulePreparedNotifyFunc prepared_func, gdk_pixbuf__ras_image_begin_load(ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func, ModuleUpdatedNotifyFunc updated_func,
ModuleFrameDoneNotifyFunc frame_done_func,
ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data, gpointer user_data,
GError **error); GError **error);
static gboolean gdk_pixbuf__ras_image_stop_load(gpointer 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; GdkPixbuf *pb;
State = gdk_pixbuf__ras_image_begin_load(NULL, NULL, NULL, State = gdk_pixbuf__ras_image_begin_load(NULL, NULL, NULL, error);
NULL, NULL, error);
membuf = g_malloc(4096); membuf = g_malloc(4096);
@ -195,6 +192,7 @@ static void RAS2State(struct rasterfile *RAS,
if (State->prepared_func != NULL) if (State->prepared_func != NULL)
/* Notify the client that we are ready to go */ /* Notify the client that we are ready to go */
(*State->prepared_func) (State->pixbuf, (*State->prepared_func) (State->pixbuf,
NULL,
State->user_data); State->user_data);
} }
@ -219,8 +217,6 @@ static void RAS2State(struct rasterfile *RAS,
static gpointer static gpointer
gdk_pixbuf__ras_image_begin_load(ModulePreparedNotifyFunc prepared_func, gdk_pixbuf__ras_image_begin_load(ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func, ModuleUpdatedNotifyFunc updated_func,
ModuleFrameDoneNotifyFunc frame_done_func,
ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data, gpointer user_data,
GError **error) GError **error)
{ {

View File

@ -92,7 +92,7 @@ gdk_pixbuf__tiff_image_load_real (FILE *f, TiffData *context, GError **error)
} }
if (context) if (context)
(* context->prepare_func) (pixbuf, context->user_data); (* context->prepare_func) (pixbuf, NULL, context->user_data);
/* Yes, it needs to be _TIFFMalloc... */ /* Yes, it needs to be _TIFFMalloc... */
rast = (uint32 *) _TIFFmalloc (num_pixs * sizeof (uint32)); rast = (uint32 *) _TIFFmalloc (num_pixs * sizeof (uint32));
@ -163,8 +163,6 @@ gdk_pixbuf__tiff_image_load (FILE *f, GError **error)
static gpointer static gpointer
gdk_pixbuf__tiff_image_begin_load (ModulePreparedNotifyFunc prepare_func, gdk_pixbuf__tiff_image_begin_load (ModulePreparedNotifyFunc prepare_func,
ModuleUpdatedNotifyFunc update_func, ModuleUpdatedNotifyFunc update_func,
ModuleFrameDoneNotifyFunc frame_done_func,
ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data, gpointer user_data,
GError **error) GError **error)
{ {

View File

@ -65,9 +65,7 @@ struct wbmp_progressive_state {
static gpointer static gpointer
gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func, gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func, ModuleUpdatedNotifyFunc updated_func,
ModuleFrameDoneNotifyFunc frame_done_func, gpointer user_data,
ModuleAnimationDoneNotifyFunc
anim_done_func, gpointer user_data,
GError **error); GError **error);
static gboolean gdk_pixbuf__wbmp_image_stop_load(gpointer 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; 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); error);
if (State == NULL) if (State == NULL)
@ -120,9 +118,7 @@ static GdkPixbuf *gdk_pixbuf__wbmp_image_load(FILE * f, GError **error)
static gpointer static gpointer
gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func, gdk_pixbuf__wbmp_image_begin_load(ModulePreparedNotifyFunc prepared_func,
ModuleUpdatedNotifyFunc updated_func, ModuleUpdatedNotifyFunc updated_func,
ModuleFrameDoneNotifyFunc frame_done_func, gpointer user_data,
ModuleAnimationDoneNotifyFunc
anim_done_func, gpointer user_data,
GError **error) GError **error)
{ {
struct wbmp_progressive_state *context; struct wbmp_progressive_state *context;
@ -285,7 +281,7 @@ static gboolean gdk_pixbuf__wbmp_image_load_increment(gpointer data,
g_assert(context->pixbuf); g_assert(context->pixbuf);
if(context->prepared_func) 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) else if(context->needmore)

View File

@ -300,7 +300,7 @@ gdk_pixbuf__xbm_image_load_real (FILE *f, XBMData *context, GError **error)
row_stride = gdk_pixbuf_get_rowstride (pixbuf); row_stride = gdk_pixbuf_get_rowstride (pixbuf);
if (context) if (context)
(* context->prepare_func) (pixbuf, context->user_data); (* context->prepare_func) (pixbuf, NULL, context->user_data);
/* Initialize PIXBUF */ /* Initialize PIXBUF */
@ -355,8 +355,6 @@ gdk_pixbuf__xbm_image_load (FILE *f, GError **error)
static gpointer static gpointer
gdk_pixbuf__xbm_image_begin_load (ModulePreparedNotifyFunc prepare_func, gdk_pixbuf__xbm_image_begin_load (ModulePreparedNotifyFunc prepare_func,
ModuleUpdatedNotifyFunc update_func, ModuleUpdatedNotifyFunc update_func,
ModuleFrameDoneNotifyFunc frame_done_func,
ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data, gpointer user_data,
GError **error) GError **error)
{ {

View File

@ -1424,8 +1424,6 @@ struct _XPMContext
static gpointer static gpointer
gdk_pixbuf__xpm_image_begin_load (ModulePreparedNotifyFunc prepare_func, gdk_pixbuf__xpm_image_begin_load (ModulePreparedNotifyFunc prepare_func,
ModuleUpdatedNotifyFunc update_func, ModuleUpdatedNotifyFunc update_func,
ModuleFrameDoneNotifyFunc frame_done_func,
ModuleAnimationDoneNotifyFunc anim_done_func,
gpointer user_data, gpointer user_data,
GError **error) GError **error)
{ {
@ -1471,7 +1469,9 @@ gdk_pixbuf__xpm_image_stop_load (gpointer data,
pixbuf = gdk_pixbuf__xpm_image_load (context->file, error); pixbuf = gdk_pixbuf__xpm_image_load (context->file, error);
if (pixbuf != NULL) { 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); (* context->update_func) (pixbuf, 0, 0, pixbuf->width, pixbuf->height, context->user_data);
gdk_pixbuf_unref (pixbuf); gdk_pixbuf_unref (pixbuf);

View File

@ -1,4 +1,5 @@
#include <math.h> #include <math.h>
#include <glib.h>
#include "config.h" #include "config.h"
#include "pixops.h" #include "pixops.h"
@ -93,6 +94,7 @@ pixops_scale_nearest (guchar *dest_buf,
for (i = 0; i < (render_y1 - render_y0); i++) 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; 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; guchar *dest = dest_buf + i * dest_rowstride;
x = render_x0 * x_step + x_step / 2; 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++) 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; 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; guchar *dest = dest_buf + i * dest_rowstride;
x = render_x0 * x_step + x_step / 2; x = render_x0 * x_step + x_step / 2;
@ -183,9 +184,9 @@ pixops_composite_nearest (guchar *dest_buf,
if (w != 0) if (w != 0)
{ {
dest[0] = (w0 * src[0] + w1 * dest[0]) / w; dest[0] = (w0 * p[0] + w1 * dest[0]) / w;
dest[1] = (w0 * src[1] + w1 * dest[1]) / w; dest[1] = (w0 * p[1] + w1 * dest[1]) / w;
dest[2] = (w0 * src[2] + w1 * dest[2]) / w; dest[2] = (w0 * p[2] + w1 * dest[2]) / w;
dest[3] = w / 0xff; dest[3] = w / 0xff;
} }
else else
@ -274,24 +275,38 @@ pixops_composite_color_nearest (guchar *dest_buf,
for (j=0 ; j < (render_x1 - render_x0); j++) for (j=0 ; j < (render_x1 - render_x0); j++)
{ {
const guchar *p = src + (x >> SCALE_SHIFT) * src_channels; const guchar *p = src + (x >> SCALE_SHIFT) * src_channels;
unsigned int a0; int a0;
int tmp;
if (src_has_alpha) if (src_has_alpha)
a0 = (p[3] * overall_alpha + 0xff) >> 8; a0 = (p[3] * overall_alpha + 0xff) >> 8;
else else
a0 = overall_alpha; a0 = overall_alpha;
if (a0 == 255)
{
dest[0] = p[0];
dest[1] = p[1];
dest[2] = p[2];
}
else
if (((j + check_x) >> check_shift) & 1) if (((j + check_x) >> check_shift) & 1)
{ {
dest[0] = r2 + ((a0 * ((int)p[0] - r2) + 0xff) >> 8); tmp = ((int) p[0] - r2) * a0;
dest[1] = g2 + ((a0 * ((int)p[1] - g2) + 0xff) >> 8); dest[0] = r2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
dest[2] = b2 + ((a0 * ((int)p[2] - b2) + 0xff) >> 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 else
{ {
dest[0] = r1 + ((a0 * ((int)p[0] - r1) + 0xff) >> 8); tmp = ((int) p[0] - r1) * a0;
dest[1] = g1 + ((a0 * ((int)p[1] - g1) + 0xff) >> 8); dest[0] = r1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
dest[2] = b1 + ((a0 * ((int)p[2] - b1) + 0xff) >> 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) if (dest_channels == 4)
@ -1003,7 +1018,7 @@ pixops_process (guchar *dest_buf,
dest_x += (new_outbuf - outbuf) / dest_channels; 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; outbuf = new_outbuf;
while (outbuf < outbuf_end) while (outbuf < outbuf_end)

View File

@ -70,6 +70,7 @@ enum {
PROP_STRETCH, PROP_STRETCH,
PROP_SIZE, PROP_SIZE,
PROP_SIZE_POINTS, PROP_SIZE_POINTS,
PROP_SCALE,
PROP_EDITABLE, PROP_EDITABLE,
PROP_STRIKETHROUGH, PROP_STRIKETHROUGH,
PROP_UNDERLINE, PROP_UNDERLINE,
@ -84,6 +85,7 @@ enum {
PROP_WEIGHT_SET, PROP_WEIGHT_SET,
PROP_STRETCH_SET, PROP_STRETCH_SET,
PROP_SIZE_SET, PROP_SIZE_SET,
PROP_SCALE_SET,
PROP_EDITABLE_SET, PROP_EDITABLE_SET,
PROP_STRIKETHROUGH_SET, PROP_STRIKETHROUGH_SET,
PROP_UNDERLINE_SET, PROP_UNDERLINE_SET,
@ -283,6 +285,16 @@ gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class)
0.0, 0.0,
G_PARAM_READABLE | G_PARAM_WRITABLE)); 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, g_object_class_install_property (object_class,
PROP_RISE, PROP_RISE,
g_param_spec_int ("rise", g_param_spec_int ("rise",
@ -351,6 +363,10 @@ gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class)
_("Font size set"), _("Font size set"),
_("Whether this tag affects the font size")); _("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, ADD_SET_PROP ("rise_set", PROP_RISE_SET,
_("Rise set"), _("Rise set"),
_("Whether this tag affects the rise")); _("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); g_value_set_double (value, ((double)celltext->font.size) / (double)PANGO_SCALE);
break; break;
case PROP_SCALE:
g_value_set_double (value, celltext->font_scale);
break;
case PROP_EDITABLE: case PROP_EDITABLE:
g_value_set_boolean (value, celltext->editable); g_value_set_boolean (value, celltext->editable);
break; break;
@ -510,6 +530,10 @@ gtk_cell_renderer_text_get_property (GObject *object,
g_value_set_boolean (value, celltext->size_set); g_value_set_boolean (value, celltext->size_set);
break; break;
case PROP_SCALE_SET:
g_value_set_boolean (value, celltext->scale_set);
break;
case PROP_EDITABLE_SET: case PROP_EDITABLE_SET:
g_value_set_boolean (value, celltext->editable_set); g_value_set_boolean (value, celltext->editable_set);
break; break;
@ -824,6 +848,11 @@ gtk_cell_renderer_text_set_property (GObject *object,
g_object_notify (G_OBJECT (celltext), "font"); g_object_notify (G_OBJECT (celltext), "font");
break; break;
case PROP_SCALE:
celltext->font_scale = g_value_get_double (value);
celltext->scale_set = TRUE;
break;
case PROP_SIZE_POINTS: case PROP_SIZE_POINTS:
celltext->font.size = g_value_get_double (value) * PANGO_SCALE; 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_style = g_value_get_enum (value);
celltext->underline_set = TRUE; celltext->underline_set = TRUE;
g_object_notify (G_OBJECT (celltext), "underline_set"); g_object_notify (G_OBJECT (celltext), "underline_set");
break; break;
case PROP_RISE: case PROP_RISE:
@ -859,62 +889,54 @@ gtk_cell_renderer_text_set_property (GObject *object,
case PROP_BACKGROUND_SET: case PROP_BACKGROUND_SET:
celltext->background_set = g_value_get_boolean (value); celltext->background_set = g_value_get_boolean (value);
g_object_notify(G_OBJECT(object), "background_set");
break; break;
case PROP_FOREGROUND_SET: case PROP_FOREGROUND_SET:
celltext->foreground_set = g_value_get_boolean (value); celltext->foreground_set = g_value_get_boolean (value);
g_object_notify(G_OBJECT(object), "foreground_set");
break; break;
case PROP_FAMILY_SET: case PROP_FAMILY_SET:
celltext->family_set = g_value_get_boolean (value); celltext->family_set = g_value_get_boolean (value);
g_object_notify(G_OBJECT(object), "family_set");
break; break;
case PROP_STYLE_SET: case PROP_STYLE_SET:
celltext->style_set = g_value_get_boolean (value); celltext->style_set = g_value_get_boolean (value);
g_object_notify(G_OBJECT(object), "style_set");
break; break;
case PROP_VARIANT_SET: case PROP_VARIANT_SET:
celltext->variant_set = g_value_get_boolean (value); celltext->variant_set = g_value_get_boolean (value);
g_object_notify(G_OBJECT(object), "variant_set");
break; break;
case PROP_WEIGHT_SET: case PROP_WEIGHT_SET:
celltext->weight_set = g_value_get_boolean (value); celltext->weight_set = g_value_get_boolean (value);
g_object_notify(G_OBJECT(object), "weight_set");
break; break;
case PROP_STRETCH_SET: case PROP_STRETCH_SET:
celltext->stretch_set = g_value_get_boolean (value); celltext->stretch_set = g_value_get_boolean (value);
g_object_notify(G_OBJECT(object), "stretch_set");
break; break;
case PROP_SIZE_SET: case PROP_SIZE_SET:
celltext->size_set = g_value_get_boolean (value); 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; break;
case PROP_EDITABLE_SET: case PROP_EDITABLE_SET:
celltext->editable_set = g_value_get_boolean (value); celltext->editable_set = g_value_get_boolean (value);
g_object_notify(G_OBJECT(object), "editable_set");
break; break;
case PROP_STRIKETHROUGH_SET: case PROP_STRIKETHROUGH_SET:
celltext->strikethrough_set = g_value_get_boolean (value); celltext->strikethrough_set = g_value_get_boolean (value);
g_object_notify(G_OBJECT(object), "strikethrough_set");
break; break;
case PROP_UNDERLINE_SET: case PROP_UNDERLINE_SET:
celltext->underline_set = g_value_get_boolean (value); celltext->underline_set = g_value_get_boolean (value);
g_object_notify(G_OBJECT(object), "underline_set");
break; break;
case PROP_RISE_SET: case PROP_RISE_SET:
celltext->rise_set = g_value_get_boolean (value); celltext->rise_set = g_value_get_boolean (value);
g_object_notify(G_OBJECT(object), "rise_set");
break; break;
default: default:
@ -1012,6 +1034,10 @@ get_layout (GtkCellRendererText *celltext,
celltext->font.size >= 0) celltext->font.size >= 0)
add_attr (attr_list, pango_attr_size_new (celltext->font.size)); 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) if (celltext->underline_set)
uline = celltext->underline_style; uline = celltext->underline_style;
else else

View File

@ -44,6 +44,7 @@ struct _GtkCellRendererText
/*< private >*/ /*< private >*/
gchar *text; gchar *text;
PangoFontDescription font; PangoFontDescription font;
gdouble font_scale;
PangoColor foreground; PangoColor foreground;
PangoColor background; PangoColor background;
@ -66,6 +67,8 @@ struct _GtkCellRendererText
guint stretch_set : 1; guint stretch_set : 1;
guint size_set : 1; guint size_set : 1;
guint scale_set : 1;
guint foreground_set : 1; guint foreground_set : 1;
guint background_set : 1; guint background_set : 1;

View File

@ -246,8 +246,8 @@ gtk_check_button_size_request (GtkWidget *widget,
gint indicator_spacing; gint indicator_spacing;
gint border_width = GTK_CONTAINER (widget)->border_width; gint border_width = GTK_CONTAINER (widget)->border_width;
requisition->width = border_width + 2; requisition->width = border_width * 2 + 2;
requisition->height = border_width + 2; requisition->height = border_width * 2 + 2;
child = GTK_BIN (widget)->child; child = GTK_BIN (widget)->child;
if (child && GTK_WIDGET_VISIBLE (child)) if (child && GTK_WIDGET_VISIBLE (child))

View File

@ -1848,7 +1848,7 @@ gtk_color_selection_destroy (GtkObject *object)
if (priv->tooltips) if (priv->tooltips)
{ {
gtk_object_destroy (priv->tooltips); gtk_object_destroy (GTK_OBJECT (priv->tooltips));
priv->tooltips = NULL; priv->tooltips = NULL;
} }

View File

@ -523,7 +523,6 @@ gtk_hscale_draw_value (GtkScale *scale)
{ {
GtkStateType state_type; GtkStateType state_type;
GtkWidget *widget; GtkWidget *widget;
gchar buffer[32];
gint width, height; gint width, height;
gint x, y; gint x, y;
@ -536,9 +535,14 @@ gtk_hscale_draw_value (GtkScale *scale)
{ {
PangoLayout *layout; PangoLayout *layout;
PangoRectangle logical_rect; 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); pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
switch (scale->value_pos) switch (scale->value_pos)

View File

@ -28,11 +28,13 @@
#include "gtkimage.h" #include "gtkimage.h"
#include "gtkiconfactory.h" #include "gtkiconfactory.h"
#include "gtkstock.h" #include "gtkstock.h"
#include <string.h>
static void gtk_image_class_init (GtkImageClass *klass); static void gtk_image_class_init (GtkImageClass *klass);
static void gtk_image_init (GtkImage *image); static void gtk_image_init (GtkImage *image);
static gint gtk_image_expose (GtkWidget *widget, static gint gtk_image_expose (GtkWidget *widget,
GdkEventExpose *event); GdkEventExpose *event);
static void gtk_image_unmap (GtkWidget *widget);
static void gtk_image_size_request (GtkWidget *widget, static void gtk_image_size_request (GtkWidget *widget,
GtkRequisition *requisition); GtkRequisition *requisition);
static void gtk_image_destroy (GtkObject *object); 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->expose_event = gtk_image_expose;
widget_class->size_request = gtk_image_size_request; widget_class->size_request = gtk_image_size_request;
widget_class->unmap = gtk_image_unmap;
} }
static void static void
@ -163,11 +166,22 @@ gtk_image_new_from_image (GdkImage *gdk_image,
* gtk_image_new_from_file: * gtk_image_new_from_file:
* @filename: a filename * @filename: a filename
* *
* Creates a new #GtkImage displaying the file @filename. If the * Creates a new #GtkImage displaying the file @filename. If the file
* file isn't found or can't be loaded, the #GtkImage will display * isn't found or can't be loaded, the resulting #GtkImage will
* a "broken image" icon. If you need to detect failures to load * display a "broken image" icon. This function never returns %NULL,
* the file, use gdk_pixbuf_new_from_file() to load the file yourself, * it always returns a valid #GtkImage widget.
* then create the #GtkImage from the pixbuf. *
* 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 * 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 * 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 * #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 * Return value: a new #GtkImage
**/ **/
@ -268,6 +282,31 @@ gtk_image_new_from_icon_set (GtkIconSet *icon_set,
return GTK_WIDGET (image); return GTK_WIDGET (image);
} }
/**
* gtk_image_new_from_animation:
* @animation: an animation
*
* Creates a #GtkImage displaying the given animation.
* The #GtkImage does not assume a reference to the
* animation; you still need to unref it if you own references.
* #GtkImage will add its own reference rather than adopting yours.
*
* Return value: a new #GtkImage widget
**/
GtkWidget*
gtk_image_new_from_animation (GdkPixbufAnimation *animation)
{
GtkImage *image;
g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
image = gtk_type_new (GTK_TYPE_IMAGE);
gtk_image_set_from_animation (image, animation);
return GTK_WIDGET (image);
}
/** /**
* gtk_image_set_from_pixmap: * gtk_image_set_from_pixmap:
* @image: a #GtkImage * @image: a #GtkImage
@ -376,7 +415,7 @@ void
gtk_image_set_from_file (GtkImage *image, gtk_image_set_from_file (GtkImage *image,
const gchar *filename) const gchar *filename)
{ {
GdkPixbuf *pixbuf; GdkPixbufAnimation *anim;
g_return_if_fail (GTK_IS_IMAGE (image)); g_return_if_fail (GTK_IS_IMAGE (image));
g_return_if_fail (filename != NULL); g_return_if_fail (filename != NULL);
@ -386,9 +425,9 @@ gtk_image_set_from_file (GtkImage *image,
if (filename == NULL) if (filename == NULL)
return; 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_image_set_from_stock (image,
GTK_STOCK_MISSING_IMAGE, GTK_STOCK_MISSING_IMAGE,
@ -396,9 +435,22 @@ gtk_image_set_from_file (GtkImage *image,
return; return;
} }
gtk_image_set_from_pixbuf (image, pixbuf); /* We could just unconditionally set_from_animation,
* but it's nicer for memory if we toss the animation
* if it's just a single pixbuf
*/
g_object_unref (G_OBJECT (pixbuf)); if (gdk_pixbuf_animation_is_static_image (anim))
{
gtk_image_set_from_pixbuf (image,
gdk_pixbuf_animation_get_static_image (anim));
}
else
{
gtk_image_set_from_animation (image, anim);
}
g_object_unref (G_OBJECT (anim));
} }
/** /**
@ -500,6 +552,41 @@ gtk_image_set_from_icon_set (GtkImage *image,
} }
} }
/**
* gtk_image_set_from_animation:
* @image: a #GtkImage
* @animation: the #GdkPixbufAnimation
*
* Causes the #GtkImage to display the given animation (or display
* nothing, if you set the animation to %NULL).
**/
void
gtk_image_set_from_animation (GtkImage *image,
GdkPixbufAnimation *animation)
{
g_return_if_fail (GTK_IS_IMAGE (image));
g_return_if_fail (animation == NULL ||
GDK_IS_PIXBUF_ANIMATION (animation));
if (animation)
g_object_ref (G_OBJECT (animation));
gtk_image_reset (image);
if (animation != NULL)
{
image->storage_type = GTK_IMAGE_ANIMATION;
image->data.anim.anim = animation;
image->data.anim.frame_timeout = 0;
image->data.anim.iter = NULL;
gtk_image_update_size (image,
gdk_pixbuf_animation_get_width (animation),
gdk_pixbuf_animation_get_height (animation));
}
}
/** /**
* gtk_image_get_storage_type: * gtk_image_get_storage_type:
* @image: a #GtkImage * @image: a #GtkImage
@ -660,6 +747,33 @@ gtk_image_get_icon_set (GtkImage *image,
*size = image->data.icon_set.size; *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* GtkWidget*
gtk_image_new (GdkImage *val, gtk_image_new (GdkImage *val,
GdkBitmap *mask) GdkBitmap *mask)
@ -695,6 +809,55 @@ gtk_image_get (GtkImage *image,
gtk_image_get_image (image, val, mask); 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 static gint
gtk_image_expose (GtkWidget *widget, gtk_image_expose (GtkWidget *widget,
@ -778,6 +941,24 @@ gtk_image_expose (GtkWidget *widget,
} }
break; 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: default:
break; break;
} }
@ -849,6 +1030,25 @@ gtk_image_expose (GtkWidget *widget,
} }
break; 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: default:
break; break;
} }
@ -876,9 +1076,6 @@ gtk_image_clear (GtkImage *image)
if (image->data.pixmap.mask) if (image->data.pixmap.mask)
g_object_unref (G_OBJECT (image->data.pixmap.mask)); g_object_unref (G_OBJECT (image->data.pixmap.mask));
image->data.pixmap.pixmap = NULL;
image->data.pixmap.mask = NULL;
break; break;
case GTK_IMAGE_IMAGE: case GTK_IMAGE_IMAGE:
@ -889,9 +1086,6 @@ gtk_image_clear (GtkImage *image)
if (image->data.image.mask) if (image->data.image.mask)
g_object_unref (G_OBJECT (image->data.image.mask)); g_object_unref (G_OBJECT (image->data.image.mask));
image->data.image.image = NULL;
image->data.image.mask = NULL;
break; break;
case GTK_IMAGE_PIXBUF: case GTK_IMAGE_PIXBUF:
@ -899,26 +1093,26 @@ gtk_image_clear (GtkImage *image)
if (image->data.pixbuf.pixbuf) if (image->data.pixbuf.pixbuf)
g_object_unref (G_OBJECT (image->data.pixbuf.pixbuf)); g_object_unref (G_OBJECT (image->data.pixbuf.pixbuf));
image->data.pixbuf.pixbuf = NULL;
break; break;
case GTK_IMAGE_STOCK: case GTK_IMAGE_STOCK:
g_free (image->data.stock.stock_id); g_free (image->data.stock.stock_id);
image->data.stock.stock_id = NULL;
image->data.stock.size = 0;
break; break;
case GTK_IMAGE_ICON_SET: case GTK_IMAGE_ICON_SET:
if (image->data.icon_set.icon_set) if (image->data.icon_set.icon_set)
gtk_icon_set_unref (image->data.icon_set.icon_set); gtk_icon_set_unref (image->data.icon_set.icon_set);
image->data.icon_set.size = 0; break;
image->data.icon_set.icon_set = NULL;
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; break;
case GTK_IMAGE_EMPTY: case GTK_IMAGE_EMPTY:
@ -928,6 +1122,8 @@ gtk_image_clear (GtkImage *image)
} }
image->storage_type = GTK_IMAGE_EMPTY; image->storage_type = GTK_IMAGE_EMPTY;
memset (&image->data, '\0', sizeof (image->data));
} }
static void static void

View File

@ -52,6 +52,7 @@ typedef struct _GtkImageImageData GtkImageImageData;
typedef struct _GtkImagePixbufData GtkImagePixbufData; typedef struct _GtkImagePixbufData GtkImagePixbufData;
typedef struct _GtkImageStockData GtkImageStockData; typedef struct _GtkImageStockData GtkImageStockData;
typedef struct _GtkImageIconSetData GtkImageIconSetData; typedef struct _GtkImageIconSetData GtkImageIconSetData;
typedef struct _GtkImageAnimationData GtkImageAnimationData;
struct _GtkImagePixmapData struct _GtkImagePixmapData
{ {
@ -82,6 +83,13 @@ struct _GtkImageIconSetData
GtkIconSize size; GtkIconSize size;
}; };
struct _GtkImageAnimationData
{
GdkPixbufAnimation *anim;
GdkPixbufAnimationIter *iter;
guint frame_timeout;
};
typedef enum typedef enum
{ {
GTK_IMAGE_EMPTY, GTK_IMAGE_EMPTY,
@ -89,7 +97,8 @@ typedef enum
GTK_IMAGE_IMAGE, GTK_IMAGE_IMAGE,
GTK_IMAGE_PIXBUF, GTK_IMAGE_PIXBUF,
GTK_IMAGE_STOCK, GTK_IMAGE_STOCK,
GTK_IMAGE_ICON_SET GTK_IMAGE_ICON_SET,
GTK_IMAGE_ANIMATION
} GtkImageType; } GtkImageType;
struct _GtkImage struct _GtkImage
@ -105,6 +114,7 @@ struct _GtkImage
GtkImagePixbufData pixbuf; GtkImagePixbufData pixbuf;
GtkImageStockData stock; GtkImageStockData stock;
GtkImageIconSetData icon_set; GtkImageIconSetData icon_set;
GtkImageAnimationData anim;
} data; } data;
}; };
@ -125,6 +135,7 @@ GtkWidget* gtk_image_new_from_stock (const gchar *stock_id,
GtkIconSize size); GtkIconSize size);
GtkWidget* gtk_image_new_from_icon_set (GtkIconSet *icon_set, GtkWidget* gtk_image_new_from_icon_set (GtkIconSet *icon_set,
GtkIconSize size); GtkIconSize size);
GtkWidget* gtk_image_new_from_animation (GdkPixbufAnimation *animation);
void gtk_image_set_from_pixmap (GtkImage *image, void gtk_image_set_from_pixmap (GtkImage *image,
GdkPixmap *pixmap, GdkPixmap *pixmap,
@ -142,6 +153,8 @@ void gtk_image_set_from_stock (GtkImage *image,
void gtk_image_set_from_icon_set (GtkImage *image, void gtk_image_set_from_icon_set (GtkImage *image,
GtkIconSet *icon_set, GtkIconSet *icon_set,
GtkIconSize size); GtkIconSize size);
void gtk_image_set_from_animation (GtkImage *image,
GdkPixbufAnimation *animation);
GtkImageType gtk_image_get_storage_type (GtkImage *image); 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, void gtk_image_get_icon_set (GtkImage *image,
GtkIconSet **icon_set, GtkIconSet **icon_set,
GtkIconSize *size); GtkIconSize *size);
GdkPixbufAnimation* gtk_image_get_animation (GtkImage *image);
#ifndef GTK_DISABLE_DEPRECATED #ifndef GTK_DISABLE_DEPRECATED

View File

@ -36,6 +36,7 @@ NONE:INT,INT
NONE:NONE NONE:NONE
NONE:POINTER NONE:POINTER
NONE:STRING,INT,POINTER NONE:STRING,INT,POINTER
STRING:DOUBLE
VOID:BOOLEAN VOID:BOOLEAN
VOID:BOXED VOID:BOXED
VOID:BOXED,BOXED VOID:BOXED,BOXED

View File

@ -36,6 +36,7 @@ NONE:INT,INT
NONE:NONE NONE:NONE
NONE:POINTER NONE:POINTER
NONE:STRING,INT,POINTER NONE:STRING,INT,POINTER
STRING:DOUBLE
VOID:BOOLEAN VOID:BOOLEAN
VOID:BOXED VOID:BOXED
VOID:BOXED,BOXED VOID:BOXED,BOXED

View File

@ -98,6 +98,7 @@ struct _GtkRangeClass
GtkTroughType trough); GtkTroughType trough);
/* Completely broken virtual functions, please ignore */ /* Completely broken virtual functions, please ignore */
void (* draw_background) (GtkRange *range); void (* draw_background) (GtkRange *range);
void (* clear_background) (GtkRange *range); void (* clear_background) (GtkRange *range);
void (* draw_trough) (GtkRange *range); void (* draw_trough) (GtkRange *range);

View File

@ -27,6 +27,7 @@
#include <math.h> #include <math.h>
#include "gtkintl.h" #include "gtkintl.h"
#include "gtkscale.h" #include "gtkscale.h"
#include "gtkmarshal.h"
enum { enum {
ARG_0, ARG_0,
@ -35,6 +36,12 @@ enum {
ARG_VALUE_POS 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_class_init (GtkScaleClass *klass);
static void gtk_scale_init (GtkScale *scale); static void gtk_scale_init (GtkScale *scale);
@ -78,6 +85,22 @@ gtk_scale_get_type (void)
return scale_type; 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 static void
gtk_scale_class_init (GtkScaleClass *class) gtk_scale_class_init (GtkScaleClass *class)
{ {
@ -104,6 +127,16 @@ gtk_scale_class_init (GtkScaleClass *class)
GTK_ARG_READWRITE, GTK_ARG_READWRITE,
ARG_VALUE_POS); 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->set_arg = gtk_scale_set_arg;
object_class->get_arg = gtk_scale_get_arg; object_class->get_arg = gtk_scale_get_arg;
@ -280,58 +313,27 @@ gtk_scale_get_value_size (GtkScale *scale,
{ {
PangoLayout *layout; PangoLayout *layout;
PangoRectangle logical_rect; PangoRectangle logical_rect;
gchar buffer[128]; gchar *txt;
gdouble value;
gint digits;
gint i, j;
range = GTK_RANGE (scale); range = GTK_RANGE (scale);
layout = gtk_widget_create_pango_layout (GTK_WIDGET (scale), NULL); layout = gtk_widget_create_pango_layout (GTK_WIDGET (scale), NULL);
value = ABS (range->adjustment->lower); txt = _gtk_scale_format_value (scale, range->adjustment->lower);
if (value == 0) value = 1; pango_layout_set_text (layout, txt, -1);
digits = log10 (value) + 1; g_free (txt);
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);
pango_layout_get_pixel_extents (layout, NULL, &logical_rect); pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
if (width) if (width)
*width = logical_rect.width; *width = logical_rect.width;
if (height) if (height)
*height = logical_rect.width; *height = logical_rect.height;
value = ABS (range->adjustment->upper); txt = _gtk_scale_format_value (scale, range->adjustment->upper);
if (value == 0) value = 1; pango_layout_set_text (layout, txt, -1);
digits = log10 (value) + 1; g_free (txt);
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); pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
if (width) if (width)
@ -383,3 +385,32 @@ gtk_scale_draw_background (GtkRange *range)
gtk_scale_draw_value (GTK_SCALE (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);
}

View File

@ -62,6 +62,9 @@ struct _GtkScaleClass
gint value_spacing; gint value_spacing;
gchar* (* format_value) (GtkRange *range,
gdouble value);
void (* draw_value) (GtkScale *scale); void (* draw_value) (GtkScale *scale);
}; };
@ -79,6 +82,9 @@ void gtk_scale_get_value_size (GtkScale *scale,
void gtk_scale_draw_value (GtkScale *scale); void gtk_scale_draw_value (GtkScale *scale);
gchar *_gtk_scale_format_value (GtkScale *scale,
gdouble value);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@ -2106,6 +2106,127 @@ gtk_text_buffer_remove_tag_by_name (GtkTextBuffer *buffer,
gtk_text_buffer_emit_tag (buffer, tag, FALSE, start, end); 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 * Obtain various iterators

View File

@ -266,6 +266,9 @@ void gtk_text_buffer_remove_tag_by_name (GtkTextBuffer *buffer,
const gchar *name, const gchar *name,
const GtkTextIter *start, const GtkTextIter *start,
const GtkTextIter *end); 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 /* You can either ignore the return value, or use it to

View File

@ -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 * @iter: an iterator
* *
* Returns TRUE if @iter is the first iterator in the buffer, that is * 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 * Return value: whether @iter is the first in the buffer
**/ **/
gboolean 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; 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 /* If we start on line 1, there are 2 lines to search (0 and 1), so
* n_lines can be 2. * 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) gtk_text_iter_get_line (start) + 1 < win->n_lines)
{ {
/* Already at the end, or not enough lines to match */ /* Already at the end, or not enough lines to match */

View File

@ -108,7 +108,8 @@ GSList * gtk_text_iter_get_marks (const GtkTextIter *iter);
GtkTextChildAnchor* gtk_text_iter_get_child_anchor (const GtkTextIter *iter); GtkTextChildAnchor* gtk_text_iter_get_child_anchor (const GtkTextIter *iter);
/* Return list of tags toggled at this point (toggled_on determines /* 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, GSList *gtk_text_iter_get_toggled_tags (const GtkTextIter *iter,
gboolean toggled_on); gboolean toggled_on);
@ -145,7 +146,7 @@ gboolean gtk_text_iter_get_attributes (const GtkTextIter *iter,
GtkTextAttributes *values); GtkTextAttributes *values);
gchar* gtk_text_iter_get_language (const GtkTextIter *iter); gchar* gtk_text_iter_get_language (const GtkTextIter *iter);
gboolean gtk_text_iter_is_end (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 * Moving around the buffer

View File

@ -1280,6 +1280,16 @@ add_text_attrs (GtkTextLayout *layout,
attr->end_index = start + byte_count; attr->end_index = start + byte_count;
pango_attr_list_insert (attrs, attr); 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 static void

View File

@ -85,6 +85,7 @@ enum {
PROP_STRETCH, PROP_STRETCH,
PROP_SIZE, PROP_SIZE,
PROP_SIZE_POINTS, PROP_SIZE_POINTS,
PROP_SCALE,
PROP_PIXELS_ABOVE_LINES, PROP_PIXELS_ABOVE_LINES,
PROP_PIXELS_BELOW_LINES, PROP_PIXELS_BELOW_LINES,
PROP_PIXELS_INSIDE_WRAP, PROP_PIXELS_INSIDE_WRAP,
@ -114,6 +115,7 @@ enum {
PROP_WEIGHT_SET, PROP_WEIGHT_SET,
PROP_STRETCH_SET, PROP_STRETCH_SET,
PROP_SIZE_SET, PROP_SIZE_SET,
PROP_SCALE_SET,
PROP_PIXELS_ABOVE_LINES_SET, PROP_PIXELS_ABOVE_LINES_SET,
PROP_PIXELS_BELOW_LINES_SET, PROP_PIXELS_BELOW_LINES_SET,
PROP_PIXELS_INSIDE_WRAP_SET, PROP_PIXELS_INSIDE_WRAP_SET,
@ -349,6 +351,16 @@ gtk_text_tag_class_init (GtkTextTagClass *klass)
0, 0,
G_PARAM_READABLE | G_PARAM_WRITABLE)); 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, g_object_class_install_property (object_class,
PROP_SIZE_POINTS, PROP_SIZE_POINTS,
g_param_spec_double ("size_points", g_param_spec_double ("size_points",
@ -543,6 +555,10 @@ gtk_text_tag_class_init (GtkTextTagClass *klass)
_("Font size set"), _("Font size set"),
_("Whether this tag affects the font size")); _("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, ADD_SET_PROP ("justification_set", PROP_JUSTIFICATION_SET,
_("Justification set"), _("Justification set"),
_("Whether this tag affects paragraph justification")); _("Whether this tag affects paragraph justification"));
@ -963,6 +979,12 @@ gtk_text_tag_set_property (GObject *object,
size_changed = TRUE; size_changed = TRUE;
break; 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: case PROP_SIZE_POINTS:
text_tag->values->font.size = g_value_get_double (value) * PANGO_SCALE; text_tag->values->font.size = g_value_get_double (value) * PANGO_SCALE;
text_tag->size_set = TRUE; text_tag->size_set = TRUE;
@ -1152,6 +1174,11 @@ gtk_text_tag_set_property (GObject *object,
size_changed = TRUE; size_changed = TRUE;
break; break;
case PROP_SCALE_SET:
text_tag->scale_set = g_value_get_boolean (value);
size_changed = TRUE;
break;
case PROP_PIXELS_ABOVE_LINES_SET: case PROP_PIXELS_ABOVE_LINES_SET:
text_tag->pixels_above_lines_set = g_value_get_boolean (value); text_tag->pixels_above_lines_set = g_value_get_boolean (value);
size_changed = TRUE; size_changed = TRUE;
@ -1337,6 +1364,10 @@ gtk_text_tag_get_property (GObject *object,
g_value_set_double (value, ((double)tag->values->font.size) / (double)PANGO_SCALE); g_value_set_double (value, ((double)tag->values->font.size) / (double)PANGO_SCALE);
break; break;
case PROP_SCALE:
g_value_set_double (value, tag->values->font_scale);
break;
case PROP_PIXELS_ABOVE_LINES: case PROP_PIXELS_ABOVE_LINES:
g_value_set_int (value, tag->values->pixels_above_lines); g_value_set_int (value, tag->values->pixels_above_lines);
break; break;
@ -1446,6 +1477,10 @@ gtk_text_tag_get_property (GObject *object,
g_value_set_boolean (value, tag->size_set); g_value_set_boolean (value, tag->size_set);
break; break;
case PROP_SCALE_SET:
g_value_set_boolean (value, tag->scale_set);
break;
case PROP_PIXELS_ABOVE_LINES_SET: case PROP_PIXELS_ABOVE_LINES_SET:
g_value_set_boolean (value, tag->pixels_above_lines_set); g_value_set_boolean (value, tag->pixels_above_lines_set);
break; break;
@ -1724,6 +1759,8 @@ gtk_text_attributes_new (void)
values->language = gtk_get_default_language (); values->language = gtk_get_default_language ();
values->font_scale = 1.0;
return values; return values;
} }
@ -1965,6 +2002,10 @@ _gtk_text_attributes_fill_from_tags (GtkTextAttributes *dest,
if (tag->size_set) if (tag->size_set)
dest->font.size = vals->font.size; 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) if (tag->justification_set)
dest->justification = vals->justification; dest->justification = vals->justification;
@ -2038,6 +2079,7 @@ _gtk_text_tag_affects_size (GtkTextTag *tag)
tag->variant_set || tag->variant_set ||
tag->weight_set || tag->weight_set ||
tag->size_set || tag->size_set ||
tag->scale_set ||
tag->stretch_set || tag->stretch_set ||
tag->justification_set || tag->justification_set ||
tag->left_margin_set || tag->left_margin_set ||

View File

@ -60,6 +60,7 @@ struct _GtkTextTag
guint weight_set : 1; guint weight_set : 1;
guint stretch_set : 1; guint stretch_set : 1;
guint size_set : 1; guint size_set : 1;
guint scale_set : 1;
guint fg_stipple_set : 1; guint fg_stipple_set : 1;
guint justification_set : 1; guint justification_set : 1;
guint left_margin_set : 1; guint left_margin_set : 1;
@ -148,6 +149,8 @@ struct _GtkTextAttributes
/* Individual chunks of this can be set/unset as a group */ /* Individual chunks of this can be set/unset as a group */
PangoFontDescription font; PangoFontDescription font;
gdouble font_scale;
gint left_margin; gint left_margin;
gint indent; gint indent;

View File

@ -506,6 +506,7 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
GTK_ARG_READWRITE, ARG_PIXELS_INSIDE_WRAP); GTK_ARG_READWRITE, ARG_PIXELS_INSIDE_WRAP);
gtk_object_add_arg_type ("GtkTextView::editable", GTK_TYPE_BOOL, gtk_object_add_arg_type ("GtkTextView::editable", GTK_TYPE_BOOL,
GTK_ARG_READWRITE, ARG_EDITABLE); GTK_ARG_READWRITE, ARG_EDITABLE);
gtk_object_add_arg_type ("GtkTextView::wrap_mode", GTK_TYPE_WRAP_MODE, gtk_object_add_arg_type ("GtkTextView::wrap_mode", GTK_TYPE_WRAP_MODE,
GTK_ARG_READWRITE, ARG_WRAP_MODE); GTK_ARG_READWRITE, ARG_WRAP_MODE);
gtk_object_add_arg_type ("GtkTextView::justify", GTK_TYPE_JUSTIFICATION, gtk_object_add_arg_type ("GtkTextView::justify", GTK_TYPE_JUSTIFICATION,

View File

@ -532,7 +532,6 @@ gtk_vscale_draw_value (GtkScale *scale)
{ {
GtkStateType state_type; GtkStateType state_type;
GtkWidget *widget; GtkWidget *widget;
gchar buffer[32];
gint width, height; gint width, height;
gint x, y; gint x, y;
@ -545,10 +544,14 @@ gtk_vscale_draw_value (GtkScale *scale)
{ {
PangoLayout *layout; PangoLayout *layout;
PangoRectangle logical_rect; PangoRectangle logical_rect;
gchar *txt;
sprintf (buffer, "%0.*f", GTK_RANGE (scale)->digits, GTK_RANGE (scale)->adjustment->value); txt = _gtk_scale_format_value (scale,
GTK_RANGE (scale)->adjustment->value);
layout = gtk_widget_create_pango_layout (widget, txt);
g_free (txt);
layout = gtk_widget_create_pango_layout (widget, buffer);
pango_layout_get_pixel_extents (layout, NULL, &logical_rect); pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
switch (scale->value_pos) switch (scale->value_pos)

View File

@ -6511,6 +6511,13 @@ create_event_watcher (void)
* GtkRange * GtkRange
*/ */
static gchar*
reformat_value (GtkScale *scale,
gdouble value)
{
return g_strdup_printf ("-->%g<--", value);
}
static void static void
create_range_controls (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_box_pack_start (GTK_BOX (box2), scrollbar, TRUE, TRUE, 0);
gtk_widget_show (scrollbar); 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); hbox = gtk_hbox_new (FALSE, 0);
scale = gtk_vscale_new (GTK_ADJUSTMENT (adjustment)); scale = gtk_vscale_new (GTK_ADJUSTMENT (adjustment));
@ -6580,6 +6596,16 @@ create_range_controls (void)
gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (hbox), scale, TRUE, TRUE, 0);
gtk_widget_show (scale); 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_box_pack_start (GTK_BOX (box2), hbox, TRUE, TRUE, 0);
gtk_widget_show (hbox); gtk_widget_show (hbox);
@ -8159,8 +8185,13 @@ configure_event_callback (GtkWidget *widget,
gchar *msg; gchar *msg;
gint x, y; gint x, y;
x = widget->allocation.x; #if 0
y = widget->allocation.y; /* 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" msg = g_strdup_printf ("event: %d,%d %d x %d\n"
"location: %d, %d", "location: %d, %d",
@ -8235,6 +8266,26 @@ set_location_callback (GtkWidget *widget,
gtk_widget_set_uposition (g_object_get_data (data, "target"), x, y); gtk_widget_set_uposition (g_object_get_data (data, "target"), x, y);
} }
static void
set_geometry_callback (GtkWidget *entry,
gpointer data)
{
gchar *text;
GtkWindow *target;
target = GTK_WINDOW (g_object_get_data (G_OBJECT (data), "target"));
text = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
#if 0
/* FIXME */
if (!gtk_window_parse_geometry (target, text))
g_print ("Bad geometry string '%s'\n", text);
#endif
g_free (text);
}
static void static void
allow_shrink_callback (GtkWidget *widget, allow_shrink_callback (GtkWidget *widget,
gpointer data) gpointer data)
@ -8282,6 +8333,7 @@ window_controls (GtkWidget *window)
GtkWidget *button; GtkWidget *button;
GtkWidget *spin; GtkWidget *spin;
GtkAdjustment *adj; GtkAdjustment *adj;
GtkWidget *entry;
GtkWidget *om; GtkWidget *om;
GtkWidget *menu; GtkWidget *menu;
gint i; gint i;
@ -8327,6 +8379,13 @@ window_controls (GtkWidget *window)
g_object_set_data (G_OBJECT (control_window), "spin2", spin); 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"); button = gtk_button_new_with_label ("Queue resize");
gtk_signal_connect_object (GTK_OBJECT (button), gtk_signal_connect_object (GTK_OBJECT (button),
"clicked", "clicked",
@ -8386,6 +8445,20 @@ window_controls (GtkWidget *window)
GTK_OBJECT (control_window)); GTK_OBJECT (control_window));
gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0); 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 (); menu = gtk_menu_new ();
i = 0; i = 0;

View File

@ -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 enum
{ {
RESPONSE_FORWARD, RESPONSE_FORWARD,
@ -1235,6 +1252,7 @@ static GtkItemFactoryEntry menu_items[] =
{ "/Attributes/Default tabs", NULL, do_apply_tabs, TRUE, NULL }, { "/Attributes/Default tabs", NULL, do_apply_tabs, TRUE, NULL },
{ "/Attributes/Color cycles", NULL, do_apply_colors, TRUE, NULL }, { "/Attributes/Color cycles", NULL, do_apply_colors, TRUE, NULL },
{ "/Attributes/No colors", NULL, do_apply_colors, FALSE, 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", NULL, 0, 0, "<Branch>" },
{ "/Test/_Example", NULL, do_example, 0, NULL }, { "/Test/_Example", NULL, do_example, 0, NULL },
}; };