Blame demos/testanimation.c

Packit 98cdb6
Packit 98cdb6
/* testpixbuf -- test program for gdk-pixbuf code
Packit 98cdb6
 * Copyright (C) 1999 Mark Crichton, Larry Ewing
Packit 98cdb6
 *
Packit 98cdb6
 * This library is free software; you can redistribute it and/or
Packit 98cdb6
 * modify it under the terms of the GNU Lesser General Public
Packit 98cdb6
 * License as published by the Free Software Foundation; either
Packit 98cdb6
 * version 2 of the License, or (at your option) any later version.
Packit 98cdb6
 *
Packit 98cdb6
 * This library is distributed in the hope that it will be useful,
Packit 98cdb6
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 98cdb6
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 98cdb6
 * Lesser General Public License for more details.
Packit 98cdb6
 *
Packit 98cdb6
 * You should have received a copy of the GNU Lesser General Public
Packit 98cdb6
 * License along with this library; if not, write to the
Packit 98cdb6
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Packit 98cdb6
 * Boston, MA 02111-1307, USA.
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
#include "config.h"
Packit 98cdb6
#include <stdio.h>
Packit 98cdb6
#include <stdlib.h>
Packit 98cdb6
#include <unistd.h>
Packit 98cdb6
#include <string.h>
Packit 98cdb6
#include <errno.h>
Packit 98cdb6
#include <gtk/gtk.h>
Packit 98cdb6
Packit 98cdb6
typedef struct _LoadContext LoadContext;
Packit 98cdb6
Packit 98cdb6
struct _LoadContext
Packit 98cdb6
{
Packit 98cdb6
  gchar *filename;
Packit 98cdb6
  GtkWidget *window;
Packit 98cdb6
  GdkPixbufLoader *pixbuf_loader;
Packit 98cdb6
  guint load_timeout;
Packit 98cdb6
  FILE* image_stream;
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
destroy_context (gpointer data)
Packit 98cdb6
{
Packit 98cdb6
  LoadContext *lc = data;
Packit 98cdb6
Packit 98cdb6
  g_free (lc->filename);
Packit 98cdb6
  
Packit 98cdb6
  if (lc->load_timeout)
Packit 98cdb6
    g_source_remove (lc->load_timeout);
Packit 98cdb6
Packit 98cdb6
  if (lc->image_stream)
Packit 98cdb6
    fclose (lc->image_stream);
Packit 98cdb6
Packit 98cdb6
  if (lc->pixbuf_loader)
Packit 98cdb6
    {
Packit 98cdb6
      gdk_pixbuf_loader_close (lc->pixbuf_loader, NULL);
Packit 98cdb6
      g_object_unref (lc->pixbuf_loader);
Packit 98cdb6
    }
Packit 98cdb6
  
Packit 98cdb6
  g_free (lc);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static LoadContext*
Packit 98cdb6
get_load_context (GtkWidget *image)
Packit 98cdb6
{
Packit 98cdb6
  LoadContext *lc;
Packit 98cdb6
Packit 98cdb6
  lc = g_object_get_data (G_OBJECT (image), "lc");
Packit 98cdb6
Packit 98cdb6
  if (lc == NULL)
Packit 98cdb6
    {
Packit 98cdb6
      lc = g_new0 (LoadContext, 1);
Packit 98cdb6
Packit 98cdb6
      g_object_set_data_full (G_OBJECT (image),        
Packit 98cdb6
                              "lc",
Packit 98cdb6
                              lc,
Packit 98cdb6
                              destroy_context);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  return lc;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
progressive_prepared_callback (GdkPixbufLoader* loader,
Packit 98cdb6
                               gpointer         data)
Packit 98cdb6
{
Packit 98cdb6
  GdkPixbuf* pixbuf;
Packit 98cdb6
  GtkWidget* image;
Packit 98cdb6
Packit 98cdb6
  image = GTK_WIDGET (data);
Packit 98cdb6
    
Packit 98cdb6
  pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
Packit 98cdb6
Packit 98cdb6
  /* Avoid displaying random memory contents, since the pixbuf
Packit 98cdb6
   * isn't filled in yet.
Packit 98cdb6
   */
Packit 98cdb6
  gdk_pixbuf_fill (pixbuf, 0xaaaaaaff);
Packit 98cdb6
Packit 98cdb6
  /* Could set the pixbuf instead, if we only wanted to display
Packit 98cdb6
   * static images.
Packit 98cdb6
   */
