home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / common / animationplay.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  47.2 KB  |  1,978 lines

  1. /*
  2.  * Animation Playback plug-in version 0.98.8
  3.  *
  4.  * (c) Adam D. Moss : 1997-2000 : adam@gimp.org : adam@foxbox.org
  5.  *
  6.  *
  7.  * This is part of the GIMP package and is released under the GNU
  8.  * Public License.
  9.  */
  10.  
  11. /*
  12.  * REVISION HISTORY:
  13.  *
  14.  * 2000-08-30 : version 0.98.8
  15.  *              Default frame timing is now 100ms instead of 125ms.
  16.  *
  17.  * 2000-06-05 : version 0.98.7
  18.  *              Fix old bug which could cause errors in evaluating the
  19.  *              final pixel of each composed layer.
  20.  *
  21.  * 2000-01-13 : version 0.98.6
  22.  *              Looser parsing of (XXXXX) layer-name tags
  23.  *
  24.  * 98.07.27 : version 0.98.5
  25.  *            UI tweaks, fix for pseudocolor displays w/gdkrgb.
  26.  *
  27.  * 98.07.20 : version 0.98.4
  28.  *            User interface improvements.
  29.  *
  30.  * 98.07.19 : version 0.98.2
  31.  *            Another speedup for some kinds of shaped animations.
  32.  *
  33.  * 98.07.19 : version 0.98.0
  34.  *            Adapted to use GDKRGB (from recent GTK >= 1.1) if
  35.  *            available - good speed and reliability improvement.
  36.  *            Plus some minor tweaks.
  37.  *
  38.  * 98.04.28 : version 0.94.2
  39.  *            Fixed a time-parsing bug.
  40.  *
  41.  * 98.04.05 : version 0.94.0
  42.  *            Improved performance and removed flicker when shaped.
  43.  *            Shaped mode also works with RGB* images now.
  44.  *            Fixed some longstanding potential visual debris.
  45.  *
  46.  * 98.04.04 : version 0.92.0
  47.  *            Improved responsiveness and performance for the new
  48.  *            shaped-animation mode.  Still some flicker.
  49.  *
  50.  * 98.04.02 : version 0.90.0
  51.  *            EXPERIMENTAL wackyness - try dragging the animation
  52.  *            out of the plugin dialog's preview box...
  53.  *            (only works on non-RGB* images for now)
  54.  *
  55.  * 98.03.16 : version 0.85.0
  56.  *            Implemented some more rare opaque/alpha combinations.
  57.  *
  58.  * 98.03.15 : version 0.84.0
  59.  *            Tried to clear up the GTK object/cast warnings.  Only
  60.  *            partially successful.  Could use some help.
  61.  *
  62.  * 97.12.11 : version 0.83.0
  63.  *            GTK's timer logic changed a little... adjusted
  64.  *            plugin to fit.
  65.  *
  66.  * 97.09.16 : version 0.81.7
  67.  *            Fixed progress bar's off-by-one problem with
  68.  *            the new timing.  Fixed erroneous black bars which
  69.  *            were sometimes visible when the first frame was
  70.  *            smaller than the image itself.  Made playback
  71.  *            controls inactive when image doesn't have multiple
  72.  *            frames.  Moved progress bar above control buttons,
  73.  *            it's less distracting there.  More cosmetic stuff.
  74.  *
  75.  * 97.09.15 : version 0.81.0
  76.  *            Now plays INDEXED and GRAY animations.
  77.  *
  78.  * 97.09.15 : version 0.75.0
  79.  *            Next frame is generated ahead of time - results
  80.  *            in more precise timing.
  81.  *
  82.  * 97.09.14 : version 0.70.0
  83.  *            Initial release.  RGB only.
  84.  */
  85.  
  86. /*
  87.  * BUGS:
  88.  *  Gets understandably upset if the source image is deleted
  89.  *    while the animation is playing.  Decent solution welcome.
  90.  *
  91.  *  In shaped mode, the shaped-window's mask and its pixmap contents
  92.  *    can get way out of sync (specifically, the mask changes but
  93.  *    the contents are frozen).  Starvation of GTK's redrawing thread?
  94.  *    How do I fix this?
  95.  *
  96.  *  Any more?  Let me know!
  97.  */
  98.  
  99. /*
  100.  * TODO:
  101.  *  pdb interface - should we bother?
  102.  *
  103.  *  speedups (caching?  most bottlenecks seem to be in pixelrgns)
  104.  *    -> do pixelrgns properly!
  105.  *
  106.  *  write other half of the user interface (default timing, disposal &c)
  107.  */
  108.  
  109. #include "config.h"
  110.  
  111. #include <stdlib.h>
  112. #include <stdio.h>
  113. #include <string.h>
  114. #include <ctype.h>
  115.  
  116. #include <gtk/gtk.h>
  117. #ifndef GDK_WINDOWING_WIN32
  118. #include <gdk/gdkx.h>
  119. #else
  120. #include <gdk/win32/gdkwin32.h>
  121. #endif
  122.  
  123. #include <libgimp/gimp.h>
  124. #include <libgimp/gimpui.h>
  125.  
  126. #include "libgimp/stdplugins-intl.h"
  127.  
  128.  
  129. /* Test for GTK1.2-style gdkrgb code, else use old 'preview' code. */
  130. #ifdef __GDK_RGB_H__
  131. #define RAPH_IS_HOME yep
  132. /* Dithertype for animated GIFs */
  133. #define DITHERTYPE GDK_RGB_DITHER_NORMAL
  134. #endif
  135.  
  136. /* #define I_AM_STUPID yesiam */
  137.  
  138. typedef enum
  139. {
  140.   DISPOSE_UNDEFINED = 0x00,
  141.   DISPOSE_COMBINE   = 0x01,
  142.   DISPOSE_REPLACE   = 0x02
  143. } DisposeType;
  144.  
  145.  
  146.  
  147. /* Declare local functions. */
  148. static void query (void);
  149. static void run   (gchar   *name,
  150.            gint     nparams,
  151.            GimpParam  *param,
  152.            gint    *nreturn_vals,
  153.            GimpParam **return_vals);
  154.  
  155. static        void do_playback        (void);
  156.  
  157. static gint window_delete_callback    (GtkWidget *widget,
  158.                        GdkEvent  *event,
  159.                        gpointer   data);
  160. static void window_close_callback     (GtkWidget *widget,
  161.                        gpointer   data);
  162. static void playstop_callback         (GtkWidget *widget,
  163.                        gpointer   data);
  164. static void rewind_callback           (GtkWidget *widget,
  165.                        gpointer   data);
  166. static void step_callback             (GtkWidget *widget,
  167.                        gpointer   data);
  168. #ifdef RAPH_IS_HOME
  169. static void repaint_sda               (GtkWidget *darea,
  170.                        gpointer data);
  171. static void repaint_da                (GtkWidget *darea,
  172.                        gpointer data);
  173. #endif
  174.  
  175. static void         render_frame        (gint32 whichframe);
  176. static void         show_frame          (void);
  177. static void         total_alpha_preview (guchar* ptr);
  178. static void         init_preview_misc   (void);
  179.  
  180.  
  181. /* tag util functions*/
  182. static         int parse_ms_tag        (const char *str);
  183. static DisposeType parse_disposal_tag  (const char *str);
  184. static DisposeType get_frame_disposal  (const guint whichframe);
  185. static     guint32 get_frame_duration  (const guint whichframe);
  186. static int is_disposal_tag (const char *str,
  187.                 DisposeType *disposal,
  188.                 int *taglength);
  189. static int is_ms_tag (const char *str,
  190.               int *duration,
  191.               int *taglength);
  192.  
  193.  
  194.  
  195.  
  196. GimpPlugInInfo PLUG_IN_INFO =
  197. {
  198.   NULL,  /* init_proc  */
  199.   NULL,  /* quit_proc  */
  200.   query, /* query_proc */
  201.   run,   /* run_proc   */
  202. };
  203.  
  204.  
  205. /* Global widgets'n'stuff */
  206. static guchar    *preview_data;
  207. #ifdef RAPH_IS_HOME
  208. static GtkWidget *drawing_area = NULL;
  209. static GtkWidget *shape_drawing_area = NULL;
  210. static guchar    *shape_drawing_area_data = NULL;
  211. static guchar    *drawing_area_data = NULL;
  212. #else
  213. static GtkPreview* preview = NULL;
  214. #endif
  215. static GtkProgressBar *progress;
  216. static guint           width, height;
  217. static guchar         *preview_alpha1_data;
  218. static guchar         *preview_alpha2_data;
  219. static gint32          image_id;
  220. static gint32          total_frames;
  221. static guint           frame_number;
  222. static gint32         *layers;
  223. static GimpDrawable      *drawable;
  224. static gboolean        playing = FALSE;
  225. static gint            timer = 0;
  226. static GimpImageBaseType      imagetype;
  227. static guchar         *palette;
  228. static gint            ncolours;
  229. static GtkWidget      *psbutton;
  230.  
  231. /* for shaping */
  232. static gchar      *shape_preview_mask;
  233. static GtkWidget  *shape_window;
  234. #ifdef RAPH_IS_HOME
  235. #else
  236. static GtkWidget  *shape_fixed;
  237. static GtkPreview *shape_preview;
  238. static GdkPixmap  *shape_pixmap;
  239. #endif
  240. typedef struct _cursoroffset {gint x,y;} CursorOffset;
  241. static gint        shaping = 0;
  242. static GdkWindow  *root_win = NULL;
  243.  
  244.  
  245. MAIN ()
  246.  
  247. static void 
  248. query (void)
  249. {
  250.   static GimpParamDef args[] =
  251.   {
  252.     { GIMP_PDB_INT32,    "run_mode", "Interactive, non-interactive" },
  253.     { GIMP_PDB_IMAGE,    "image",    "Input image" },
  254.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable (unused)" }
  255.   };
  256.   static gint nargs = sizeof (args) / sizeof (args[0]);
  257.  
  258.   gimp_install_procedure ("plug_in_animationplay",
  259.               "This plugin allows you to preview a GIMP layer-based animation.",
  260.               "",
  261.               "Adam D. Moss <adam@gimp.org>",
  262.               "Adam D. Moss <adam@gimp.org>",
  263.               "1997, 1998...",
  264.               N_("<Image>/Filters/Animation/Animation Playback..."),
  265.               "RGB*, INDEXED*, GRAY*",
  266.               GIMP_PLUGIN,
  267.               nargs, 0,
  268.               args, NULL);
  269. }
  270.  
  271. static void 
  272. run (gchar   *name, 
  273.      gint     n_params, 
  274.      GimpParam  *param, 
  275.      gint    *nreturn_vals,
  276.      GimpParam **return_vals)
  277. {
  278.   static GimpParam values[1];
  279.   GimpRunModeType run_mode;
  280.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  281.  
  282.   *nreturn_vals = 1;
  283.   *return_vals = values;
  284.  
  285.   run_mode = param[0].data.d_int32;
  286.  
  287.   if (run_mode == GIMP_RUN_NONINTERACTIVE) 
  288.     {
  289.       if (n_params != 3) 
  290.     {
  291.       status = GIMP_PDB_CALLING_ERROR;
  292.     }
  293.       INIT_I18N();
  294.     } 
  295.   else 
  296.     {
  297.       INIT_I18N_UI();
  298.     }
  299.  
  300.   if (status == GIMP_PDB_SUCCESS) 
  301.     {
  302.       image_id = param[1].data.d_image;
  303.       
  304.       do_playback();
  305.       
  306.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  307.     gimp_displays_flush();
  308.     }
  309.  
  310.   values[0].type = GIMP_PDB_STATUS;
  311.   values[0].data.d_status = status;
  312. }
  313.  
  314.  
  315.  
  316. /*
  317. static int
  318. parse_ms_tag (char *str)
  319. {
  320.   gint sum = 0;
  321.   gint offset = 0;
  322.   gint length;
  323.  
  324.   length = strlen(str);
  325.  
  326. find_another_bra:
  327.  
  328.   while ((offset<length) && (str[offset]!='('))
  329.     offset++;
  330.   
  331.   if (offset>=length)
  332.     return(-1);
  333.  
  334.   if (!isdigit(str[++offset]))
  335.     goto find_another_bra;
  336.  
  337.   do
  338.     {
  339.       sum *= 10;
  340.       sum += str[offset] - '0';
  341.       offset++;
  342.     }
  343.   while ((offset<length) && (isdigit(str[offset])));  
  344.  
  345.   if (length-offset <= 2)
  346.     return(-3);
  347.  
  348.   if ((toupper(str[offset]) != 'M') || (toupper(str[offset+1]) != 'S'))
  349.     return(-4);
  350.  
  351.   return (sum);
  352. }
  353.  
  354.  
  355. static DisposeType
  356. parse_disposal_tag (char *str)
  357. {
  358.   gint offset = 0;
  359.   gint length;
  360.  
  361.   length = strlen(str);
  362.  
  363.   while ((offset+9)<=length)
  364.     {
  365.       if (strncmp(&str[offset],"(combine)",9)==0) 
  366.     return(DISPOSE_COMBINE);
  367.       if (strncmp(&str[offset],"(replace)",9)==0) 
  368.     return(DISPOSE_REPLACE);
  369.       offset++;
  370.     }
  371.  
  372.   return (DISPOSE_UNDEFINED);
  373. }*/
  374.  
  375.  
  376. static void
  377. reshape_from_bitmap (gchar* bitmap)
  378. {
  379.   GdkBitmap *shape_mask;
  380.   static gchar *prev_bitmap = NULL;
  381.  
  382.   if ((!prev_bitmap) ||
  383.       (memcmp(prev_bitmap, bitmap, (width*height)/8 +height)))
  384.     {
  385.       shape_mask = gdk_bitmap_create_from_data(shape_window->window,
  386.                            bitmap,
  387.                            width, height);
  388.       gtk_widget_shape_combine_mask (shape_window, shape_mask, 0, 0);
  389.       gdk_bitmap_unref (shape_mask);
  390.  
  391.       if (!prev_bitmap)
  392.     {
  393.       prev_bitmap = g_malloc ((width*height)/8 +height);
  394.     }
  395.       memcpy (prev_bitmap, bitmap, (width*height)/8 +height);
  396.     }
  397. }
  398.  
  399.  
  400. static void
  401. shape_pressed (GtkWidget      *widget, 
  402.            GdkEventButton *event)
  403. {
  404.   CursorOffset *p;
  405.  
  406.   /* ignore double and triple click */
  407.   if (event->type != GDK_BUTTON_PRESS)
  408.     return;
  409.  
  410.   p = gtk_object_get_user_data (GTK_OBJECT(widget));
  411.   p->x = (int) event->x;
  412.   p->y = (int) event->y;
  413.  
  414.   gtk_grab_add (widget);
  415.   gdk_pointer_grab (widget->window, TRUE,
  416.                     GDK_BUTTON_RELEASE_MASK |
  417.                     GDK_BUTTON_MOTION_MASK |
  418.                     GDK_POINTER_MOTION_HINT_MASK,
  419.                     NULL, NULL, 0);
  420.   gdk_window_raise (widget->window);
  421. }
  422.  
  423.  
  424. #ifdef RAPH_IS_HOME
  425. static void
  426. maybeblocked_expose (GtkWidget      *widget, 
  427.              GdkEventExpose *event)
  428. {
  429.   if (playing)
  430.     gtk_signal_emit_stop_by_name (GTK_OBJECT(widget), "expose_event");
  431.   else
  432.     repaint_sda (widget, event);
  433. }
  434. #else
  435.  
  436.  
  437. static void
  438. blocked_expose (GtkWidget      *widget, 
  439.         GdkEventExpose *event)
  440. {
  441.   gtk_signal_emit_stop_by_name (GTK_OBJECT(widget), "expose_event");
  442. }
  443. #endif
  444.  
  445.  
  446. #ifdef I_AM_STUPID
  447. static void
  448. xblocked_expose (GtkWidget      *widget, 
  449.          GdkEventExpose *event)
  450. {
  451.   printf("eep!\n");fflush(stdout);
  452.   abort();
  453. }
  454.  
  455. static void
  456. unblocked_expose (GtkWidget      *widget, 
  457.           GdkEventExpose *event)
  458. {
  459.   gboolean should_block;
  460.   
  461.   printf("%p: t%d w:%p s:%d c:%d \n",widget, event->type, event->window,
  462.      event->send_event, event->count);
  463.   fflush(stdout);
  464.  
  465.   return;
  466.   
  467.   /*
  468.    * If the animation is playing, we only respond to exposures
  469.    * which are artificially generated as a result of i.e.
  470.    * draw_widget.  This is to avoid needlessly redrawing twice
  471.    * per frame, because also 'real' exposure events may be generated
  472.    * by reshaping the windoow.
  473.    *
  474.    * If the animation is not playing, then we respond to any type
  475.    * of expose event.
  476.    */
  477.      
  478.   if (playing)
  479.     should_block = (!event->send_event) || (event->count != 0);
  480.   else
  481.     should_block = FALSE;
  482.  
  483.   if (should_block)
  484.     {
  485.       /*
  486.        * Since a whole load of exposures can come back-to-back,
  487.        * starvation can occur for the dialog etc.  This alleviates
  488.        * the pain.
  489.        */
  490.       while (gtk_events_pending())
  491.     gtk_main_iteration_do(TRUE);
  492.  
  493.       /*
  494.        * Block the expose from being acted upon.
  495.        */
  496.       blocked_expose(widget, event);
  497.  
  498.       return;
  499.     }
  500. }
  501. #endif
  502.  
  503.  
  504. static void
  505. shape_released (GtkWidget *widget)
  506. {
  507.   gtk_grab_remove (widget);
  508.   gdk_pointer_ungrab (0);
  509.   gdk_flush();
  510. }
  511.  
  512.  
  513. static void
  514. shape_motion (GtkWidget      *widget,
  515.               GdkEventMotion *event)
  516. {
  517.   gint xp, yp;
  518.   CursorOffset * p;
  519.   GdkModifierType mask;
  520.  
  521.   gdk_window_get_pointer (root_win, &xp, &yp, &mask);
  522.  
  523.   /*  printf("%u %d\n", mask, event->state);fflush(stdout); */
  524.  
  525.   /* if a button is still held by the time we process this event... */
  526.   if (mask & (GDK_BUTTON1_MASK|
  527.           GDK_BUTTON2_MASK|
  528.           GDK_BUTTON3_MASK|
  529.           GDK_BUTTON4_MASK|
  530.           GDK_BUTTON5_MASK))
  531.     {
  532.       p = gtk_object_get_user_data (GTK_OBJECT (widget));
  533.  
  534.       gtk_widget_set_uposition (widget, xp  - p->x, yp  - p->y);
  535.     }
  536.   else /* the user has released all buttons */
  537.     {
  538.       shape_released(widget);
  539.     }
  540. }
  541.  
  542.  
  543. #ifdef RAPH_IS_HOME
  544. static void
  545. repaint_da (GtkWidget *darea, 
  546.         gpointer   data)
  547. {
  548.   /*  printf("Repaint!  Woohoo!\n");*/
  549.   gdk_draw_rgb_image (drawing_area->window,
  550.               drawing_area->style->white_gc,
  551.               0, 0, width, height,
  552.               (total_frames==1)?GDK_RGB_DITHER_MAX:DITHERTYPE,
  553.               drawing_area_data, width * 3);
  554. }
  555.  
  556.  
  557. static void
  558. repaint_sda (GtkWidget *darea, 
  559.          gpointer   data)
  560. {
  561.   /*printf("Repaint!  Woohoo!\n");*/
  562.   gdk_draw_rgb_image (shape_drawing_area->window,
  563.               shape_drawing_area->style->white_gc,
  564.               0, 0, width, height,
  565.               (total_frames==1)?GDK_RGB_DITHER_MAX:DITHERTYPE,
  566.               shape_drawing_area_data, width * 3);
  567. }
  568. #endif
  569.  
  570.  
  571. static void
  572. preview_pressed (GtkWidget      *widget, 
  573.          GdkEventButton *event)
  574. {
  575. #ifdef RAPH_IS_HOME
  576. #else
  577.   gint i;
  578. #endif
  579.   gint xp, yp;
  580.   GdkModifierType mask;
  581.  
  582.   if (shaping) return;
  583.   
  584. #ifdef RAPH_IS_HOME
  585.   /* Create a total-alpha buffer merely for the not-shaped
  586.      drawing area to now display. */
  587.  
  588.   drawing_area_data = g_malloc (width * height * 3);
  589.   total_alpha_preview (drawing_area_data);
  590.  
  591. #else
  592.   /* put current preview buf into shaped buf */
  593.   for (i=0;i<height;i++)
  594.     {
  595.       gtk_preview_draw_row (shape_preview,
  596.                 &preview_data[3*i*width],
  597.                 0, i, width);
  598.   }
  599.   total_alpha_preview (preview_data);
  600. #endif
  601.       
  602.   gdk_window_get_pointer (root_win, &xp, &yp, &mask);
  603.   gtk_widget_set_uposition (shape_window, xp  - event->x, yp  - event->y);
  604.   
  605.   gtk_widget_show (shape_window);
  606.  
  607.   gdk_window_set_back_pixmap(shape_window->window, NULL, 0);
  608. #ifdef RAPH_IS_HOME
  609.   gdk_window_set_back_pixmap(shape_drawing_area->window, NULL, 1);
  610. #else
  611.   gdk_window_set_back_pixmap(shape_fixed->window, NULL, 1);
  612. #endif
  613.  
  614. #ifdef RAPH_IS_HOME
  615. #else
  616.   for (i=0;i<height;i++)
  617.     {
  618.       gtk_preview_draw_row (preview,
  619.                 &preview_data[3*i*width],
  620.                 0, i, width);
  621.     }
  622. #endif
  623.   show_frame();
  624.  
  625.   shaping = 1;
  626.   memset(shape_preview_mask, 0, (width*height)/8 + height);
  627.   render_frame(frame_number);
  628.   show_frame();
  629.   
  630. #ifdef RAPH_IS_HOME
  631.   repaint_da (NULL,NULL);
  632. #endif
  633.  
  634.   /* mildly amusing hack */
  635.   shape_pressed(shape_window, event);
  636. }
  637.  
  638.  
  639.  
  640. static void
  641. build_dialog (GimpImageBaseType  basetype,
  642.           char       *imagename)
  643. {
  644.   gchar* windowname;
  645.   CursorOffset* icon_pos;
  646.   GtkAdjustment *adj;
  647.  
  648.   GtkWidget* dlg;
  649.   GtkWidget* button;
  650.   GtkWidget* frame;
  651.   GtkWidget* frame2;
  652.   GtkWidget* vbox;
  653.   GtkWidget* hbox;
  654.   GtkWidget* hbox2;
  655.   GtkWidget* eventbox;
  656.   GdkCursor* cursor;
  657.  
  658.   gimp_ui_init ("animationplay", TRUE);
  659.  
  660.   windowname = g_strconcat (_("Animation Playback: "), imagename, NULL);
  661.  
  662.   dlg = gimp_dialog_new (windowname, "animationplay",
  663.              gimp_standard_help_func, "filters/animationplay.html",
  664.              GTK_WIN_POS_MOUSE,
  665.              FALSE, TRUE, FALSE,
  666.  
  667.              _("Close"), window_close_callback,
  668.              NULL, 1, NULL, TRUE, TRUE,
  669.  
  670.              NULL);
  671.  
  672.   g_free (windowname);
  673.  
  674.   gtk_signal_connect (GTK_OBJECT (dlg), "delete_event",
  675.               GTK_SIGNAL_FUNC (window_delete_callback),
  676.               NULL);
  677.  
  678.   {
  679.     /* The 'playback' half of the dialog */
  680.     
  681.     windowname = g_malloc (strlen (_("Playback: ")) + strlen (imagename) + 1);
  682.     if (total_frames > 1)
  683.       {
  684.     strcpy (windowname, _("Playback: "));
  685.     strcat (windowname, imagename);
  686.       }
  687.     else
  688.       {
  689.     strcpy (windowname, imagename);    
  690.       }
  691.     frame = gtk_frame_new (windowname);
  692.     g_free (windowname);
  693.     gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  694.     gtk_container_set_border_width (GTK_CONTAINER (frame), 3);
  695.     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox),
  696.             frame, TRUE, TRUE, 0);
  697.     
  698.     {
  699.       hbox = gtk_hbox_new (FALSE, 5);
  700.       gtk_container_set_border_width (GTK_CONTAINER (hbox), 3);
  701.       gtk_container_add (GTK_CONTAINER (frame), hbox);
  702.       
  703.       {
  704.     vbox = gtk_vbox_new (FALSE, 5);
  705.     gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
  706.     gtk_container_add (GTK_CONTAINER (hbox), vbox);
  707.     
  708.     {
  709.       hbox2 = gtk_hbox_new (FALSE, 0);
  710.       gtk_container_set_border_width (GTK_CONTAINER (hbox2), 0);
  711.       gtk_box_pack_start (GTK_BOX (vbox), hbox2, TRUE, TRUE, 0);
  712.       
  713.       {
  714.         psbutton = gtk_toggle_button_new_with_label ( _("Play/Stop"));
  715.         gtk_signal_connect (GTK_OBJECT (psbutton), "toggled",
  716.                 (GtkSignalFunc) playstop_callback, NULL);
  717.         gtk_box_pack_start (GTK_BOX (hbox2), psbutton, TRUE, TRUE, 0);
  718.         gtk_widget_show (psbutton);
  719.         
  720.         button = gtk_button_new_with_label ( _("Rewind"));
  721.         gtk_signal_connect (GTK_OBJECT (button), "clicked",
  722.                 (GtkSignalFunc) rewind_callback, NULL);
  723.         gtk_box_pack_start (GTK_BOX (hbox2), button, TRUE, TRUE, 0);
  724.         gtk_widget_show (button);
  725.         
  726.         button = gtk_button_new_with_label ( _("Step"));
  727.         gtk_signal_connect (GTK_OBJECT (button), "clicked",
  728.                 (GtkSignalFunc) step_callback, NULL);
  729.         gtk_box_pack_start (GTK_BOX (hbox2), button, TRUE, TRUE, 0);
  730.         gtk_widget_show (button);
  731.       }
  732.       /* If there aren't multiple frames, playback controls make no
  733.          sense */
  734.       /*      if (total_frames<=1) gtk_widget_set_sensitive (hbox2, FALSE);
  735.       gtk_widget_show(hbox2);*/
  736.  
  737.       if (total_frames>1)
  738.         gtk_widget_show(hbox2);
  739.  
  740.       hbox2 = gtk_hbox_new (TRUE, 0);
  741.       gtk_container_set_border_width (GTK_CONTAINER (hbox2), 0);
  742.       gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, FALSE, 0);
  743.       {
  744.         frame2 = gtk_frame_new (NULL);
  745.         gtk_frame_set_shadow_type (GTK_FRAME (frame2), GTK_SHADOW_ETCHED_IN);
  746.         gtk_box_pack_start (GTK_BOX (hbox2), frame2, FALSE, FALSE, 0);
  747.         
  748.         {
  749.           eventbox = gtk_event_box_new();
  750.           gtk_container_add (GTK_CONTAINER (frame2), GTK_WIDGET (eventbox));
  751.           
  752.           {
  753. #ifdef RAPH_IS_HOME
  754.         drawing_area = gtk_drawing_area_new ();
  755.                 gtk_widget_set_usize (drawing_area, width, height);
  756.                 gtk_container_add (GTK_CONTAINER (eventbox),
  757.                                    GTK_WIDGET (drawing_area));
  758.                 gtk_widget_show (drawing_area);
  759. #else
  760.         preview =
  761.           GTK_PREVIEW (gtk_preview_new (GTK_PREVIEW_COLOR));/* FIXME */
  762.         gtk_preview_size (preview, width, height);
  763.         gtk_container_add (GTK_CONTAINER (eventbox),
  764.                    GTK_WIDGET (preview));
  765.         gtk_widget_show(GTK_WIDGET (preview));
  766. #endif
  767.           }
  768.           gtk_widget_show(eventbox);
  769.           gtk_widget_set_events (eventbox,
  770.                      gtk_widget_get_events (eventbox)
  771.                      | GDK_BUTTON_PRESS_MASK);
  772.         }
  773.         gtk_widget_show(frame2);
  774.       }
  775.       gtk_widget_show(hbox2);
  776.  
  777.  
  778.       adj = (GtkAdjustment *) gtk_adjustment_new (1, 1, total_frames,
  779.                               1, 1, 1);
  780.       progress = GTK_PROGRESS_BAR (gtk_progress_bar_new_with_adjustment
  781.                        (adj));
  782.       {
  783.         gtk_progress_set_format_string (GTK_PROGRESS (progress),
  784.                         _("Frame %v of %u"));
  785.         gtk_progress_set_show_text (GTK_PROGRESS (progress), TRUE);
  786.         /*      gtk_widget_set_usize (GTK_WIDGET (progress), 150, 15);*/
  787.         gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (progress),
  788.                 TRUE, TRUE, 0);
  789.       }
  790.       if (total_frames>1)
  791.         gtk_widget_show (GTK_WIDGET (progress));
  792.     }
  793.     gtk_widget_show(vbox);
  794.     
  795.       }
  796.       gtk_widget_show(hbox);
  797.       
  798.     }
  799.     gtk_widget_show(frame);
  800.     
  801.   }
  802.   gtk_widget_show(dlg);
  803.  
  804.  
  805.   /* let's get into shape. */
  806.   shape_window = gtk_window_new (GTK_WINDOW_POPUP);
  807.   {
  808. #ifdef RAPH_IS_HOME
  809.     shape_drawing_area = gtk_drawing_area_new ();
  810.     {
  811.       gtk_widget_set_usize (shape_drawing_area, width, height);
  812.       gtk_container_add (GTK_CONTAINER (shape_window), shape_drawing_area);
  813.     }
  814.     gtk_widget_show (shape_drawing_area);
  815.     gtk_widget_set_events (shape_drawing_area,
  816.                gtk_widget_get_events (shape_drawing_area)
  817.                | GDK_BUTTON_PRESS_MASK);
  818. #else
  819.     shape_fixed = gtk_fixed_new ();
  820.     {
  821.       gtk_widget_set_usize (shape_fixed, width,height);
  822.       gtk_container_add (GTK_CONTAINER (shape_window), shape_fixed);
  823.  
  824.       shape_preview =
  825.     GTK_PREVIEW (gtk_preview_new (GTK_PREVIEW_COLOR)); /* FIXME */
  826.       {
  827.     gtk_preview_size (shape_preview, width, height);
  828.       }
  829.     }
  830.     gtk_widget_show (shape_fixed);
  831. #endif
  832.     gtk_widget_realize (shape_window);
  833.  
  834. #ifdef RAPH_IS_HOME
  835. #else
  836.     shape_pixmap = gdk_pixmap_new (shape_window->window,
  837.                    width, height,
  838.                    gtk_preview_get_visual()->depth);
  839. #endif
  840.     
  841.     gdk_window_set_back_pixmap(shape_window->window, NULL, 0);
  842.  
  843.     cursor = gdk_cursor_new (GDK_CENTER_PTR);
  844.     gdk_window_set_cursor(shape_window->window, cursor);
  845.     gdk_cursor_destroy (cursor);
  846.  
  847.     gtk_signal_connect (GTK_OBJECT (shape_window), "button_press_event",
  848.             GTK_SIGNAL_FUNC (shape_pressed),NULL);
  849.     gtk_signal_connect (GTK_OBJECT (shape_window), "button_release_event",
  850.             GTK_SIGNAL_FUNC (shape_released),NULL);
  851.     gtk_signal_connect (GTK_OBJECT (shape_window), "motion_notify_event",
  852.             GTK_SIGNAL_FUNC (shape_motion),NULL);
  853.  
  854.     icon_pos = g_new (CursorOffset, 1);
  855.     gtk_object_set_user_data(GTK_OBJECT(shape_window), icon_pos);
  856.   }
  857.   /*  gtk_widget_show (shape_window);*/
  858.  
  859.   gtk_signal_connect (GTK_OBJECT (eventbox), "button_press_event",
  860.               GTK_SIGNAL_FUNC (preview_pressed),NULL);
  861.  
  862. #ifdef I_AM_STUPID
  863.   gtk_signal_connect (GTK_OBJECT (shape_window), "expose_event",
  864.               GTK_SIGNAL_FUNC (unblocked_expose),shape_window);
  865. #endif
  866.  
  867. #ifdef RAPH_IS_HOME
  868.   gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
  869.               GTK_SIGNAL_FUNC (repaint_da), drawing_area);
  870.  
  871.   gtk_signal_connect (GTK_OBJECT (shape_drawing_area), "expose_event",
  872.               GTK_SIGNAL_FUNC (maybeblocked_expose),
  873.               shape_drawing_area);
  874. #else
  875.   gtk_signal_connect (GTK_OBJECT (shape_fixed), "expose_event",
  876.               GTK_SIGNAL_FUNC (blocked_expose),shape_fixed);
  877. #endif
  878.  
  879.   root_win = gdk_window_foreign_new (GDK_ROOT_WINDOW ());
  880. }
  881.  
  882.  
  883.  
  884. static void 
  885. do_playback (void)
  886. {
  887.   int i;
  888.  
  889.   width     = gimp_image_width(image_id);
  890.   height    = gimp_image_height(image_id);
  891.   layers    = gimp_image_get_layers (image_id, &total_frames);
  892.   imagetype = gimp_image_base_type(image_id);
  893.  
  894.   if (imagetype == GIMP_INDEXED)
  895.     palette = gimp_image_get_cmap(image_id, &ncolours);
  896.   else if (imagetype == GIMP_GRAY)
  897.     {
  898.       /* This is a bit sick, until this plugin ever gets
  899.      real GRAY support (not worth it?) */
  900.       palette = g_malloc(768);
  901.       for (i=0;i<256;i++)
  902.       {
  903.           palette[i*3] = palette[i*3+1] = palette[i*3+2] = i;
  904.       }
  905.       ncolours = 256;
  906.     }
  907.  
  908.  
  909.   frame_number = 0;
  910.   
  911.   /* cache hint "cache nothing", since we iterate over every
  912.      tile in every layer. */
  913.   gimp_tile_cache_size (0);
  914.  
  915.   init_preview_misc();
  916.  
  917.   build_dialog(gimp_image_base_type(image_id),
  918.                gimp_image_get_filename(image_id));
  919.  
  920.   /* Make sure that whole preview is dirtied with pure-alpha */
  921.   total_alpha_preview(preview_data);
  922.  
  923. #ifdef RAPH_IS_HOME
  924.   /*  gdk_draw_rgb_image (drawing_area->window,
  925.               drawing_area->style->white_gc,
  926.               0, 0, width, height,
  927.               DITHERTYPE,
  928.               preview_data, width * 3);*/
  929. #else
  930.   for (i=0;i<height;i++)
  931.   {
  932.     gtk_preview_draw_row (preview,
  933.                           &preview_data[3*i*width],
  934.                           0, i, width);
  935.   }
  936. #endif
  937.   
  938.   render_frame(0);
  939.   show_frame();
  940.  
  941.   gtk_main ();
  942.   gdk_flush ();
  943. }
  944.  
  945.  
  946. /* Rendering Functions */
  947.  
  948. static void
  949. render_frame (gint32 whichframe)
  950. {
  951.   GimpPixelRgn pixel_rgn;
  952.   static guchar *rawframe = NULL;
  953.   static gint rawwidth=0, rawheight=0, rawbpp=0;
  954.   gint rawx=0, rawy=0;
  955.   guchar* srcptr;
  956.   guchar* destptr;
  957.   gint i,j,k; /* imaginative loop variables */
  958.   DisposeType dispose;
  959.  
  960.  
  961.   if (whichframe >= total_frames)
  962.     {
  963.       printf( "playback: Asked for frame number %d in a %d-frame animation!\n",
  964.          (int) (whichframe+1), (int) total_frames);
  965.       exit(-1);
  966.     }
  967.  
  968.   drawable = gimp_drawable_get (layers[total_frames-(whichframe+1)]);
  969.   /* Lame attempt to catch the case that a user has closed the image. */
  970.   if (! (drawable->width > 0 && drawable->height > 0))
  971.     {
  972.       gtk_main_quit ();
  973.       return;
  974.     }
  975.  
  976.   dispose = get_frame_disposal(frame_number);
  977.  
  978.   /* Image has been closed/etc since we got the layer list? */
  979.   /* FIXME - How do we tell if a gimp_drawable_get() fails? */
  980.   if (gimp_drawable_width(drawable->id)==0)
  981.     window_close_callback (NULL, NULL);
  982.  
  983.   if (((dispose==DISPOSE_REPLACE)||(whichframe==0)) &&
  984.       gimp_drawable_has_alpha(drawable->id))
  985.     {
  986.       total_alpha_preview(preview_data);
  987.     }
  988.  
  989.  
  990.   /* only get a new 'raw' drawable-data buffer if this and
  991.      the previous raw buffer were different sizes*/
  992.  
  993.   if ((rawwidth*rawheight*rawbpp)
  994.       !=
  995.       ((gimp_drawable_width(drawable->id)*
  996.     gimp_drawable_height(drawable->id)*
  997.     gimp_drawable_bpp(drawable->id))))
  998.     {
  999.       if (rawframe != NULL) g_free(rawframe);
  1000.       rawframe = g_malloc((gimp_drawable_width(drawable->id)) *
  1001.               (gimp_drawable_height(drawable->id)) *
  1002.               (gimp_drawable_bpp(drawable->id)));
  1003.     }
  1004.     
  1005.   rawwidth = gimp_drawable_width(drawable->id);
  1006.   rawheight = gimp_drawable_height(drawable->id);
  1007.   rawbpp = gimp_drawable_bpp(drawable->id);
  1008.  
  1009.  
  1010.   /* Initialise and fetch the whole raw new frame */
  1011.  
  1012.   gimp_pixel_rgn_init (&pixel_rgn,
  1013.                drawable,
  1014.                0, 0,
  1015.                drawable->width, drawable->height,
  1016.                FALSE,
  1017.                FALSE);
  1018.   gimp_pixel_rgn_get_rect (&pixel_rgn,
  1019.                rawframe,
  1020.                0, 0,
  1021.                drawable->width, drawable->height);
  1022.   /*  gimp_pixel_rgns_register (1, &pixel_rgn);*/
  1023.  
  1024.   gimp_drawable_offsets (drawable->id,
  1025.              &rawx,
  1026.              &rawy);
  1027.  
  1028.  
  1029.   /* render... */
  1030.  
  1031.   switch (imagetype)
  1032.     {
  1033.     case GIMP_RGB:
  1034.       if ((rawwidth==width) &&
  1035.       (rawheight==height) &&
  1036.       (rawx==0) &&
  1037.       (rawy==0))
  1038.     {
  1039.       /* --- These cases are for the best cases,  in        --- */
  1040.       /* --- which this frame is the same size and position --- */
  1041.       /* --- as the preview buffer itself                   --- */
  1042.       
  1043.       if (gimp_drawable_has_alpha (drawable->id))
  1044.         { /* alpha */
  1045.           destptr = preview_data;
  1046.           srcptr  = rawframe;
  1047.           
  1048.           i = rawwidth*rawheight;
  1049.           while (i--)
  1050.         {
  1051.           if (!(*(srcptr+3)&128))
  1052.             {
  1053.               srcptr  += 4;
  1054.               destptr += 3;
  1055.               continue;
  1056.             }
  1057.           *(destptr++) = *(srcptr++);
  1058.           *(destptr++) = *(srcptr++);
  1059.           *(destptr++) = *(srcptr++);
  1060.           srcptr++;
  1061.         }
  1062.  
  1063.           /* calculate the shape mask */
  1064.           if (shaping)
  1065.         {
  1066.           srcptr = rawframe + 3;
  1067.           for (j=0;j<rawheight;j++)
  1068.             {
  1069.               k = j * ((7 + rawwidth) / 8);
  1070.               for (i=0;i<rawwidth;i++)
  1071.             {
  1072.               if ((*srcptr)&128)
  1073.                 shape_preview_mask[k+i/8] |= (1<<(i&7));
  1074.  
  1075.               srcptr += 4;
  1076.             }
  1077.             }
  1078.         }
  1079.         }
  1080.       else /* no alpha */
  1081.         {
  1082.           if ((rawwidth==width)&&(rawheight==height))
  1083.         {
  1084.           /*printf("quickie\n");fflush(stdout);*/
  1085.           memcpy(preview_data, rawframe, width*height*3);
  1086.         }
  1087.  
  1088.           if (shaping)
  1089.         {
  1090.           /* opacify the shape mask */
  1091.           memset(shape_preview_mask, 255,
  1092.              (rawwidth*rawheight)/8 + rawheight);
  1093.         }
  1094.         }
  1095.       /* Display the preview buffer... finally. */
  1096.       if (shaping)
  1097.         {
  1098. #ifdef RAPH_IS_HOME
  1099.           reshape_from_bitmap (shape_preview_mask);
  1100.           gdk_draw_rgb_image (shape_drawing_area->window,
  1101.                   shape_drawing_area->style->white_gc,
  1102.                   0, 0, width, height,
  1103.                   (total_frames==1)?GDK_RGB_DITHER_MAX
  1104.                   :DITHERTYPE,
  1105.                   preview_data, width * 3);
  1106. #else
  1107.           for (i=0;i<height;i++)
  1108.         {
  1109.           gtk_preview_draw_row (shape_preview,
  1110.                     &preview_data[3*i*width],
  1111.                     0, i, width);
  1112.         }
  1113. #endif
  1114.         }
  1115.       else
  1116.         {
  1117. #ifdef RAPH_IS_HOME
  1118.           reshape_from_bitmap (shape_preview_mask);
  1119.           gdk_draw_rgb_image (drawing_area->window,
  1120.                   drawing_area->style->white_gc,
  1121.                   0, 0, width, height,
  1122.                   (total_frames==1)?GDK_RGB_DITHER_MAX
  1123.                   :DITHERTYPE,
  1124.                   preview_data, width * 3);
  1125. #else
  1126.           for (i=0;i<height;i++)
  1127.         {
  1128.           gtk_preview_draw_row (preview,
  1129.                     &preview_data[3*i*width],
  1130.                     0, i, width);
  1131.         }
  1132. #endif
  1133.         }
  1134.     }
  1135.       else
  1136.     {
  1137.       /* --- These are suboptimal catch-all cases for when  --- */
  1138.       /* --- this frame is bigger/smaller than the preview  --- */
  1139.       /* --- buffer, and/or offset within it.               --- */
  1140.       
  1141.       if (gimp_drawable_has_alpha (drawable->id))
  1142.         { /* alpha */
  1143.           
  1144.           srcptr = rawframe;
  1145.           
  1146.           for (j=rawy; j<rawheight+rawy; j++)
  1147.         {
  1148.           for (i=rawx; i<rawwidth+rawx; i++)
  1149.             {
  1150.               if ((i>=0 && i<width) &&
  1151.               (j>=0 && j<height))
  1152.             {
  1153.               if (*(srcptr+3)&128)
  1154.                 {
  1155.                   preview_data[(j*width+i)*3   ] = *(srcptr);
  1156.                   preview_data[(j*width+i)*3 +1] = *(srcptr+1);
  1157.                   preview_data[(j*width+i)*3 +2] = *(srcptr+2);
  1158.                 }
  1159.             }
  1160.               
  1161.               srcptr += 4;
  1162.             }
  1163.         }
  1164.           
  1165.           if (shaping)
  1166.         {
  1167.           srcptr = rawframe + 3;
  1168.           for (j=rawy; j<rawheight+rawy; j++)
  1169.             {
  1170.               k = j * ((width+7)/8);
  1171.               for (i=rawx; i<rawwidth+rawx; i++)
  1172.             {
  1173.               if ((i>=0 && i<width) &&
  1174.                   (j>=0 && j<height))
  1175.                 {
  1176.                   if ((*srcptr)&128)
  1177.                 shape_preview_mask[k+i/8] |= (1<<(i&7));
  1178.                 }
  1179.               srcptr += 4;
  1180.             }
  1181.             }
  1182.         }
  1183.         }
  1184.       else
  1185.         {
  1186.           /* noalpha */
  1187.           
  1188.           srcptr = rawframe;
  1189.           
  1190.           for (j=rawy; j<rawheight+rawy; j++)
  1191.         {
  1192.           for (i=rawx; i<rawwidth+rawx; i++)
  1193.             {
  1194.               if ((i>=0 && i<width) &&
  1195.               (j>=0 && j<height))
  1196.             {
  1197.               preview_data[(j*width+i)*3   ] = *(srcptr);
  1198.               preview_data[(j*width+i)*3 +1] = *(srcptr+1);
  1199.               preview_data[(j*width+i)*3 +2] = *(srcptr+2);
  1200.             }
  1201.               
  1202.               srcptr += 3;
  1203.             }
  1204.         }
  1205.         }
  1206.       
  1207.       /* Display the preview buffer... finally. */
  1208.       if (shaping)
  1209.         {
  1210.           if ((dispose!=DISPOSE_REPLACE)&&(whichframe!=0))
  1211.         {
  1212. #ifdef RAPH_IS_HOME
  1213.           int top, bottom;
  1214.  
  1215.           top = (rawy < 0) ? 0 : rawy;
  1216.           bottom = (rawy+rawheight) < height ?
  1217.             (rawy+rawheight) : height-1;
  1218.  
  1219.           reshape_from_bitmap (shape_preview_mask);
  1220.           gdk_draw_rgb_image (shape_drawing_area->window,
  1221.                       shape_drawing_area->style->white_gc,
  1222.                       0, top, width, bottom-top,
  1223.                       (total_frames==1)?GDK_RGB_DITHER_MAX
  1224.                       :DITHERTYPE,
  1225.                       &preview_data[3*top*width], width * 3);
  1226. #else
  1227.           for (i=rawy;i<rawy+rawheight;i++)
  1228.             {
  1229.               if (i>=0 && i<height)
  1230.             gtk_preview_draw_row (shape_preview,
  1231.                           &preview_data[3*i*width],
  1232.                           0, i, width);
  1233.             }
  1234. #endif
  1235.         }
  1236.           else
  1237.         {
  1238. #ifdef RAPH_IS_HOME
  1239.           reshape_from_bitmap (shape_preview_mask);
  1240.           gdk_draw_rgb_image (shape_drawing_area->window,
  1241.                       shape_drawing_area->style->white_gc,
  1242.                       0, 0, width, height,
  1243.                       (total_frames==1)?GDK_RGB_DITHER_MAX
  1244.                       :DITHERTYPE,
  1245.                       preview_data, width * 3);
  1246. #else
  1247.           for (i=0;i<height;i++)
  1248.             {
  1249.               gtk_preview_draw_row (shape_preview,
  1250.                         &preview_data[3*i*width],
  1251.                         0, i, width);
  1252.             }
  1253. #endif
  1254.         }
  1255.         }
  1256.       else
  1257.         {
  1258.           if ((dispose!=DISPOSE_REPLACE)&&(whichframe!=0))
  1259.         {
  1260. #ifdef RAPH_IS_HOME
  1261.           int top, bottom;
  1262.  
  1263.           top = (rawy < 0) ? 0 : rawy;
  1264.           bottom = (rawy+rawheight) < height ?
  1265.             (rawy+rawheight) : height-1;
  1266.  
  1267.           gdk_draw_rgb_image (drawing_area->window,
  1268.                       drawing_area->style->white_gc,
  1269.                       0, top, width, bottom-top,
  1270.                       (total_frames==1)?GDK_RGB_DITHER_MAX
  1271.                       :DITHERTYPE,
  1272.                       &preview_data[3*top*width], width * 3);
  1273. #else
  1274.           for (i=rawy;i<rawy+rawheight;i++)
  1275.             {
  1276.               if (i>=0 && i<height)
  1277.             gtk_preview_draw_row (preview,
  1278.                           &preview_data[3*i*width],
  1279.                           0, i, width);
  1280.             }
  1281. #endif
  1282.         }
  1283.           else
  1284.         {
  1285. #ifdef RAPH_IS_HOME
  1286.           gdk_draw_rgb_image (drawing_area->window,
  1287.                       drawing_area->style->white_gc,
  1288.                       0, 0, width, height,
  1289.                       (total_frames==1)?GDK_RGB_DITHER_MAX:
  1290.                       DITHERTYPE,
  1291.                       preview_data, width * 3);
  1292. #else
  1293.           for (i=0;i<height;i++)
  1294.             {
  1295.               gtk_preview_draw_row (preview,
  1296.                         &preview_data[3*i*width],
  1297.                         0, i, width);
  1298.             }
  1299. #endif
  1300.         }
  1301.         }
  1302.     }
  1303.       break;
  1304.  
  1305.     case GIMP_GRAY:
  1306.     case GIMP_INDEXED:
  1307.       if ((rawwidth==width) &&
  1308.       (rawheight==height) &&
  1309.       (rawx==0) &&
  1310.       (rawy==0))
  1311.     {
  1312.       /* --- These cases are for the best cases,  in        --- */
  1313.       /* --- which this frame is the same size and position --- */
  1314.       /* --- as the preview buffer itself                   --- */
  1315.       
  1316.       if (gimp_drawable_has_alpha (drawable->id))
  1317.         { /* alpha */
  1318.           destptr = preview_data;
  1319.           srcptr  = rawframe;
  1320.           
  1321.           i = rawwidth*rawheight;
  1322.           while (i--)
  1323.         {
  1324.           if (!(*(srcptr+1)))
  1325.             {
  1326.               srcptr  += 2;
  1327.               destptr += 3;
  1328.               continue;
  1329.             }
  1330.           
  1331.           *(destptr++) = palette[3*(*(srcptr))];
  1332.           *(destptr++) = palette[1+3*(*(srcptr))];
  1333.           *(destptr++) = palette[2+3*(*(srcptr))];
  1334.           srcptr+=2;
  1335.         }
  1336.  
  1337.           /* calculate the shape mask */
  1338.           if (shaping)
  1339.         {
  1340.           srcptr = rawframe + 1;
  1341.           for (j=0;j<rawheight;j++)
  1342.             {
  1343.               k = j * ((7 + rawwidth) / 8);
  1344.               for (i=0;i<rawwidth;i++)
  1345.             {
  1346.               if (*srcptr)
  1347.                 shape_preview_mask[k+i/8] |= (1<<(i&7));
  1348.               srcptr += 2;
  1349.             }
  1350.             }
  1351.         }
  1352.         }
  1353.       else /* no alpha */
  1354.         {
  1355.           destptr = preview_data;
  1356.           srcptr  = rawframe;
  1357.           
  1358.           i = rawwidth*rawheight;
  1359.           while (--i)
  1360.         {
  1361.           *(destptr++) = palette[3*(*(srcptr))];
  1362.           *(destptr++) = palette[1+3*(*(srcptr))];
  1363.           *(destptr++) = palette[2+3*(*(srcptr))];
  1364.           srcptr++;
  1365.         }
  1366.  
  1367.           if (shaping)
  1368.         {
  1369.           /* opacify the shape mask */
  1370.           memset(shape_preview_mask, 255,
  1371.              (rawwidth*rawheight)/8 + rawheight);
  1372.         }
  1373.         }
  1374.       
  1375.       /* Display the preview buffer... finally. */
  1376.       if (shaping)
  1377.         {
  1378. #ifdef RAPH_IS_HOME
  1379.           reshape_from_bitmap (shape_preview_mask);
  1380.           gdk_draw_rgb_image (shape_drawing_area->window,
  1381.                   shape_drawing_area->style->white_gc,
  1382.                   0, 0, width, height,
  1383.                   (total_frames==1)?GDK_RGB_DITHER_MAX:
  1384.                   DITHERTYPE,
  1385.                   preview_data, width * 3);
  1386. #else
  1387.           for (i=0;i<height;i++)
  1388.         {
  1389.           gtk_preview_draw_row (shape_preview,
  1390.                     &preview_data[3*i*width],
  1391.                     0, i, width);
  1392.         }
  1393. #endif
  1394.         }
  1395.       else
  1396.         {
  1397. #ifdef RAPH_IS_HOME
  1398.           gdk_draw_rgb_image (drawing_area->window,
  1399.                   drawing_area->style->white_gc,
  1400.                   0, 0, width, height,
  1401.                   (total_frames==1)?GDK_RGB_DITHER_MAX:
  1402.                   DITHERTYPE,
  1403.                   preview_data, width * 3);
  1404. #else
  1405.           for (i=0;i<height;i++)
  1406.         {
  1407.           gtk_preview_draw_row (preview,
  1408.                     &preview_data[3*i*width],
  1409.                     0, i, width);
  1410.         }
  1411. #endif
  1412.         }
  1413.     }
  1414.       else
  1415.     {
  1416.       /* --- These are suboptimal catch-all cases for when  --- */
  1417.       /* --- this frame is bigger/smaller than the preview  --- */
  1418.       /* --- buffer, and/or offset within it.               --- */
  1419.       
  1420.       if (gimp_drawable_has_alpha (drawable->id))
  1421.         { /* alpha */
  1422.           
  1423.           srcptr = rawframe;
  1424.           
  1425.           for (j=rawy; j<rawheight+rawy; j++)
  1426.         {
  1427.           for (i=rawx; i<rawwidth+rawx; i++)
  1428.             {
  1429.               if ((i>=0 && i<width) &&
  1430.               (j>=0 && j<height))
  1431.             {
  1432.               if (*(srcptr+1))
  1433.                 {
  1434.                   preview_data[(j*width+i)*3   ] =
  1435.                 palette[3*(*(srcptr))];
  1436.                   preview_data[(j*width+i)*3 +1] =
  1437.                 palette[1+3*(*(srcptr))];
  1438.                   preview_data[(j*width+i)*3 +2] =
  1439.                 palette[2+3*(*(srcptr))];
  1440.                 }
  1441.             }
  1442.               
  1443.               srcptr += 2;
  1444.             }
  1445.         }
  1446.           
  1447.           if (shaping)
  1448.         {
  1449.           srcptr = rawframe + 1;
  1450.           for (j=rawy; j<rawheight+rawy; j++)
  1451.             {
  1452.               k = j * ((width+7)/8);
  1453.               for (i=rawx; i<rawwidth+rawx; i++)
  1454.             {
  1455.               if ((i>=0 && i<width) &&
  1456.                   (j>=0 && j<height))
  1457.                 {
  1458.                   if (*srcptr)
  1459.                 shape_preview_mask[k+i/8] |= (1<<(i&7));
  1460.                 }
  1461.               srcptr += 2;
  1462.             }
  1463.             }
  1464.         }
  1465.         }
  1466.       else
  1467.         {
  1468.           /* noalpha */
  1469.  
  1470.           srcptr = rawframe;
  1471.           
  1472.           for (j=rawy; j<rawheight+rawy; j++)
  1473.         {
  1474.           for (i=rawx; i<rawwidth+rawx; i++)
  1475.             {
  1476.               if ((i>=0 && i<width) &&
  1477.               (j>=0 && j<height))
  1478.             {
  1479.               preview_data[(j*width+i)*3   ] =
  1480.                 palette[3*(*(srcptr))];
  1481.               preview_data[(j*width+i)*3 +1] =
  1482.                 palette[1+3*(*(srcptr))];
  1483.               preview_data[(j*width+i)*3 +2] =
  1484.                 palette[2+3*(*(srcptr))];
  1485.             }
  1486.               
  1487.               srcptr ++;
  1488.             }
  1489.         }
  1490.         }
  1491.       
  1492.       /* Display the preview buffer... finally. */
  1493.       if (shaping)
  1494.         {
  1495.           if ((dispose!=DISPOSE_REPLACE)&&(whichframe!=0))
  1496.         {
  1497. #ifdef RAPH_IS_HOME
  1498.           int top, bottom;
  1499.  
  1500.           top = (rawy < 0) ? 0 : rawy;
  1501.           bottom = (rawy+rawheight) < height ?
  1502.             (rawy+rawheight) : height-1;
  1503.  
  1504.           reshape_from_bitmap (shape_preview_mask);
  1505.           gdk_draw_rgb_image (shape_drawing_area->window,
  1506.                       shape_drawing_area->style->white_gc,
  1507.                       0, top, width, bottom-top,
  1508.                       (total_frames==1)?GDK_RGB_DITHER_MAX
  1509.                       :DITHERTYPE,
  1510.                       &preview_data[3*top*width], width * 3);
  1511. #else
  1512.           for (i=rawy;i<rawy+rawheight;i++)
  1513.             {
  1514.               if (i>=0 && i<height)
  1515.             gtk_preview_draw_row (shape_preview,
  1516.                           &preview_data[3*i*width],
  1517.                           0, i, width);
  1518.             }
  1519. #endif
  1520.         }
  1521.           else
  1522.         {
  1523. #ifdef RAPH_IS_HOME
  1524.           reshape_from_bitmap (shape_preview_mask);
  1525.           gdk_draw_rgb_image (shape_drawing_area->window,
  1526.                       shape_drawing_area->style->white_gc,
  1527.                       0, 0, width, height,
  1528.                       (total_frames==1)?GDK_RGB_DITHER_MAX
  1529.                       :DITHERTYPE,
  1530.                       preview_data, width * 3);
  1531. #else
  1532.           for (i=0;i<height;i++)
  1533.             {
  1534.               gtk_preview_draw_row (shape_preview,
  1535.                         &preview_data[3*i*width],
  1536.                         0, i, width);
  1537.             }
  1538. #endif
  1539.         }
  1540.         }
  1541.       else
  1542.         {
  1543.           if ((dispose!=DISPOSE_REPLACE)&&(whichframe!=0))
  1544.         {
  1545. #ifdef RAPH_IS_HOME
  1546.           int top, bottom;
  1547.  
  1548.           top = (rawy < 0) ? 0 : rawy;
  1549.           bottom = (rawy+rawheight) < height ?
  1550.             (rawy+rawheight) : height-1;
  1551.  
  1552.           gdk_draw_rgb_image (drawing_area->window,
  1553.                       drawing_area->style->white_gc,
  1554.                       0, top, width, bottom-top,
  1555.                       (total_frames==1)?GDK_RGB_DITHER_MAX
  1556.                       :DITHERTYPE,
  1557.                       &preview_data[3*top*width], width * 3);
  1558. #else
  1559.           for (i=rawy;i<rawy+rawheight;i++)
  1560.             {
  1561.               if (i>=0 && i<height)
  1562.             gtk_preview_draw_row (preview,
  1563.                           &preview_data[3*i*width],
  1564.                           0, i, width);
  1565.             }
  1566. #endif
  1567.         }
  1568.           else
  1569.         {
  1570. #ifdef RAPH_IS_HOME
  1571.           gdk_draw_rgb_image (drawing_area->window,
  1572.                       drawing_area->style->white_gc,
  1573.                       0, 0, width, height,
  1574.                       (total_frames==1)?GDK_RGB_DITHER_MAX
  1575.                       :DITHERTYPE,
  1576.                       preview_data, width * 3);
  1577. #else
  1578.           for (i=0;i<height;i++)
  1579.             {
  1580.               gtk_preview_draw_row (preview,
  1581.                         &preview_data[3*i*width],
  1582.                         0, i, width);
  1583.             }
  1584. #endif
  1585.         }
  1586.         }
  1587.     }
  1588.       break;
  1589.       
  1590.     }
  1591.  
  1592.   /* clean up */  
  1593.   gimp_drawable_detach(drawable);
  1594. }
  1595.  
  1596.  
  1597. /* If we're using GDKRGB, we don't reshape in this function because
  1598.    it's too late (GDKRGB is synchronous).  So this just updates the
  1599.    progress bar. */
  1600. static void
  1601. show_frame (void)
  1602. {
  1603. #ifndef RAPH_IS_HOME
  1604.   GdkGC *gc;
  1605.  
  1606.   /* Tell GTK to physically draw the preview */
  1607.   if (!shaping)
  1608.     {
  1609.       gtk_widget_draw (GTK_WIDGET (preview), NULL);
  1610.     }
  1611.  
  1612.   if (shaping)
  1613.     {
  1614.       /* Try to avoid starvation of UI events */
  1615.       while (gtk_events_pending())
  1616.     gtk_main_iteration_do(TRUE);
  1617.  
  1618.       gc = gdk_gc_new (shape_pixmap);
  1619.       gtk_preview_put (GTK_PREVIEW (shape_preview),
  1620.                shape_pixmap, gc,
  1621.                0, 0, 0, 0, width, height);
  1622.       gdk_gc_destroy (gc);
  1623.       gdk_window_set_back_pixmap(shape_window->window, shape_pixmap,
  1624.                  FALSE);
  1625.  
  1626.       reshape_from_bitmap(shape_preview_mask);
  1627.  
  1628.       gdk_flush();
  1629.  
  1630.       gtk_widget_queue_draw(shape_window);
  1631.     }
  1632. #endif /* ! RAPH_IS_HOME */
  1633.  
  1634.   /* update the dialog's progress bar */
  1635.   gtk_progress_bar_update (progress,
  1636.                ((float)frame_number/(float)(total_frames-0.999)));
  1637. }
  1638.  
  1639.  
  1640. static void
  1641. init_preview_misc (void)
  1642. {
  1643.   int i;
  1644.  
  1645.   preview_data = g_malloc(width*height*3);
  1646.   shape_preview_mask = g_malloc((width*height)/8 + 1 + height);
  1647.   preview_alpha1_data = g_malloc(width*3);
  1648.   preview_alpha2_data = g_malloc(width*3);
  1649.  
  1650.   for (i=0;i<width;i++)
  1651.     {
  1652.       if (i&8)
  1653.     {
  1654.       preview_alpha1_data[i*3 +0] =
  1655.       preview_alpha1_data[i*3 +1] =
  1656.       preview_alpha1_data[i*3 +2] = 102;
  1657.       preview_alpha2_data[i*3 +0] =
  1658.       preview_alpha2_data[i*3 +1] =
  1659.       preview_alpha2_data[i*3 +2] = 154;
  1660.     }
  1661.       else
  1662.     {
  1663.       preview_alpha1_data[i*3 +0] =
  1664.       preview_alpha1_data[i*3 +1] =
  1665.       preview_alpha1_data[i*3 +2] = 154;
  1666.       preview_alpha2_data[i*3 +0] =
  1667.       preview_alpha2_data[i*3 +1] =
  1668.       preview_alpha2_data[i*3 +2] = 102;
  1669.     }
  1670.     }
  1671.  
  1672. #ifdef RAPH_IS_HOME
  1673.   drawing_area_data = preview_data;
  1674.   shape_drawing_area_data = preview_data;
  1675. #endif
  1676. }
  1677.  
  1678.  
  1679. static void
  1680. total_alpha_preview (guchar* ptr)
  1681. {
  1682.   int i;
  1683.  
  1684.   if (shaping)
  1685.     {
  1686.       memset(shape_preview_mask, 0, (width*height)/8 + height);
  1687.     }
  1688.   else
  1689.     {
  1690.       for (i=0;i<height;i++)
  1691.     {
  1692.       if (i&8)
  1693.         memcpy(&ptr[i*3*width], preview_alpha1_data, 3*width);
  1694.       else
  1695.         memcpy(&ptr[i*3*width], preview_alpha2_data, 3*width);
  1696.     }
  1697.     }
  1698. }
  1699.  
  1700.  
  1701.  
  1702. /* Util. */
  1703.  
  1704. static void
  1705. remove_timer (void)
  1706. {
  1707.   if (timer)
  1708.     {
  1709.       gtk_timeout_remove (timer);
  1710.       timer = 0;
  1711.     }
  1712. }
  1713.  
  1714. static void
  1715. do_step (void)
  1716. {
  1717.   frame_number = (frame_number+1)%total_frames;
  1718.   render_frame(frame_number);
  1719. }
  1720.  
  1721.  
  1722. /*  Callbacks  */
  1723.  
  1724. static gint
  1725. window_delete_callback (GtkWidget *widget,
  1726.                 GdkEvent  *event,
  1727.                 gpointer   data)
  1728. {
  1729.   if (playing)
  1730.     playstop_callback(NULL, NULL);
  1731.  
  1732.   if (shape_window)
  1733.     gtk_widget_destroy(GTK_WIDGET(shape_window));
  1734.  
  1735.   gdk_flush();
  1736.   gtk_main_quit();
  1737.  
  1738.   return FALSE;
  1739. }
  1740.  
  1741. static void
  1742. window_close_callback (GtkWidget *widget,
  1743.                gpointer   data)
  1744. {
  1745.   if (data)
  1746.     gtk_widget_destroy(GTK_WIDGET(data));
  1747.  
  1748.   window_delete_callback (NULL, NULL, NULL);
  1749. }
  1750.  
  1751. static gint
  1752. advance_frame_callback (GtkWidget *widget,
  1753.             gpointer   data)
  1754. {
  1755.   remove_timer();
  1756.  
  1757.   timer = gtk_timeout_add (get_frame_duration((frame_number+1)%total_frames),
  1758.                (GtkFunction) advance_frame_callback, NULL);
  1759.  
  1760.   do_step();
  1761.   show_frame();
  1762.  
  1763.   return FALSE;
  1764. }
  1765.  
  1766. static void
  1767. playstop_callback (GtkWidget *widget,
  1768.            gpointer   data)
  1769. {
  1770.   if (!playing)
  1771.     { /* START PLAYING */
  1772.       playing = TRUE;
  1773.       timer = gtk_timeout_add (get_frame_duration(frame_number),
  1774.                    (GtkFunction) advance_frame_callback, NULL);
  1775.     }
  1776.   else
  1777.     { /* STOP PLAYING */
  1778.       playing = FALSE;
  1779.       remove_timer();
  1780.     }
  1781. }
  1782.  
  1783. static void
  1784. rewind_callback (GtkWidget *widget,
  1785.          gpointer   data)
  1786. {
  1787.   if (playing)
  1788.     {
  1789.       playstop_callback(NULL, NULL); /* GTK weirdness workaround */
  1790.       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (psbutton), FALSE);
  1791.       playing = FALSE;
  1792.       remove_timer();
  1793.     }
  1794.  
  1795.   frame_number = 0;
  1796.   render_frame(frame_number);
  1797.   show_frame();
  1798. }
  1799.  
  1800. static void
  1801. step_callback (GtkWidget *widget,
  1802.            gpointer   data)
  1803. {
  1804.   if (playing)
  1805.     {
  1806.       playstop_callback(NULL, NULL); /* GTK weirdness workaround */
  1807.       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (psbutton), FALSE);
  1808.       playing = FALSE;
  1809.       remove_timer();
  1810.     }
  1811.  
  1812.   do_step();
  1813.   show_frame();
  1814. }
  1815.  
  1816.  
  1817.  
  1818.  
  1819.  
  1820. /* tag util. */
  1821.  
  1822. static DisposeType
  1823. get_frame_disposal (const guint whichframe)
  1824. {
  1825.   gchar* layer_name;
  1826.   DisposeType disposal;
  1827.   
  1828.   layer_name = gimp_layer_get_name(layers[total_frames-(whichframe+1)]);
  1829.   disposal = parse_disposal_tag(layer_name);
  1830.   g_free(layer_name);
  1831.  
  1832.   return(disposal);
  1833. }
  1834.  
  1835.  
  1836.  
  1837. static guint32
  1838. get_frame_duration (const guint whichframe)
  1839. {
  1840.   gchar* layer_name;
  1841.   gint   duration = 0;
  1842.  
  1843.   layer_name = gimp_layer_get_name(layers[total_frames-(whichframe+1)]);
  1844.   if (layer_name != NULL)
  1845.     {
  1846.       duration = parse_ms_tag(layer_name);
  1847.       g_free(layer_name);
  1848.     }
  1849.   
  1850.   if (duration < 0) duration = 100;  /* FIXME for default-if-not-said  */
  1851.   else
  1852.     if (duration == 0) duration = 100; /* FIXME - 0-wait is nasty */
  1853.  
  1854.   return ((guint32) duration);
  1855. }
  1856.  
  1857.  
  1858. static int
  1859. is_ms_tag (const char *str, int *duration, int *taglength)
  1860. {
  1861.   gint sum = 0;
  1862.   gint offset;
  1863.   gint length;
  1864.  
  1865.   length = strlen(str);
  1866.  
  1867.   if (str[0] != '(')
  1868.     return 0;
  1869.  
  1870.   offset = 1;
  1871.  
  1872.   /* eat any spaces between open-parenthesis and number */
  1873.   while ((offset<length) && (str[offset] == ' '))
  1874.     offset++;
  1875.   
  1876.   if ((offset>=length) || (!isdigit(str[offset])))
  1877.     return 0;
  1878.  
  1879.   do
  1880.     {
  1881.       sum *= 10;
  1882.       sum += str[offset] - '0';
  1883.       offset++;
  1884.     }
  1885.   while ((offset<length) && (isdigit(str[offset])));  
  1886.  
  1887.   if (length-offset <= 2)
  1888.     return 0;
  1889.  
  1890.   /* eat any spaces between number and 'ms' */
  1891.   while ((offset<length) && (str[offset] == ' '))
  1892.     offset++;
  1893.  
  1894.   if ((length-offset <= 2) ||
  1895.       (toupper(str[offset]) != 'M') || (toupper(str[offset+1]) != 'S'))
  1896.     return 0;
  1897.  
  1898.   offset += 2;
  1899.  
  1900.   /* eat any spaces between 'ms' and close-parenthesis */
  1901.   while ((offset<length) && (str[offset] == ' '))
  1902.     offset++;
  1903.  
  1904.   if ((length-offset < 1) || (str[offset] != ')'))
  1905.     return 0;
  1906.  
  1907.   offset++;
  1908.   
  1909.   *duration = sum;
  1910.   *taglength = offset;
  1911.  
  1912.   return 1;
  1913. }
  1914.  
  1915.  
  1916. static int
  1917. parse_ms_tag (const char *str)
  1918. {
  1919.   int i;
  1920.   int rtn;
  1921.   int dummy;
  1922.   int length;
  1923.  
  1924.   length = strlen(str);
  1925.  
  1926.   for (i=0; i<length; i++)
  1927.     {
  1928.       if (is_ms_tag(&str[i], &rtn, &dummy))
  1929.     return rtn;
  1930.     }
  1931.   
  1932.   return -1;
  1933. }
  1934.  
  1935.  
  1936. static int
  1937. is_disposal_tag (const char *str, DisposeType *disposal, int *taglength)
  1938. {
  1939.   if (strlen(str) != 9)
  1940.     return 0;
  1941.   
  1942.   if (strncmp(str, "(combine)", 9) == 0)
  1943.     {
  1944.       *taglength = 9;
  1945.       *disposal = DISPOSE_COMBINE;
  1946.       return 1;
  1947.     }
  1948.   else if (strncmp(str, "(replace)", 9) == 0)
  1949.     {
  1950.       *taglength = 9;
  1951.       *disposal = DISPOSE_REPLACE;
  1952.       return 1;
  1953.     }
  1954.  
  1955.   return 0;
  1956. }
  1957.  
  1958.  
  1959. static DisposeType
  1960. parse_disposal_tag (const char *str)
  1961. {
  1962.   DisposeType rtn;
  1963.   int i, dummy;
  1964.   gint length;
  1965.  
  1966.   length = strlen(str);
  1967.  
  1968.   for (i=0; i<length; i++)
  1969.     {
  1970.       if (is_disposal_tag(&str[i], &rtn, &dummy))
  1971.     {
  1972.       return rtn;
  1973.     }
  1974.     }
  1975.  
  1976.   return (DISPOSE_UNDEFINED); /* FIXME */
  1977. }
  1978.