home *** CD-ROM | disk | FTP | other *** search
/ Freelog 65 / Freelog065.iso / BAS / Bureautique / Gnumeric / gnumeric-1.3.92-rc1.exe / images.c < prev    next >
C/C++ Source or Header  |  2004-10-15  |  13KB  |  465 lines

  1. /* Images
  2.  *
  3.  * GtkImage is used to display an image; the image can be in a number of formats.
  4.  * Typically, you load an image into a GdkPixbuf, then display the pixbuf.
  5.  *
  6.  * This demo code shows some of the more obscure cases, in the simple
  7.  * case a call to gtk_image_new_from_file() is all you need.
  8.  *
  9.  * If you want to put image data in your program as a C variable,
  10.  * use the make-inline-pixbuf program that comes with GTK+.
  11.  * This way you won't need to depend on loading external files, your
  12.  * application binary can be self-contained.
  13.  */
  14.  
  15. #include <config.h>
  16. #include <gtk/gtk.h>
  17. #include <stdio.h>
  18. #include <errno.h>
  19. #include "demo-common.h"
  20.  
  21. static GtkWidget *window = NULL;
  22. static GdkPixbufLoader *pixbuf_loader = NULL;
  23. static guint load_timeout = 0;
  24. static FILE* image_stream = NULL;
  25.  
  26. static void
  27. progressive_prepared_callback (GdkPixbufLoader *loader,
  28.                    gpointer        data)
  29. {
  30.   GdkPixbuf *pixbuf;
  31.   GtkWidget *image;
  32.  
  33.   image = GTK_WIDGET (data);
  34.   
  35.   pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
  36.  
  37.   /* Avoid displaying random memory contents, since the pixbuf
  38.    * isn't filled in yet.
  39.    */
  40.   gdk_pixbuf_fill (pixbuf, 0xaaaaaaff);
  41.   
  42.   gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
  43. }
  44.  
  45. static void
  46. progressive_updated_callback (GdkPixbufLoader *loader,
  47.                               gint           x,
  48.                               gint           y,
  49.                               gint           width,
  50.                               gint           height,
  51.                               gpointer       data)
  52. {
  53.   GtkWidget *image;
  54.   
  55.   image = GTK_WIDGET (data);
  56.  
  57.   /* We know the pixbuf inside the GtkImage has changed, but the image
  58.    * itself doesn't know this; so queue a redraw.  If we wanted to be
  59.    * really efficient, we could use a drawing area or something
  60.    * instead of a GtkImage, so we could control the exact position of
  61.    * the pixbuf on the display, then we could queue a draw for only
  62.    * the updated area of the image.
  63.    */
  64.   
  65.   gtk_widget_queue_draw (image);
  66. }
  67.  
  68. static gint
  69. progressive_timeout (gpointer data)
  70. {
  71.   GtkWidget *image;
  72.  
  73.   image = GTK_WIDGET (data);
  74.   
  75.   /* This shows off fully-paranoid error handling, so looks scary.
  76.    * You could factor out the error handling code into a nice separate
  77.    * function to make things nicer.
  78.    */
  79.   
  80.   if (image_stream)
  81.     {
  82.       size_t bytes_read;
  83.       guchar buf[256];
  84.       GError *error = NULL;
  85.       
  86.       bytes_read = fread (buf, 1, 256, image_stream);
  87.  
  88.       if (ferror (image_stream))
  89.     {
  90.       GtkWidget *dialog;
  91.       
  92.       dialog = gtk_message_dialog_new (GTK_WINDOW (window),
  93.                        GTK_DIALOG_DESTROY_WITH_PARENT,
  94.                        GTK_MESSAGE_ERROR,
  95.                        GTK_BUTTONS_CLOSE,
  96.                        "Failure reading image file 'alphatest.png': %s",
  97.                        g_strerror (errno));
  98.  
  99.       g_signal_connect (dialog, "response",
  100.                 G_CALLBACK (gtk_widget_destroy), NULL);
  101.  
  102.       fclose (image_stream);
  103.       image_stream = NULL;
  104.  
  105.       gtk_widget_show (dialog);
  106.       
  107.       load_timeout = 0;
  108.  
  109.       return FALSE; /* uninstall the timeout */
  110.     }
  111.  
  112.       if (!gdk_pixbuf_loader_write (pixbuf_loader,
  113.                     buf, bytes_read,
  114.                     &error))
  115.     {
  116.       GtkWidget *dialog;
  117.       
  118.       dialog = gtk_message_dialog_new (GTK_WINDOW (window),
  119.                        GTK_DIALOG_DESTROY_WITH_PARENT,
  120.                        GTK_MESSAGE_ERROR,
  121.                        GTK_BUTTONS_CLOSE,
  122.                        "Failed to load image: %s",
  123.                        error->message);
  124.  
  125.       g_error_free (error);
  126.       
  127.       g_signal_connect (dialog, "response",
  128.                 G_CALLBACK (gtk_widget_destroy), NULL);
  129.  
  130.       fclose (image_stream);
  131.       image_stream = NULL;
  132.       
  133.       gtk_widget_show (dialog);
  134.  
  135.       load_timeout = 0;
  136.  
  137.       return FALSE; /* uninstall the timeout */
  138.     }
  139.  
  140.       if (feof (image_stream))
  141.     {
  142.       fclose (image_stream);
  143.       image_stream = NULL;
  144.  
  145.       /* Errors can happen on close, e.g. if the image
  146.        * file was truncated we'll know on close that
  147.        * it was incomplete.
  148.        */
  149.       error = NULL;
  150.       if (!gdk_pixbuf_loader_close (pixbuf_loader,
  151.                     &error))
  152.         {
  153.           GtkWidget *dialog;
  154.           
  155.           dialog = gtk_message_dialog_new (GTK_WINDOW (window),
  156.                            GTK_DIALOG_DESTROY_WITH_PARENT,
  157.                            GTK_MESSAGE_ERROR,
  158.                            GTK_BUTTONS_CLOSE,
  159.                            "Failed to load image: %s",
  160.                            error->message);
  161.           
  162.           g_error_free (error);
  163.           
  164.           g_signal_connect (dialog, "response",
  165.                 G_CALLBACK (gtk_widget_destroy), NULL);
  166.           
  167.           gtk_widget_show (dialog);
  168.  
  169.           g_object_unref (pixbuf_loader);
  170.           pixbuf_loader = NULL;
  171.           
  172.           load_timeout = 0;
  173.           
  174.           return FALSE; /* uninstall the timeout */
  175.         }
  176.       
  177.       g_object_unref (pixbuf_loader);
  178.       pixbuf_loader = NULL;
  179.     }
  180.     }
  181.   else
  182.     {
  183.       gchar *filename;
  184.       gchar *error_message = NULL;
  185.       GError *error = NULL; 
  186.  
  187.       /* demo_find_file() looks in the the current directory first,
  188.        * so you can run gtk-demo without installing GTK, then looks
  189.        * in the location where the file is installed.
  190.        */
  191.       filename = demo_find_file ("alphatest.png", &error);
  192.       if (error)
  193.     {
  194.       error_message = g_strdup (error->message);
  195.       g_error_free (error);
  196.     }
  197.       else
  198.     {
  199.       image_stream = fopen (filename, "r");
  200.       g_free (filename);
  201.  
  202.       if (!image_stream)
  203.         error_message = g_strdup_printf ("Unable to open image file 'alphatest.png': %s",
  204.                          g_strerror (errno));
  205.     }
  206.  
  207.       if (image_stream == NULL)
  208.     {
  209.       GtkWidget *dialog;
  210.       
  211.       dialog = gtk_message_dialog_new (GTK_WINDOW (window),
  212.                        GTK_DIALOG_DESTROY_WITH_PARENT,
  213.                        GTK_MESSAGE_ERROR,
  214.                        GTK_BUTTONS_CLOSE,
  215.                        "%s", error_message);
  216.       g_free (error_message);
  217.  
  218.       g_signal_connect (dialog, "response",
  219.                 G_CALLBACK (gtk_widget_destroy), NULL);
  220.       
  221.       gtk_widget_show (dialog);
  222.  
  223.       load_timeout = 0;
  224.  
  225.       return FALSE; /* uninstall the timeout */
  226.     }
  227.  
  228.       if (pixbuf_loader)
  229.     {
  230.       gdk_pixbuf_loader_close (pixbuf_loader, NULL);
  231.       g_object_unref (pixbuf_loader);
  232.       pixbuf_loader = NULL;
  233.     }
  234.       
  235.       pixbuf_loader = gdk_pixbuf_loader_new ();
  236.       
  237.       g_signal_connect (pixbuf_loader, "area_prepared",
  238.             G_CALLBACK (progressive_prepared_callback), image);
  239.       
  240.       g_signal_connect (pixbuf_loader, "area_updated",
  241.             G_CALLBACK (progressive_updated_callback), image);
  242.     }
  243.  
  244.   /* leave timeout installed */
  245.   return TRUE;
  246. }
  247.  
  248. static void
  249. start_progressive_loading (GtkWidget *image)
  250. {
  251.   /* This is obviously totally contrived (we slow down loading
  252.    * on purpose to show how incremental loading works).
  253.    * The real purpose of incremental loading is the case where
  254.    * you are reading data from a slow source such as the network.
  255.    * The timeout simply simulates a slow data source by inserting
  256.    * pauses in the reading process.
  257.    */
  258.   load_timeout = g_timeout_add (150,
  259.                 progressive_timeout,
  260.                 image);
  261. }
  262.  
  263. static void
  264. cleanup_callback (GtkObject *object,
  265.           gpointer   data)
  266. {
  267.   if (load_timeout)
  268.     {
  269.       g_source_remove (load_timeout);
  270.       load_timeout = 0;
  271.     }
  272.   
  273.   if (pixbuf_loader)
  274.     {
  275.       gdk_pixbuf_loader_close (pixbuf_loader, NULL);
  276.       g_object_unref (pixbuf_loader);
  277.       pixbuf_loader = NULL;
  278.     }
  279.  
  280.   if (image_stream)
  281.     fclose (image_stream);
  282.   image_stream = NULL;
  283. }
  284.  
  285. static void
  286. toggle_sensitivity_callback (GtkWidget *togglebutton,
  287.                              gpointer   user_data)
  288. {
  289.   GtkContainer *container = user_data;
  290.   GList *list;
  291.   GList *tmp;
  292.   
  293.   list = gtk_container_get_children (container);
  294.  
  295.   tmp = list;
  296.   while (tmp != NULL)
  297.     {
  298.       /* don't disable our toggle */
  299.       if (GTK_WIDGET (tmp->data) != togglebutton)
  300.         gtk_widget_set_sensitive (GTK_WIDGET (tmp->data),
  301.                                   !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (togglebutton)));
  302.       
  303.       tmp = tmp->next;
  304.     }
  305.  
  306.   g_list_free (list);
  307. }
  308.   
  309.  
  310. GtkWidget *
  311. do_images (GtkWidget *do_widget)
  312. {
  313.   GtkWidget *frame;
  314.   GtkWidget *vbox;
  315.   GtkWidget *image;
  316.   GtkWidget *label;
  317.   GtkWidget *align;
  318.   GtkWidget *button;
  319.   GdkPixbuf *pixbuf;
  320.   GError *error = NULL;
  321.   char *filename;
  322.   
  323.   if (!window)
  324.     {
  325.       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  326.       gtk_window_set_screen (GTK_WINDOW (window),
  327.                  gtk_widget_get_screen (do_widget));
  328.       gtk_window_set_title (GTK_WINDOW (window), "Images");
  329.  
  330.       g_signal_connect (window, "destroy",
  331.             G_CALLBACK (gtk_widget_destroyed), &window);
  332.       g_signal_connect (window, "destroy",
  333.             G_CALLBACK (cleanup_callback), NULL);
  334.  
  335.       gtk_container_set_border_width (GTK_CONTAINER (window), 8);
  336.  
  337.       vbox = gtk_vbox_new (FALSE, 8);
  338.       gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
  339.       gtk_container_add (GTK_CONTAINER (window), vbox);
  340.  
  341.       label = gtk_label_new (NULL);
  342.       gtk_label_set_markup (GTK_LABEL (label),
  343.                 "<u>Image loaded from a file</u>");
  344.       gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  345.       
  346.       frame = gtk_frame_new (NULL);
  347.       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  348.       /* The alignment keeps the frame from growing when users resize
  349.        * the window
  350.        */
  351.       align = gtk_alignment_new (0.5, 0.5, 0, 0);
  352.       gtk_container_add (GTK_CONTAINER (align), frame);
  353.       gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
  354.  
  355.       /* demo_find_file() looks in the the current directory first,
  356.        * so you can run gtk-demo without installing GTK, then looks
  357.        * in the location where the file is installed.
  358.        */
  359.       pixbuf = NULL;
  360.       filename = demo_find_file ("gtk-logo-rgb.gif", &error);
  361.       if (filename)
  362.     {
  363.       pixbuf = gdk_pixbuf_new_from_file (filename, &error);
  364.       g_free (filename);
  365.     }
  366.  
  367.       if (error)
  368.     {
  369.       /* This code shows off error handling. You can just use
  370.        * gtk_image_new_from_file() instead if you don't want to report
  371.        * errors to the user. If the file doesn't load when using
  372.        * gtk_image_new_from_file(), a "missing image" icon will
  373.        * be displayed instead.
  374.        */
  375.       GtkWidget *dialog;
  376.       
  377.       dialog = gtk_message_dialog_new (GTK_WINDOW (window),
  378.                        GTK_DIALOG_DESTROY_WITH_PARENT,
  379.                        GTK_MESSAGE_ERROR,
  380.                        GTK_BUTTONS_CLOSE,
  381.                        "Unable to open image file 'gtk-logo-rgb.gif': %s",
  382.                        error->message);
  383.       g_error_free (error);
  384.       
  385.       g_signal_connect (dialog, "response",
  386.                 G_CALLBACK (gtk_widget_destroy), NULL);
  387.       
  388.       gtk_widget_show (dialog);
  389.     }
  390.       
  391.       image = gtk_image_new_from_pixbuf (pixbuf);
  392.  
  393.       gtk_container_add (GTK_CONTAINER (frame), image);
  394.  
  395.  
  396.       /* Animation */
  397.  
  398.       label = gtk_label_new (NULL);
  399.       gtk_label_set_markup (GTK_LABEL (label),
  400.                 "<u>Animation loaded from a file</u>");
  401.       gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  402.       
  403.       frame = gtk_frame_new (NULL);
  404.       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  405.       /* The alignment keeps the frame from growing when users resize
  406.        * the window
  407.        */
  408.       align = gtk_alignment_new (0.5, 0.5, 0, 0);
  409.       gtk_container_add (GTK_CONTAINER (align), frame);
  410.       gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
  411.  
  412.       filename = demo_find_file ("floppybuddy.gif", NULL);
  413.       image = gtk_image_new_from_file (filename);
  414.       g_free (filename);
  415.  
  416.       gtk_container_add (GTK_CONTAINER (frame), image);
  417.       
  418.  
  419.       /* Progressive */
  420.       
  421.       
  422.       label = gtk_label_new (NULL);
  423.       gtk_label_set_markup (GTK_LABEL (label),
  424.                 "<u>Progressive image loading</u>");
  425.       gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  426.       
  427.       frame = gtk_frame_new (NULL);
  428.       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  429.       /* The alignment keeps the frame from growing when users resize
  430.        * the window
  431.        */
  432.       align = gtk_alignment_new (0.5, 0.5, 0, 0);
  433.       gtk_container_add (GTK_CONTAINER (align), frame);
  434.       gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
  435.  
  436.       /* Create an empty image for now; the progressive loader
  437.        * will create the pixbuf and fill it in.
  438.        */
  439.       image = gtk_image_new_from_pixbuf (NULL);
  440.       gtk_container_add (GTK_CONTAINER (frame), image);
  441.  
  442.       start_progressive_loading (image);
  443.  
  444.       /* Sensitivity control */
  445.       button = gtk_toggle_button_new_with_mnemonic ("_Insensitive");
  446.       gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
  447.  
  448.       g_signal_connect (button, "toggled",
  449.                         G_CALLBACK (toggle_sensitivity_callback),
  450.                         vbox);
  451.     }
  452.  
  453.   if (!GTK_WIDGET_VISIBLE (window))
  454.     {
  455.       gtk_widget_show_all (window);
  456.     }
  457.   else
  458.     {
  459.       gtk_widget_destroy (window);
  460.       window = NULL;
  461.     }
  462.  
  463.   return window;
  464. }
  465.