Packit 98cdb6
  gtk_image_set_from_animation (GTK_IMAGE (image),
Packit 98cdb6
                                gdk_pixbuf_loader_get_animation (loader));
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
progressive_updated_callback (GdkPixbufLoader* loader,
Packit 98cdb6
                              gint x, gint y, gint width, gint height,
Packit 98cdb6
                              gpointer data)
Packit 98cdb6
{
Packit 98cdb6
  GtkWidget* image;
Packit 98cdb6
  
Packit 98cdb6
  image = GTK_WIDGET (data);
Packit 98cdb6
Packit 98cdb6
  /* We know the pixbuf inside the GtkImage has changed, but the image
Packit 98cdb6
   * itself doesn't know this; so queue a redraw.  If we wanted to be
Packit 98cdb6
   * really efficient, we could use a drawing area or something
Packit 98cdb6
   * instead of a GtkImage, so we could control the exact position of
Packit 98cdb6
   * the pixbuf on the display, then we could queue a draw for only
Packit 98cdb6
   * the updated area of the image.
Packit 98cdb6
   */
Packit 98cdb6
Packit 98cdb6
  /* We only really need to redraw if the image's animation iterator
Packit 98cdb6
   * is gdk_pixbuf_animation_iter_on_currently_loading_frame(), but
Packit 98cdb6
   * who cares.
Packit 98cdb6
   */
Packit 98cdb6
  
Packit 98cdb6
  gtk_widget_queue_draw (image);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static gint
Packit 98cdb6
progressive_timeout (gpointer data)
Packit 98cdb6
{
Packit 98cdb6
  GtkWidget *image;
Packit 98cdb6
  LoadContext *lc;
Packit 98cdb6
  
Packit 98cdb6
  image = GTK_WIDGET (data);
Packit 98cdb6
  lc = get_load_context (image);
Packit 98cdb6
  
Packit 98cdb6
  /* This shows off fully-paranoid error handling, so looks scary.
Packit 98cdb6
   * You could factor out the error handling code into a nice separate
Packit 98cdb6
   * function to make things nicer.
Packit 98cdb6
   */
Packit 98cdb6
  
Packit 98cdb6
  if (lc->image_stream)
Packit 98cdb6
    {
Packit 98cdb6
      size_t bytes_read;
Packit 98cdb6
      guchar buf[256];
Packit 98cdb6
      GError *error = NULL;
Packit 98cdb6
      
Packit 98cdb6
      bytes_read = fread (buf, 1, 256, lc->image_stream);
Packit 98cdb6
Packit 98cdb6
      if (ferror (lc->image_stream))
Packit 98cdb6
        {
Packit 98cdb6
          GtkWidget *dialog;
Packit 98cdb6
          
Packit 98cdb6
          dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
Packit 98cdb6
                                           GTK_DIALOG_DESTROY_WITH_PARENT,
Packit 98cdb6
                                           GTK_MESSAGE_ERROR,
Packit 98cdb6
                                           GTK_BUTTONS_CLOSE,
Packit 98cdb6
                                           "Failure reading image file 'alphatest.png': %s",
Packit 98cdb6
                                           g_strerror (errno));
Packit 98cdb6
Packit 98cdb6
          g_signal_connect (dialog, "response",
Packit 98cdb6
			    G_CALLBACK (gtk_widget_destroy), NULL);
Packit 98cdb6
Packit 98cdb6
          fclose (lc->image_stream);
Packit 98cdb6
          lc->image_stream = NULL;
Packit 98cdb6
Packit 98cdb6
          gtk_widget_show (dialog);
Packit 98cdb6
          
Packit 98cdb6
          lc->load_timeout = 0;
Packit 98cdb6
Packit 98cdb6
          return FALSE; /* uninstall the timeout */
Packit 98cdb6
        }
Packit 98cdb6
Packit 98cdb6
      if (!gdk_pixbuf_loader_write (lc->pixbuf_loader,
Packit 98cdb6
                                    buf, bytes_read,
Packit 98cdb6
                                    &error))
Packit 98cdb6
        {
Packit 98cdb6
          GtkWidget *dialog;
Packit 98cdb6
          
Packit 98cdb6
          dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
Packit 98cdb6
                                           GTK_DIALOG_DESTROY_WITH_PARENT,
Packit 98cdb6
                                           GTK_MESSAGE_ERROR,
Packit 98cdb6
                                           GTK_BUTTONS_CLOSE,
Packit 98cdb6
                                           "Failed to load image: %s",
Packit 98cdb6
                                           error->message);
Packit 98cdb6
Packit 98cdb6
          g_error_free (error);
Packit 98cdb6
          
Packit 98cdb6
          g_signal_connect (dialog, "response",
Packit 98cdb6
			    G_CALLBACK (gtk_widget_destroy), NULL);
Packit 98cdb6
Packit 98cdb6
          fclose (lc->image_stream);
Packit 98cdb6
          lc->image_stream = NULL;
Packit 98cdb6
          
Packit 98cdb6
          gtk_widget_show (dialog);
Packit 98cdb6
Packit 98cdb6
          lc->load_timeout = 0;
Packit 98cdb6
Packit 98cdb6
          return FALSE; /* uninstall the timeout */
Packit 98cdb6
        }
Packit 98cdb6
Packit 98cdb6
      if (feof (lc->image_stream))
Packit 98cdb6
        {
Packit 98cdb6
          fclose (lc->image_stream);
Packit 98cdb6
          lc->image_stream = NULL;
Packit 98cdb6
Packit 98cdb6
          /* Errors can happen on close, e.g. if the image
Packit 98cdb6
           * file was truncated we'll know on close that
Packit 98cdb6
           * it was incomplete.
Packit 98cdb6
           */
Packit 98cdb6
          error = NULL;
Packit 98cdb6
          if (!gdk_pixbuf_loader_close (lc->pixbuf_loader,
Packit 98cdb6
                                        &error))
Packit 98cdb6
            {
Packit 98cdb6
              GtkWidget *dialog;
Packit 98cdb6
              
Packit 98cdb6
              dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
Packit 98cdb6
                                               GTK_DIALOG_DESTROY_WITH_PARENT,
Packit 98cdb6
                                               GTK_MESSAGE_ERROR,
Packit 98cdb6
                                               GTK_BUTTONS_CLOSE,
Packit 98cdb6
                                               "Failed to load image: %s",
Packit 98cdb6
                                               error->message);
Packit 98cdb6
              
Packit 98cdb6
              g_error_free (error);
Packit 98cdb6
              
Packit 98cdb6
              g_signal_connect (dialog, "response",
Packit 98cdb6
				G_CALLBACK (gtk_widget_destroy), NULL);
Packit 98cdb6
              
Packit 98cdb6
              gtk_widget_show (dialog);
Packit 98cdb6
Packit 98cdb6
              g_object_unref (lc->pixbuf_loader);
Packit 98cdb6
              lc->pixbuf_loader = NULL;
Packit 98cdb6
              
Packit 98cdb6
              lc->load_timeout = 0;
Packit 98cdb6
              
Packit 98cdb6
              return FALSE; /* uninstall the timeout */
Packit 98cdb6
            }
Packit 98cdb6
          
Packit 98cdb6
          g_object_unref (lc->pixbuf_loader);
Packit 98cdb6
          lc->pixbuf_loader = NULL;
Packit 98cdb6
        }
