home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / libgimp / gimpmenu.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-04  |  31.7 KB  |  1,174 lines

  1. /* LIBGIMP - The GIMP Library
  2.  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
  3.  *
  4.  * gimpmenu.c
  5.  *
  6.  * This library is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2 of the License, or (at your option) any later version.
  10.  *
  11.  * This library is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Library General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with this library; if not, write to the
  18.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19.  * Boston, MA 02111-1307, USA.
  20.  */
  21.  
  22. #include <string.h>
  23.  
  24. #include "gimp.h"
  25. #include "gimpui.h"
  26.  
  27. #define MENU_THUMBNAIL_WIDTH   24
  28. #define MENU_THUMBNAIL_HEIGHT  24
  29.  
  30. /* Copy data from temp_PDB call */
  31. struct _GimpBrushData 
  32. {
  33.   gboolean  busy;
  34.   gchar    *bname;
  35.   gdouble   opacity;
  36.   gint      spacing;
  37.   gint      paint_mode;
  38.   gint      width;
  39.   gint      height;
  40.   gchar    *brush_mask_data;
  41.   GimpRunBrushCallback callback;
  42.   gboolean  closing;
  43.   gpointer  data;
  44. };
  45.  
  46. typedef struct _GimpBrushData GimpBrushData;
  47.  
  48. /* Copy data from temp_PDB call */
  49. struct _GimpPatternData 
  50. {
  51.   gboolean  busy;
  52.   gchar    *pname;
  53.   gint      width;
  54.   gint      height;
  55.   gint      bytes;
  56.   gchar    *pattern_mask_data;
  57.   GimpRunPatternCallback  callback;
  58.   gboolean  closing;
  59.   gpointer  data;
  60. };
  61.  
  62. typedef struct _GimpPatternData GimpPatternData;
  63.  
  64. /* Copy data from temp_PDB call */
  65. struct _GimpGradientData 
  66. {
  67.   gboolean  busy;
  68.   gchar    *gname;
  69.   gint      width;
  70.   gdouble  *gradient_data;
  71.   GimpRunGradientCallback  callback;
  72.   gboolean  closing;
  73.   gpointer  data;
  74. };
  75.  
  76. typedef struct _GimpGradientData GimpGradientData;
  77.  
  78. static void     gimp_menu_callback      (GtkWidget         *widget,
  79.                      gint32            *id);
  80. static void     do_brush_callback       (GimpBrushData     *bdata);
  81. static gint     idle_test_brush         (GimpBrushData     *bdata);
  82. static gint     idle_test_pattern       (GimpPatternData   *pdata);
  83. static gint     idle_test_gradient      (GimpGradientData  *gdata);
  84. static void     temp_brush_invoker      (gchar             *name,
  85.                      gint               nparams,
  86.                      GimpParam         *param,
  87.                      gint              *nreturn_vals,
  88.                      GimpParam        **return_vals);
  89. static gboolean input_callback            (GIOChannel        *channel,
  90.                      GIOCondition       condition,
  91.                      gpointer           data);
  92. static void     gimp_setup_callbacks    (void);
  93. static gchar  * gen_temp_plugin_name    (void);
  94. static void     fill_preview_with_thumb (GtkWidget         *widget,
  95.                      gint32             drawable_ID,
  96.                      gint               width,
  97.                      gint               height);
  98.  
  99. /* From gimp.c */
  100. void gimp_run_temp (void);
  101.  
  102. static GHashTable       *gbrush_ht           = NULL;
  103. static GHashTable       *gpattern_ht         = NULL;
  104. static GHashTable       *ggradient_ht        = NULL;
  105. static GimpBrushData    *active_brush_pdb    = NULL;
  106. static GimpPatternData  *active_pattern_pdb  = NULL;
  107. static GimpGradientData *active_gradient_pdb = NULL;
  108.  
  109. GtkWidget *
  110. gimp_image_menu_new (GimpConstraintFunc constraint,
  111.              GimpMenuCallback   callback,
  112.              gpointer           data,
  113.              gint32             active_image)
  114. {
  115.   GtkWidget *menu;
  116.   GtkWidget *menuitem;
  117.   gchar *filename;
  118.   gchar *label;
  119.   gint32 *images;
  120.   gint nimages;
  121.   gint i, k;
  122.  
  123.   menu = gtk_menu_new ();
  124.   gtk_object_set_user_data (GTK_OBJECT (menu), (gpointer) callback);
  125.   gtk_object_set_data (GTK_OBJECT (menu), "gimp_callback_data", data);
  126.  
  127.   images = gimp_image_list (&nimages);
  128.   for (i = 0, k = 0; i < nimages; i++)
  129.     if (!constraint || (* constraint) (images[i], -1, data))
  130.       {
  131.     filename = gimp_image_get_filename (images[i]);
  132.     label = g_strdup_printf ("%s-%d", g_basename (filename), images[i]);
  133.     g_free (filename);
  134.  
  135.     menuitem = gtk_menu_item_new_with_label (label);
  136.     gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  137.                 (GtkSignalFunc) gimp_menu_callback,
  138.                 &images[i]);
  139.     gtk_menu_append (GTK_MENU (menu), menuitem);
  140.     gtk_widget_show (menuitem);
  141.  
  142.     g_free (label);
  143.  
  144.     if (images[i] == active_image)
  145.       gtk_menu_set_active (GTK_MENU (menu), k);
  146.  
  147.     k += 1;
  148.       }
  149.  
  150.   if (k == 0)
  151.     {
  152.       menuitem = gtk_menu_item_new_with_label ("none");
  153.       gtk_widget_set_sensitive (menuitem, FALSE);
  154.       gtk_menu_append (GTK_MENU (menu), menuitem);
  155.       gtk_widget_show (menuitem);
  156.     }
  157.  
  158.   if (images)
  159.     {
  160.       if (active_image == -1)
  161.     active_image = images[0];
  162.       (* callback) (active_image, data);
  163.     }
  164.  
  165.   return menu;
  166. }
  167.  
  168.  
  169. GtkWidget *
  170. gimp_layer_menu_new (GimpConstraintFunc constraint,
  171.              GimpMenuCallback   callback,
  172.              gpointer           data,
  173.              gint32             active_layer)
  174. {
  175.   GtkWidget *menu;
  176.   GtkWidget *menuitem;
  177.   gchar *name;
  178.   gchar *image_label;
  179.   gchar *label;
  180.   gint32 *images;
  181.   gint32 *layers;
  182.   gint32 layer;
  183.   gint nimages;
  184.   gint nlayers;
  185.   gint i, j, k;
  186.  
  187.   menu = gtk_menu_new ();
  188.   gtk_object_set_user_data (GTK_OBJECT (menu), (gpointer) callback);
  189.   gtk_object_set_data (GTK_OBJECT (menu), "gimp_callback_data", data);
  190.  
  191.   layer = -1;
  192.  
  193.   images = gimp_image_list (&nimages);
  194.   for (i = 0, k = 0; i < nimages; i++)
  195.     if (!constraint || (* constraint) (images[i], -1, data))
  196.       {
  197.     name = gimp_image_get_filename (images[i]);
  198.     image_label = g_strdup_printf ("%s-%d", g_basename (name), images[i]);
  199.     g_free (name);
  200.  
  201.     layers = gimp_image_get_layers (images[i], &nlayers);
  202.     for (j = 0; j < nlayers; j++)
  203.       if (!constraint || (* constraint) (images[i], layers[j], data))
  204.         {
  205.           GtkWidget *hbox;
  206.           GtkWidget *vbox;
  207.           GtkWidget *wcolor_box;
  208.           GtkWidget *wlabel;
  209.  
  210.           name = gimp_layer_get_name (layers[j]);
  211.           label = g_strdup_printf ("%s/%s", image_label, name);
  212.           g_free (name);
  213.  
  214.           menuitem = gtk_menu_item_new();
  215.           gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  216.                   (GtkSignalFunc) gimp_menu_callback,
  217.                   &layers[j]);
  218.  
  219.           hbox = gtk_hbox_new(FALSE, 0);
  220.           gtk_container_add(GTK_CONTAINER(menuitem), hbox);
  221.           gtk_widget_show(hbox);
  222.  
  223.           vbox = gtk_vbox_new(FALSE, 0);
  224.           gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
  225.           gtk_widget_show(vbox);
  226.           
  227.           wcolor_box = gtk_preview_new(GTK_PREVIEW_COLOR);
  228.           gtk_preview_set_dither (GTK_PREVIEW (wcolor_box), GDK_RGB_DITHER_MAX);
  229.  
  230.           fill_preview_with_thumb (wcolor_box,
  231.                        layers[j],
  232.                        MENU_THUMBNAIL_WIDTH,
  233.                        MENU_THUMBNAIL_HEIGHT);
  234.  
  235.           gtk_widget_set_usize (GTK_WIDGET (wcolor_box),
  236.                     MENU_THUMBNAIL_WIDTH,
  237.                     MENU_THUMBNAIL_HEIGHT);
  238.  
  239.           gtk_container_add (GTK_CONTAINER (vbox), wcolor_box);
  240.           gtk_widget_show (wcolor_box);
  241.  
  242.           wlabel = gtk_label_new (label);
  243.           gtk_misc_set_alignment (GTK_MISC (wlabel), 0.0, 0.5);
  244.           gtk_box_pack_start (GTK_BOX (hbox), wlabel, TRUE, TRUE, 4);
  245.           gtk_widget_show (wlabel);
  246.  
  247.           gtk_menu_append (GTK_MENU (menu), menuitem);
  248.           gtk_widget_show (menuitem);
  249.  
  250.           g_free (label);
  251.  
  252.           if (layers[j] == active_layer)
  253.         {
  254.           layer = active_layer;
  255.           gtk_menu_set_active (GTK_MENU (menu), k);
  256.         }
  257.           else if (layer == -1)
  258.         layer = layers[j];
  259.  
  260.           k += 1;
  261.         }
  262.  
  263.     g_free (image_label);
  264.       }
  265.   g_free (images);
  266.  
  267.   if (k == 0)
  268.     {
  269.       menuitem = gtk_menu_item_new_with_label ("none");
  270.       gtk_widget_set_sensitive (menuitem, FALSE);
  271.       gtk_menu_append (GTK_MENU (menu), menuitem);
  272.       gtk_widget_show (menuitem);
  273.     }
  274.  
  275.   if (layer != -1)
  276.     (* callback) (layer, data);
  277.  
  278.   return menu;
  279. }
  280.  
  281. GtkWidget *
  282. gimp_channel_menu_new (GimpConstraintFunc constraint,
  283.                GimpMenuCallback   callback,
  284.                gpointer           data,
  285.                gint32             active_channel)
  286. {
  287.   GtkWidget *menu;
  288.   GtkWidget *menuitem;
  289.   gchar *name;
  290.   gchar *image_label;
  291.   gchar *label;
  292.   gint32 *images;
  293.   gint32 *channels;
  294.   gint32 channel;
  295.   gint nimages;
  296.   gint nchannels;
  297.   gint i, j, k;
  298.  
  299.   menu = gtk_menu_new ();
  300.   gtk_object_set_user_data (GTK_OBJECT (menu), (gpointer) callback);
  301.   gtk_object_set_data (GTK_OBJECT (menu), "gimp_callback_data", data);
  302.  
  303.   channel = -1;
  304.  
  305.   images = gimp_image_list (&nimages);
  306.   for (i = 0, k = 0; i < nimages; i++)
  307.     if (!constraint || (* constraint) (images[i], -1, data))
  308.       {
  309.     name = gimp_image_get_filename (images[i]);
  310.     image_label = g_strdup_printf ("%s-%d", g_basename (name), images[i]);
  311.     g_free (name);
  312.  
  313.     channels = gimp_image_get_channels (images[i], &nchannels);
  314.     for (j = 0; j < nchannels; j++)
  315.       if (!constraint || (* constraint) (images[i], channels[j], data))
  316.         {
  317.           GtkWidget *hbox;
  318.           GtkWidget *vbox;
  319.           GtkWidget *wcolor_box;
  320.           GtkWidget *wlabel;
  321.  
  322.           name = gimp_channel_get_name (channels[j]);
  323.           label = g_strdup_printf ("%s/%s", image_label, name);
  324.           g_free (name);
  325.  
  326.           menuitem = gtk_menu_item_new ();
  327.           gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  328.                   GTK_SIGNAL_FUNC (gimp_menu_callback),
  329.                   &channels[j]);
  330.           
  331.           hbox = gtk_hbox_new (FALSE, 0);
  332.           gtk_container_add (GTK_CONTAINER (menuitem), hbox);
  333.           gtk_widget_show (hbox);
  334.  
  335.           vbox = gtk_vbox_new (FALSE, 0);
  336.           gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
  337.           gtk_widget_show (vbox);
  338.  
  339.           wcolor_box = gtk_preview_new (GTK_PREVIEW_COLOR);
  340.           gtk_preview_set_dither (GTK_PREVIEW (wcolor_box),
  341.                       GDK_RGB_DITHER_MAX);
  342.  
  343.            fill_preview_with_thumb (wcolor_box, 
  344.                        channels[j], 
  345.                        MENU_THUMBNAIL_WIDTH, 
  346.                        MENU_THUMBNAIL_HEIGHT); 
  347.  
  348.           gtk_widget_set_usize (GTK_WIDGET (wcolor_box),
  349.                     MENU_THUMBNAIL_WIDTH,
  350.                     MENU_THUMBNAIL_HEIGHT);
  351.  
  352.           gtk_container_add (GTK_CONTAINER(vbox), wcolor_box);
  353.           gtk_widget_show (wcolor_box);
  354.  
  355.           wlabel = gtk_label_new (label);
  356.           gtk_misc_set_alignment (GTK_MISC (wlabel), 0.0, 0.5);
  357.           gtk_box_pack_start (GTK_BOX (hbox), wlabel, TRUE, TRUE, 4);
  358.           gtk_widget_show (wlabel);
  359.  
  360.           gtk_menu_append (GTK_MENU (menu), menuitem);
  361.           gtk_widget_show (menuitem);
  362.  
  363.           g_free (label);
  364.  
  365.           if (channels[j] == active_channel)
  366.         {
  367.           channel = active_channel;
  368.           gtk_menu_set_active (GTK_MENU (menu), k);
  369.         }
  370.           else if (channel == -1)
  371.         channel = channels[j];
  372.  
  373.           k += 1;
  374.         }
  375.  
  376.     g_free (image_label);
  377.       }
  378.   g_free (images);
  379.  
  380.   if (k == 0)
  381.     {
  382.       menuitem = gtk_menu_item_new_with_label ("none");
  383.       gtk_widget_set_sensitive (menuitem, FALSE);
  384.       gtk_menu_append (GTK_MENU (menu), menuitem);
  385.       gtk_widget_show (menuitem);
  386.     }
  387.  
  388.   if (channel != -1)
  389.     (* callback) (channel, data);
  390.  
  391.   return menu;
  392. }
  393.  
  394. GtkWidget *
  395. gimp_drawable_menu_new (GimpConstraintFunc constraint,
  396.             GimpMenuCallback   callback,
  397.             gpointer           data,
  398.             gint32             active_drawable)
  399. {
  400.   GtkWidget *menu;
  401.   GtkWidget *menuitem;
  402.   gchar  *name;
  403.   gchar  *image_label;
  404.   gchar  *label;
  405.   gint32 *images;
  406.   gint32 *layers;
  407.   gint32 *channels;
  408.   gint32  drawable;
  409.   gint    nimages;
  410.   gint    nlayers;
  411.   gint    nchannels;
  412.   gint    i, j, k;
  413.  
  414.   menu = gtk_menu_new ();
  415.   gtk_object_set_user_data (GTK_OBJECT (menu), (gpointer) callback);
  416.   gtk_object_set_data (GTK_OBJECT (menu), "gimp_callback_data", data);
  417.  
  418.   drawable = -1;
  419.  
  420.   images = gimp_image_list (&nimages);
  421.  
  422.   for (i = 0, k = 0; i < nimages; i++)
  423.     if (!constraint || (* constraint) (images[i], -1, data))
  424.       {
  425.     name = gimp_image_get_filename (images[i]);
  426.     image_label = g_strdup_printf ("%s-%d", g_basename (name), images[i]);
  427.     g_free (name);
  428.  
  429.     layers = gimp_image_get_layers (images[i], &nlayers);
  430.  
  431.     for (j = 0; j < nlayers; j++)
  432.       if (!constraint || (* constraint) (images[i], layers[j], data))
  433.         {
  434.           GtkWidget *hbox;
  435.           GtkWidget *vbox;
  436.           GtkWidget *wcolor_box;
  437.           GtkWidget *wlabel;
  438.  
  439.           name = gimp_layer_get_name (layers[j]);
  440.           label = g_strdup_printf ("%s/%s", image_label, name);
  441.           g_free (name);
  442.  
  443.           menuitem = gtk_menu_item_new ();
  444.           gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  445.                   (GtkSignalFunc) gimp_menu_callback,
  446.                   &layers[j]);
  447.  
  448.           hbox = gtk_hbox_new (FALSE, 0);
  449.           gtk_container_add (GTK_CONTAINER(menuitem), hbox);
  450.           gtk_widget_show (hbox);
  451.  
  452.           vbox = gtk_vbox_new (FALSE, 0);
  453.           gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
  454.           gtk_widget_show (vbox);
  455.           
  456.           wcolor_box = gtk_preview_new (GTK_PREVIEW_COLOR);
  457.           gtk_preview_set_dither (GTK_PREVIEW (wcolor_box), GDK_RGB_DITHER_MAX);
  458.  
  459.           fill_preview_with_thumb (wcolor_box,
  460.                        layers[j],
  461.                        MENU_THUMBNAIL_WIDTH,
  462.                        MENU_THUMBNAIL_HEIGHT);
  463.  
  464.           gtk_widget_set_usize (GTK_WIDGET (wcolor_box), 
  465.                     MENU_THUMBNAIL_WIDTH , 
  466.                     MENU_THUMBNAIL_HEIGHT);
  467.  
  468.           gtk_container_add (GTK_CONTAINER(vbox), wcolor_box);
  469.           gtk_widget_show (wcolor_box);
  470.  
  471.           wlabel = gtk_label_new (label);
  472.           gtk_misc_set_alignment (GTK_MISC (wlabel), 0.0, 0.5);
  473.           gtk_box_pack_start (GTK_BOX (hbox), wlabel, TRUE, TRUE, 4);
  474.           gtk_widget_show (wlabel);
  475.  
  476.           gtk_menu_append (GTK_MENU (menu), menuitem);
  477.           gtk_widget_show (menuitem);
  478.  
  479.           g_free (label);
  480.  
  481.           if (layers[j] == active_drawable)
  482.         {
  483.           drawable = active_drawable;
  484.           gtk_menu_set_active (GTK_MENU (menu), k);
  485.         }
  486.           else if (drawable == -1)
  487.         drawable = layers[j];
  488.  
  489.           k += 1;
  490.         }
  491.  
  492.     channels = gimp_image_get_channels (images[i], &nchannels);
  493.  
  494.     for (j = 0; j < nchannels; j++)
  495.       if (!constraint || (* constraint) (images[i], channels[j], data))
  496.         {
  497.           GtkWidget *hbox;
  498.           GtkWidget *vbox;
  499.           GtkWidget *wcolor_box;
  500.           GtkWidget *wlabel;
  501.  
  502.           name = gimp_channel_get_name (channels[j]);
  503.           label = g_strdup_printf ("%s/%s", image_label, name);
  504.           g_free (name);
  505.  
  506.           menuitem = gtk_menu_item_new ();
  507.           gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  508.                   GTK_SIGNAL_FUNC (gimp_menu_callback),
  509.                   &channels[j]);
  510.  
  511.           hbox = gtk_hbox_new (FALSE, 0);
  512.           gtk_container_add (GTK_CONTAINER (menuitem), hbox);
  513.           gtk_widget_show (hbox);
  514.  
  515.           vbox = gtk_vbox_new (FALSE, 0);
  516.           gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
  517.           gtk_widget_show (vbox);
  518.           
  519.           wcolor_box = gtk_preview_new (GTK_PREVIEW_COLOR);
  520.           gtk_preview_set_dither (GTK_PREVIEW (wcolor_box),
  521.                       GDK_RGB_DITHER_MAX);
  522.  
  523.            fill_preview_with_thumb (wcolor_box, 
  524.                        channels[j], 
  525.                        MENU_THUMBNAIL_WIDTH, 
  526.                        MENU_THUMBNAIL_HEIGHT); 
  527.  
  528.           gtk_widget_set_usize (GTK_WIDGET (wcolor_box), 
  529.                     MENU_THUMBNAIL_WIDTH , 
  530.                     MENU_THUMBNAIL_HEIGHT);
  531.           
  532.           gtk_container_add (GTK_CONTAINER (vbox), wcolor_box);
  533.           gtk_widget_show (wcolor_box);
  534.  
  535.           wlabel = gtk_label_new (label);
  536.           gtk_misc_set_alignment (GTK_MISC (wlabel), 0.0, 0.5);
  537.           gtk_box_pack_start (GTK_BOX (hbox), wlabel, TRUE, TRUE, 4);
  538.           gtk_widget_show (wlabel);
  539.  
  540.           gtk_menu_append (GTK_MENU (menu), menuitem);
  541.           gtk_widget_show (menuitem);
  542.  
  543.           g_free (label);
  544.  
  545.           if (channels[j] == active_drawable)
  546.         {
  547.           drawable = active_drawable;
  548.           gtk_menu_set_active (GTK_MENU (menu), k);
  549.         }
  550.           else if (drawable == -1)
  551.         drawable = channels[j];
  552.  
  553.           k += 1;
  554.         }
  555.  
  556.     g_free (image_label);
  557.       }
  558.   g_free (images);
  559.  
  560.   if (k == 0)
  561.     {
  562.       menuitem = gtk_menu_item_new_with_label ("none");
  563.       gtk_widget_set_sensitive (menuitem, FALSE);
  564.       gtk_menu_append (GTK_MENU (menu), menuitem);
  565.       gtk_widget_show (menuitem);
  566.     }
  567.  
  568.   if (drawable != -1)
  569.     (* callback) (drawable, data);
  570.  
  571.   return menu;
  572. }
  573.  
  574.  
  575. static void
  576. gimp_menu_callback (GtkWidget *widget,
  577.             gint32    *id)
  578. {
  579.   GimpMenuCallback callback;
  580.   gpointer         callback_data;
  581.  
  582.   callback =
  583.     (GimpMenuCallback) gtk_object_get_user_data (GTK_OBJECT (widget->parent));
  584.   callback_data = gtk_object_get_data (GTK_OBJECT (widget->parent),
  585.                        "gimp_callback_data");
  586.  
  587.   (* callback) (*id, callback_data);
  588. }
  589.  
  590. static void
  591. fill_preview_with_thumb (GtkWidget *widget,
  592.              gint32     drawable_ID,
  593.              gint       width,
  594.              gint       height)
  595. {
  596.   guchar  *drawable_data;
  597.   gint     bpp;
  598.   gint     x, y;
  599.   guchar  *src;
  600.   gdouble  r, g, b, a;
  601.   gdouble  c0, c1;
  602.   guchar  *p0, *p1, *even, *odd;
  603.  
  604.   bpp = 0; /* Only returned */
  605.   
  606.   drawable_data = 
  607.     gimp_drawable_get_thumbnail_data (drawable_ID, &width, &height, &bpp);
  608.  
  609.   gtk_preview_size (GTK_PREVIEW (widget), width, height);
  610.  
  611.   even = g_malloc (width * 3);
  612.   odd  = g_malloc (width * 3);
  613.   src  = drawable_data;
  614.  
  615.   for (y = 0; y < height; y++)
  616.     {
  617.       p0 = even;
  618.       p1 = odd;
  619.       
  620.       for (x = 0; x < width; x++) 
  621.     {
  622.       if (bpp == 4)
  623.         {
  624.           r = ((gdouble) src[x*4+0]) / 255.0;
  625.           g = ((gdouble) src[x*4+1]) / 255.0;
  626.           b = ((gdouble) src[x*4+2]) / 255.0;
  627.           a = ((gdouble) src[x*4+3]) / 255.0;
  628.         }
  629.       else if (bpp == 3)
  630.         {
  631.           r = ((gdouble) src[x*3+0]) / 255.0;
  632.           g = ((gdouble) src[x*3+1]) / 255.0;
  633.           b = ((gdouble) src[x*3+2]) / 255.0;
  634.           a = 1.0;
  635.         }
  636.       else
  637.         {
  638.           r = ((gdouble) src[x*bpp+0]) / 255.0;
  639.           g = b = r;
  640.           if (bpp == 2)
  641.         a = ((gdouble) src[x*bpp+1]) / 255.0;
  642.           else
  643.         a = 1.0;
  644.         }
  645.  
  646.       if ((x / GIMP_CHECK_SIZE_SM) & 1) 
  647.         {
  648.           c0 = GIMP_CHECK_LIGHT;
  649.           c1 = GIMP_CHECK_DARK;
  650.         } 
  651.       else 
  652.         {
  653.           c0 = GIMP_CHECK_DARK;
  654.           c1 = GIMP_CHECK_LIGHT;
  655.         }
  656.     
  657.       *p0++ = (c0 + (r - c0) * a) * 255.0;
  658.       *p0++ = (c0 + (g - c0) * a) * 255.0;
  659.       *p0++ = (c0 + (b - c0) * a) * 255.0;
  660.  
  661.       *p1++ = (c1 + (r - c1) * a) * 255.0;
  662.       *p1++ = (c1 + (g - c1) * a) * 255.0;
  663.       *p1++ = (c1 + (b - c1) * a) * 255.0;  
  664.     }
  665.       
  666.       if ((y / GIMP_CHECK_SIZE_SM) & 1)
  667.     gtk_preview_draw_row (GTK_PREVIEW (widget), (guchar *)odd,  0, y, width);
  668.       else
  669.     gtk_preview_draw_row (GTK_PREVIEW (widget), (guchar *)even, 0, y, width);
  670.  
  671.       src += width * bpp;
  672.     }
  673.  
  674.   g_free (even);
  675.   g_free (odd);
  676. }
  677.  
  678.  
  679. /* These functions allow the callback PDB work with gtk
  680.  * ALT.
  681.  * Note that currently PDB calls in libgimp are completely deterministic.
  682.  * There is always one call followed by a reply.
  683.  * If we are in the main gdk wait routine we can cannot get a reply
  684.  * to a wire message, only the request for a new PDB proc to be run.
  685.  * we will restrict this to a temp PDB function we have registered.
  686.  */
  687.  
  688. static void 
  689. do_brush_callback (GimpBrushData *bdata)
  690. {
  691.   if (!bdata->busy)
  692.     return;
  693.  
  694.   if (bdata->callback)
  695.     bdata->callback (bdata->bname,
  696.              bdata->opacity,
  697.              bdata->spacing,
  698.              bdata->paint_mode,
  699.              bdata->width,
  700.              bdata->height,
  701.              bdata->brush_mask_data,
  702.              bdata->closing,
  703.              bdata->data);
  704.  
  705.   if (bdata->bname)
  706.     g_free (bdata->bname);  
  707.   
  708.   if (bdata->brush_mask_data)
  709.     g_free (bdata->brush_mask_data); 
  710.  
  711.   bdata->busy = FALSE;
  712.   bdata->bname = NULL;
  713.   bdata->brush_mask_data = NULL;
  714. }
  715.  
  716. static void 
  717. do_pattern_callback (GimpPatternData *pdata)
  718. {
  719.   if (!pdata->busy)
  720.     return;
  721.  
  722.   if (pdata->callback)
  723.     pdata->callback (pdata->pname,
  724.              pdata->width,
  725.              pdata->height,
  726.              pdata->bytes,
  727.              pdata->pattern_mask_data,
  728.              pdata->closing,
  729.              pdata->data);
  730.   
  731.   if (pdata->pname)
  732.     g_free (pdata->pname);  
  733.   
  734.   if (pdata->pattern_mask_data)
  735.     g_free (pdata->pattern_mask_data); 
  736.  
  737.   pdata->busy = FALSE;
  738.   pdata->pname = NULL;
  739.   pdata->pattern_mask_data = NULL;
  740. }
  741.  
  742. static void 
  743. do_gradient_callback (GimpGradientData *gdata)
  744. {
  745.   if (!gdata->busy)
  746.     return;
  747.  
  748.   if (gdata->callback)
  749.     gdata->callback (gdata->gname,
  750.              gdata->width,
  751.              gdata->gradient_data,
  752.              gdata->closing,
  753.              gdata->data);
  754.  
  755.   if (gdata->gname)
  756.     g_free (gdata->gname);  
  757.   
  758.   if (gdata->gradient_data)
  759.     g_free (gdata->gradient_data); 
  760.  
  761.   gdata->busy = FALSE;
  762.   gdata->gname = NULL;
  763.   gdata->gradient_data = NULL;
  764. }
  765.  
  766. static gint
  767. idle_test_brush (GimpBrushData *bdata)
  768. {
  769.   do_brush_callback (bdata);
  770.  
  771.   return FALSE;
  772. }
  773.  
  774.  
  775. static gint
  776. idle_test_pattern (GimpPatternData *pdata)
  777. {
  778.   do_pattern_callback (pdata);
  779.  
  780.   return FALSE;
  781. }
  782.  
  783. static gint
  784. idle_test_gradient (GimpGradientData *gdata)
  785. {
  786.   do_gradient_callback (gdata);
  787.  
  788.   return FALSE;
  789. }
  790.  
  791. static void
  792. temp_brush_invoker (gchar      *name,
  793.             gint        nparams,
  794.             GimpParam  *param,
  795.             gint       *nreturn_vals,
  796.             GimpParam **return_vals)
  797. {
  798.   static GimpParam values[1];
  799.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  800.   GimpBrushData *bdata;
  801.  
  802.   bdata = (GimpBrushData *) g_hash_table_lookup (gbrush_ht, name);
  803.  
  804.   if (!bdata)
  805.     g_warning("Can't find internal brush data");
  806.   else
  807.     if(!bdata->busy)
  808.       {
  809.     bdata->bname           = g_strdup (param[0].data.d_string);
  810.     bdata->opacity         = (gdouble)param[1].data.d_float;
  811.     bdata->spacing         = param[2].data.d_int32;
  812.     bdata->paint_mode      = param[3].data.d_int32;
  813.     bdata->width           = param[4].data.d_int32;
  814.     bdata->height          = param[5].data.d_int32;
  815.     bdata->brush_mask_data = g_malloc(param[6].data.d_int32);
  816.     g_memmove (bdata->brush_mask_data, 
  817.            param[7].data.d_int8array, param[6].data.d_int32); 
  818.     bdata->closing         = param[8].data.d_int32;
  819.     active_brush_pdb       = bdata;
  820.     bdata->busy            = TRUE;
  821.     
  822.     gtk_idle_add ((GtkFunction)idle_test_brush, active_brush_pdb);
  823.       }
  824.  
  825.   *nreturn_vals = 1;
  826.   *return_vals = values;
  827.   
  828.   values[0].type = GIMP_PDB_STATUS;
  829.   values[0].data.d_status = status;
  830. }
  831.  
  832. static void
  833. temp_pattern_invoker (gchar      *name,
  834.               gint        nparams,
  835.               GimpParam  *param,
  836.               gint       *nreturn_vals,
  837.               GimpParam **return_vals)
  838. {
  839.   static GimpParam values[1];
  840.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  841.   GimpPatternData *pdata;
  842.  
  843.   pdata = (GimpPatternData *)g_hash_table_lookup (gpattern_ht, name);
  844.  
  845.   if (!pdata)
  846.     g_warning ("Can't find internal pattern data");
  847.   else
  848.     if (!pdata->busy)
  849.       {
  850.     pdata->pname             = g_strdup(param[0].data.d_string);
  851.     pdata->width             = param[1].data.d_int32;
  852.     pdata->height            = param[2].data.d_int32;
  853.     pdata->bytes             = param[3].data.d_int32;
  854.     pdata->pattern_mask_data = g_malloc(param[4].data.d_int32);
  855.     g_memmove (pdata->pattern_mask_data,
  856.            param[5].data.d_int8array, param[4].data.d_int32);
  857.     pdata->closing           = param[6].data.d_int32;
  858.     active_pattern_pdb       = pdata;
  859.     pdata->busy              = TRUE;
  860.  
  861.     gtk_idle_add ((GtkFunction)idle_test_pattern, active_pattern_pdb);
  862.       }
  863.  
  864.   *nreturn_vals = 1;
  865.   *return_vals = values;
  866.   
  867.   values[0].type = GIMP_PDB_STATUS;
  868.   values[0].data.d_status = status;
  869. }
  870.  
  871. static void
  872. temp_gradient_invoker (gchar      *name,
  873.                gint        nparams,
  874.                GimpParam  *param,
  875.                gint       *nreturn_vals,
  876.                GimpParam **return_vals)
  877. {
  878.   static GimpParam values[1];
  879.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  880.   GimpGradientData *gdata;
  881.  
  882.   gdata = (GimpGradientData *) g_hash_table_lookup (ggradient_ht, name);
  883.  
  884.   if (!gdata)
  885.       g_warning("Can't find internal gradient data");
  886.   else
  887.     {
  888.       if (!gdata->busy)
  889.     {
  890.       gint i;
  891.       gdouble *pv;
  892.       gdouble *values;
  893.       
  894.       gdata->gname         = g_strdup (param[0].data.d_string);
  895.       gdata->width         = param[1].data.d_int32;
  896.       gdata->gradient_data = g_new (gdouble, param[1].data.d_int32);
  897.  
  898.       values = param[2].data.d_floatarray;
  899.       pv = gdata->gradient_data;
  900.  
  901.       for (i = 0; i < gdata->width; i++)
  902.         gdata->gradient_data[i] = param[2].data.d_floatarray[i];
  903.  
  904.       gdata->closing      = param[3].data.d_int32;
  905.       active_gradient_pdb = gdata;
  906.       gdata->busy         = TRUE;
  907.       gtk_idle_add ((GtkFunction)idle_test_gradient, active_gradient_pdb);
  908.     }
  909.     }
  910.  
  911.   *nreturn_vals = 1;
  912.   *return_vals = values;
  913.   
  914.   values[0].type = GIMP_PDB_STATUS;
  915.   values[0].data.d_status = status;
  916. }
  917.  
  918. static gboolean
  919. input_callback (GIOChannel  *channel,
  920.         GIOCondition condition,
  921.         gpointer     data)
  922. {
  923.   /* We have some data in the wire - read it */
  924.   /* The below will only ever run a single proc */
  925.   gimp_run_temp ();
  926.  
  927.   return TRUE;
  928. }
  929.  
  930. static void
  931. gimp_setup_callbacks (void)
  932. {
  933.   static gboolean first_time = TRUE;
  934.  
  935.   if (first_time)
  936.     {
  937.       /* Tie into the gdk input function only once */
  938.       g_io_add_watch (_readchannel, G_IO_IN | G_IO_PRI, input_callback, NULL);
  939.  
  940.       first_time = FALSE;
  941.     }
  942. }
  943.  
  944. static gchar *
  945. gen_temp_plugin_name (void)
  946. {
  947.   GimpParam *return_vals;
  948.   gint   nreturn_vals;
  949.   gchar *result;
  950.  
  951.   return_vals = gimp_run_procedure ("gimp_temp_PDB_name",
  952.                     &nreturn_vals,
  953.                     GIMP_PDB_END);
  954.  
  955.   result = "temp_name_gen_failed";
  956.   if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
  957.     result = g_strdup (return_vals[1].data.d_string);
  958.  
  959.   gimp_destroy_params (return_vals, nreturn_vals);
  960.  
  961.   return result;
  962. }
  963.  
  964. /* Can only be used in conjuction with gdk since we need to tie into the input 
  965.  * selection mech.
  966.  */
  967. gchar *
  968. gimp_interactive_selection_brush (gchar             *dialogname, 
  969.                   gchar             *brush_name,
  970.                   gdouble            opacity,
  971.                   gint               spacing,
  972.                   gint               paint_mode,
  973.                   GimpRunBrushCallback  callback,
  974.                   gpointer           data)
  975. {
  976.   static GimpParamDef args[] =
  977.   {
  978.     { GIMP_PDB_STRING,    "str",           "String" },
  979.     { GIMP_PDB_FLOAT,     "opacity",       "Opacity" },
  980.     { GIMP_PDB_INT32,     "spacing",       "Spacing" },
  981.     { GIMP_PDB_INT32,     "paint mode",    "Paint mode" },
  982.     { GIMP_PDB_INT32,     "mask width",    "Brush width" },
  983.     { GIMP_PDB_INT32,     "mask height"    "Brush heigth" },
  984.     { GIMP_PDB_INT32,     "mask len",      "Length of brush mask data" },
  985.     { GIMP_PDB_INT8ARRAY, "mask data",     "The brush mask data" },
  986.     { GIMP_PDB_INT32,     "dialog status", "Registers if the dialog was closing "
  987.                                         "[0 = No, 1 = Yes]" },
  988.   };
  989.   static GimpParamDef *return_vals = NULL;
  990.   static gint nargs = sizeof (args) / sizeof (args[0]);
  991.   static gint nreturn_vals = 0;
  992.   gint bnreturn_vals;
  993.   GimpParam *pdbreturn_vals;
  994.   gchar *pdbname = gen_temp_plugin_name ();
  995.   GimpBrushData *bdata;
  996.  
  997.   bdata = g_new0 (GimpBrushData, 1);
  998.  
  999.   gimp_install_temp_proc (pdbname,
  1000.               "Temp PDB for interactive popups",
  1001.               "More here later",
  1002.               "Andy Thomas",
  1003.               "Andy Thomas",
  1004.               "1997",
  1005.               NULL,
  1006.               "RGB*, GRAY*",
  1007.               GIMP_TEMPORARY,
  1008.               nargs, nreturn_vals,
  1009.               args, return_vals,
  1010.               temp_brush_invoker);
  1011.  
  1012.   pdbreturn_vals =
  1013.     gimp_run_procedure ("gimp_brushes_popup",
  1014.             &bnreturn_vals,
  1015.             GIMP_PDB_STRING, pdbname,
  1016.             GIMP_PDB_STRING, dialogname,
  1017.             GIMP_PDB_STRING, brush_name,
  1018.             GIMP_PDB_FLOAT,  opacity,
  1019.             GIMP_PDB_INT32,  spacing,
  1020.             GIMP_PDB_INT32,  paint_mode,
  1021.             GIMP_PDB_END);
  1022.  
  1023. /*   if (pdbreturn_vals[0].data.d_status != GIMP_PDB_SUCCESS) */
  1024. /*     { */
  1025. /*       printf("ret failed = 0x%x\n",bnreturn_vals); */
  1026. /*     } */
  1027. /*   else */
  1028. /*       printf("worked = 0x%x\n",bnreturn_vals); */
  1029.  
  1030.   gimp_setup_callbacks (); /* New function to allow callbacks to be watched */
  1031.  
  1032.   gimp_destroy_params (pdbreturn_vals,bnreturn_vals);
  1033.  
  1034.   /*   g_free(pdbname); */
  1035.  
  1036.   /* Now add to hash table so we can find it again */
  1037.   if (gbrush_ht == NULL)
  1038.     gbrush_ht = g_hash_table_new (g_str_hash,
  1039.                   g_str_equal);
  1040.   
  1041.   bdata->callback = callback;
  1042.   bdata->data = data;
  1043.   g_hash_table_insert (gbrush_ht, pdbname, bdata);
  1044.  
  1045.   return pdbname;
  1046. }
  1047.  
  1048. gchar *
  1049. gimp_interactive_selection_pattern (gchar                  *dialogname, 
  1050.                     gchar                  *pattern_name,
  1051.                     GimpRunPatternCallback  callback,
  1052.                     gpointer                data)
  1053. {
  1054.   static GimpParamDef args[] =
  1055.   {
  1056.     { GIMP_PDB_STRING,   "str",           "String" },
  1057.     { GIMP_PDB_INT32,    "mask width",    "Pattern width" },
  1058.     { GIMP_PDB_INT32,    "mask height",   "Pattern heigth" },
  1059.     { GIMP_PDB_INT32,    "mask bpp",      "Pattern bytes per pixel" },
  1060.     { GIMP_PDB_INT32,    "mask len",      "Length of pattern mask data" },
  1061.     { GIMP_PDB_INT8ARRAY,"mask data",     "The pattern mask data" },
  1062.     { GIMP_PDB_INT32,    "dialog status", "Registers if the dialog was closing "
  1063.                                        "[0 = No, 1 = Yes]" },
  1064.   };
  1065.   static GimpParamDef *return_vals = NULL;
  1066.   static gint nargs = sizeof (args) / sizeof (args[0]);
  1067.   static gint nreturn_vals = 0;
  1068.   gint bnreturn_vals;
  1069.   GimpParam *pdbreturn_vals;
  1070.   gchar *pdbname = gen_temp_plugin_name ();
  1071.   GimpPatternData *pdata;
  1072.  
  1073.   pdata = g_new0 (GimpPatternData, 1);
  1074.  
  1075.   gimp_install_temp_proc (pdbname,
  1076.               "Temp PDB for interactive popups",
  1077.               "More here later",
  1078.               "Andy Thomas",
  1079.               "Andy Thomas",
  1080.               "1997",
  1081.               NULL,
  1082.               "RGB*, GRAY*",
  1083.               GIMP_TEMPORARY,
  1084.               nargs, nreturn_vals,
  1085.               args, return_vals,
  1086.               temp_pattern_invoker);
  1087.  
  1088.   pdbreturn_vals =
  1089.     gimp_run_procedure("gimp_patterns_popup",
  1090.                &bnreturn_vals,
  1091.                GIMP_PDB_STRING,pdbname,
  1092.                GIMP_PDB_STRING,dialogname,
  1093.                GIMP_PDB_STRING,pattern_name,/*name*/
  1094.                GIMP_PDB_END);
  1095.  
  1096.   gimp_setup_callbacks (); /* New function to allow callbacks to be watched */
  1097.  
  1098.   gimp_destroy_params (pdbreturn_vals, bnreturn_vals);
  1099.  
  1100.   /* Now add to hash table so we can find it again */
  1101.   if (gpattern_ht == NULL)
  1102.     gpattern_ht = g_hash_table_new (g_str_hash,
  1103.                     g_str_equal);
  1104.  
  1105.   pdata->callback = callback;
  1106.   pdata->data = data;
  1107.   g_hash_table_insert (gpattern_ht, pdbname,pdata);
  1108.  
  1109.   return pdbname;
  1110. }
  1111.  
  1112. gchar *
  1113. gimp_interactive_selection_gradient (gchar                   *dialogname, 
  1114.                      gchar                   *gradient_name,
  1115.                      gint                     sample_sz,
  1116.                      GimpRunGradientCallback  callback,
  1117.                      gpointer                 data)
  1118. {
  1119.   static GimpParamDef args[] =
  1120.   {
  1121.     { GIMP_PDB_STRING,    "str",           "String" },
  1122.     { GIMP_PDB_INT32,     "grad width",    "Gradient width" },
  1123.     { GIMP_PDB_FLOATARRAY,"grad data",     "The gradient mask data" },
  1124.     { GIMP_PDB_INT32,     "dialog status", "Registers if the dialog was closing "
  1125.                                         "[0 = No, 1 = Yes]" },
  1126.   };
  1127.   static GimpParamDef *return_vals = NULL;
  1128.   static gint nargs = sizeof (args) / sizeof (args[0]);
  1129.   static gint nreturn_vals = 0;
  1130.   gint    bnreturn_vals;
  1131.   GimpParam *pdbreturn_vals;
  1132.   gchar  *pdbname = gen_temp_plugin_name();
  1133.   GimpGradientData *gdata;
  1134.  
  1135.   gdata = g_new0 (GimpGradientData, 1);
  1136.  
  1137.   gimp_install_temp_proc (pdbname,
  1138.               "Temp PDB for interactive popups",
  1139.               "More here later",
  1140.               "Andy Thomas",
  1141.               "Andy Thomas",
  1142.               "1997",
  1143.               NULL,
  1144.               "RGB*, GRAY*",
  1145.               GIMP_TEMPORARY,
  1146.               nargs, nreturn_vals,
  1147.               args, return_vals,
  1148.               temp_gradient_invoker);
  1149.  
  1150.   pdbreturn_vals =
  1151.     gimp_run_procedure ("gimp_gradients_popup",
  1152.             &bnreturn_vals,
  1153.             GIMP_PDB_STRING, pdbname,
  1154.             GIMP_PDB_STRING, dialogname,
  1155.             GIMP_PDB_STRING, gradient_name, /*name*/
  1156.             GIMP_PDB_INT32,  sample_sz,     /* size of sample to be returned */ 
  1157.             GIMP_PDB_END);
  1158.  
  1159.   gimp_setup_callbacks (); /* New function to allow callbacks to be watched */
  1160.  
  1161.   gimp_destroy_params (pdbreturn_vals,bnreturn_vals);
  1162.  
  1163.   /* Now add to hash table so we can find it again */
  1164.   if (ggradient_ht == NULL)
  1165.     ggradient_ht = g_hash_table_new (g_str_hash,
  1166.                      g_str_equal);
  1167.  
  1168.   gdata->callback = callback;
  1169.   gdata->data = data;
  1170.   g_hash_table_insert (ggradient_ht, pdbname,gdata);
  1171.  
  1172.   return pdbname;
  1173. }
  1174.