Packit 98cdb6
    }
Packit 98cdb6
  else
Packit 98cdb6
    {
Packit 98cdb6
      lc->image_stream = fopen (lc->filename, "r");
Packit 98cdb6
Packit 98cdb6
      if (lc->image_stream == NULL)
Packit 98cdb6
        {
Packit 98cdb6
          GtkWidget *dialog;
Packit 98cdb6
          
Packit 98cdb6
          dialog = gtk_message_dialog_new (GTK_WINDOW (lc->window),
Packit 98cdb6
                                           GTK_DIALOG_DESTROY_WITH_PARENT,
Packit 98cdb6
                                           GTK_MESSAGE_ERROR,
Packit 98cdb6
                                           GTK_BUTTONS_CLOSE,
Packit 98cdb6
                                           "Unable to open image file '%s': %s",
Packit 98cdb6
                                           lc->filename,
Packit 98cdb6
                                           g_strerror (errno));
Packit 98cdb6
Packit 98cdb6
          g_signal_connect (dialog, "response",
Packit 98cdb6
			    G_CALLBACK (gtk_widget_destroy), NULL);
Packit 98cdb6
          
Packit 98cdb6
          gtk_widget_show (dialog);
Packit 98cdb6
Packit 98cdb6
          lc->load_timeout = 0;
Packit 98cdb6
Packit 98cdb6
          return FALSE; /* uninstall the timeout */
Packit 98cdb6
        }
Packit 98cdb6
Packit 98cdb6
      if (lc->pixbuf_loader)
Packit 98cdb6
        {
Packit 98cdb6
          gdk_pixbuf_loader_close (lc->pixbuf_loader, NULL);
Packit 98cdb6
          g_object_unref (lc->pixbuf_loader);
Packit 98cdb6
          lc->pixbuf_loader = NULL;
Packit 98cdb6
        }
Packit 98cdb6
      
Packit 98cdb6
      lc->pixbuf_loader = gdk_pixbuf_loader_new ();
Packit 98cdb6
      
Packit 98cdb6
      g_signal_connect (lc->pixbuf_loader, "area_prepared",
Packit 98cdb6
			G_CALLBACK (progressive_prepared_callback), image);
Packit 98cdb6
      g_signal_connect (lc->pixbuf_loader, "area_updated",
Packit 98cdb6
			G_CALLBACK (progressive_updated_callback), image);
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  /* leave timeout installed */
Packit 98cdb6
  return TRUE;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
start_progressive_loading (GtkWidget *image)
Packit 98cdb6
{
Packit 98cdb6
  LoadContext *lc;
Packit 98cdb6
Packit 98cdb6
  lc = get_load_context (image);
Packit 98cdb6
  
Packit 98cdb6
  /* This is obviously totally contrived (we slow down loading
Packit 98cdb6
   * on purpose to show how incremental loading works).
Packit 98cdb6
   * The real purpose of incremental loading is the case where
Packit 98cdb6
   * you are reading data from a slow source such as the network.
Packit 98cdb6
   * The timeout simply simulates a slow data source by inserting
Packit 98cdb6
   * pauses in the reading process.
Packit 98cdb6
   */
Packit 98cdb6
  lc->load_timeout = gdk_threads_add_timeout (100,
Packit 98cdb6
                                    progressive_timeout,
Packit 98cdb6
                                    image);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static GtkWidget *
Packit 98cdb6
do_image (const char *filename)
Packit 98cdb6
{
Packit 98cdb6
  GtkWidget *frame;
Packit 98cdb6
  GtkWidget *vbox;
Packit 98cdb6
  GtkWidget *image;
Packit 98cdb6
  GtkWidget *label;
Packit 98cdb6
  GtkWidget *align;
Packit 98cdb6
  GtkWidget *window;
Packit 98cdb6
  gchar *str, *escaped;
Packit 98cdb6
  LoadContext *lc;
Packit 98cdb6
  
Packit 98cdb6
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
Packit 98cdb6
  gtk_window_set_title (GTK_WINDOW (window), "Image Loading");
Packit 98cdb6
Packit 98cdb6
  gtk_container_set_border_width (GTK_CONTAINER (window), 8);
Packit 98cdb6
Packit 98cdb6
  vbox = gtk_vbox_new (FALSE, 8);
Packit 98cdb6
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
Packit 98cdb6
  gtk_container_add (GTK_CONTAINER (window), vbox);
Packit 98cdb6
Packit 98cdb6
  label = gtk_label_new (NULL);
Packit 98cdb6
  gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
Packit 98cdb6
  escaped = g_markup_escape_text (filename, -1);
Packit 98cdb6
  str = g_strdup_printf ("Progressively loading: %s", escaped);
Packit 98cdb6
  gtk_label_set_markup (GTK_LABEL (label),
Packit 98cdb6
                        str);
Packit 98cdb6
  g_free (escaped);
Packit 98cdb6
  g_free (str);
Packit 98cdb6
  
Packit 98cdb6
  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
Packit 98cdb6
      
Packit 98cdb6
  frame = gtk_frame_new (NULL);
Packit 98cdb6
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
Packit 98cdb6
  /* The alignment keeps the frame from growing when users resize
Packit 98cdb6
   * the window
Packit 98cdb6
   */
Packit 98cdb6
  align = gtk_alignment_new (0.5, 0.5, 0, 0);
Packit 98cdb6
  gtk_container_add (GTK_CONTAINER (align), frame);
Packit 98cdb6
  gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);      
Packit 98cdb6
Packit 98cdb6
  image = gtk_image_new_from_pixbuf (NULL);
Packit 98cdb6
  gtk_container_add (GTK_CONTAINER (frame), image);
Packit 98cdb6
Packit 98cdb6
  lc = get_load_context (image);
Packit 98cdb6
Packit 98cdb6
  lc->window = window;
Packit 98cdb6
  lc->filename = g_strdup (filename);
Packit 98cdb6
  
Packit 98cdb6
  start_progressive_loading (image);
Packit 98cdb6
Packit 98cdb6
  g_signal_connect (window, "destroy",
Packit 98cdb6
		    G_CALLBACK (gtk_main_quit), NULL);
Packit 98cdb6
  
Packit 98cdb6
  g_signal_connect (window, "delete_event",
Packit 98cdb6
		    G_CALLBACK (gtk_main_quit), NULL);
Packit 98cdb6
Packit 98cdb6
  gtk_widget_show_all (window);
Packit 98cdb6
Packit 98cdb6
  return window;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
do_nonprogressive (const gchar *filename)
Packit 98cdb6
{
Packit 98cdb6
  GtkWidget *frame;
Packit 98cdb6
  GtkWidget *vbox;
Packit 98cdb6
  GtkWidget *image;
Packit 98cdb6
  GtkWidget *label;
Packit 98cdb6
  GtkWidget *align;
Packit 98cdb6
  GtkWidget *window;
Packit 98cdb6
  gchar *str, *escaped;
Packit 98cdb6
  
Packit 98cdb6
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
Packit 98cdb6
  gtk_window_set_title (GTK_WINDOW (window), "Animation");
Packit 98cdb6
Packit 98cdb6
  gtk_container_set_border_width (GTK_CONTAINER (window), 8);
Packit 98cdb6
Packit 98cdb6
  vbox = gtk_vbox_new (FALSE, 8);
Packit 98cdb6
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
Packit 98cdb6
  gtk_container_add (GTK_CONTAINER (window), vbox);
Packit 98cdb6
Packit 98cdb6
  label = gtk_label_new (NULL);
Packit 98cdb6
  gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
Packit 98cdb6
  escaped = g_markup_escape_text (filename, -1);
Packit 98cdb6
  str = g_strdup_printf ("Loaded from file: %s", escaped);
Packit 98cdb6
  gtk_label_set_markup (GTK_LABEL (label),
Packit 98cdb6
                        str);
Packit 98cdb6
  g_free (escaped);
Packit 98cdb6
  g_free (str);
Packit 98cdb6
  
Packit 98cdb6
  gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
Packit 98cdb6
      
Packit 98cdb6
  frame = gtk_frame_new (NULL);
Packit 98cdb6
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
Packit 98cdb6
  /* The alignment keeps the frame from growing when users resize
Packit 98cdb6
   * the window
Packit 98cdb6
   */
Packit 98cdb6
  align = gtk_alignment_new (0.5, 0.5, 0, 0);
Packit 98cdb6
  gtk_container_add (GTK_CONTAINER (align), frame);
Packit 98cdb6
  gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);      
Packit 98cdb6
Packit 98cdb6
  image = gtk_image_new_from_file (filename);
Packit 98cdb6
  gtk_container_add (GTK_CONTAINER (frame), image);
Packit 98cdb6
Packit 98cdb6
  g_signal_connect (window, "destroy",
Packit 98cdb6
		    G_CALLBACK (gtk_main_quit), NULL);
Packit 98cdb6
  
Packit 98cdb6
  g_signal_connect (window, "delete_event",
Packit 98cdb6
		    G_CALLBACK (gtk_main_quit), NULL);
Packit 98cdb6
Packit 98cdb6
  gtk_widget_show_all (window);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
int
Packit 98cdb6
main (int    argc,
Packit 98cdb6
      char **argv)
Packit 98cdb6
{
Packit 98cdb6
  gint i;
Packit 98cdb6
  
Packit 98cdb6
  gtk_init (&argc, &argv);
Packit 98cdb6
Packit 98cdb6
  i = 1;
Packit 98cdb6
  while (i < argc)
Packit 98cdb6
    {
Packit 98cdb6
      do_image (argv[i]);
Packit 98cdb6
      do_nonprogressive (argv[i]);
Packit 98cdb6
      
Packit 98cdb6
      ++i;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  gtk_main ();
Packit 98cdb6
  
Packit 98cdb6
  return 0;
Packit 98cdb6
}
Packit 98cdb6