home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / gimpset.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-17  |  9.1 KB  |  410 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <gtk/gtk.h>
  22.  
  23. #include "apptypes.h"
  24. #include "gimpobject.h"
  25. #include "gimpsignal.h"
  26. #include "gimpsetP.h"
  27.  
  28.  
  29. /* Yep, this can be optimized quite a lot */
  30.  
  31. typedef struct _GimpSetHandler
  32. {
  33.   const gchar   *signame;
  34.   GtkSignalFunc  func;
  35.   gpointer       user_data;
  36. } GimpSetHandler;
  37.  
  38. typedef struct
  39. {
  40.   gpointer  object;
  41.   GArray   *handlers;
  42.   guint     destroy_handler;
  43. } Node;
  44.  
  45. enum
  46. {
  47.   ADD,
  48.   REMOVE,
  49.   ACTIVE_CHANGED,
  50.   LAST_SIGNAL
  51. };
  52.  
  53. static Node * gimp_set_find_node (GimpSet  *set,
  54.                   gpointer  object);
  55. static Node * gimp_set_node_new  (GimpSet  *set,
  56.                   gpointer  object);
  57. static void   gimp_set_node_free (GimpSet  *set,
  58.                   Node     *node);
  59.  
  60. static guint gimp_set_signals[LAST_SIGNAL] = { 0 };
  61.  
  62. static GimpObjectClass *parent_class = NULL;
  63.  
  64. static void
  65. gimp_set_destroy (GtkObject *object)
  66. {
  67.   GimpSet *set = GIMP_SET (object);
  68.   GSList  *list;
  69.  
  70.   for (list = set->list; list; list = list->next)
  71.     gimp_set_node_free (set, list->data);
  72.  
  73.   g_slist_free (set->list);
  74.   g_array_free (set->handlers, TRUE);
  75.  
  76.   if (GTK_OBJECT_CLASS (parent_class)->destroy)
  77.     GTK_OBJECT_CLASS (parent_class)->destroy (object);
  78. }
  79.  
  80. static void
  81. gimp_set_init (GimpSet *set)
  82. {
  83.   set->list           = NULL;
  84.   set->type           = GTK_TYPE_OBJECT;
  85.   set->handlers       = g_array_new (FALSE, FALSE, sizeof (GimpSetHandler));
  86.   set->active_element = NULL;
  87. }
  88.  
  89. static void
  90. gimp_set_class_init (GimpSetClass* klass)
  91. {
  92.   GtkObjectClass *object_class;
  93.  
  94.   object_class = GTK_OBJECT_CLASS (klass);
  95.  
  96.   parent_class = gtk_type_class (gimp_object_get_type ());
  97.     
  98.   gimp_set_signals[ADD]=
  99.     gimp_signal_new ("add",
  100.              GTK_RUN_FIRST,
  101.              object_class->type,
  102.                      GTK_SIGNAL_OFFSET (GimpSetClass,
  103.                     add),
  104.              gimp_sigtype_pointer);
  105.  
  106.   gimp_set_signals[REMOVE]=
  107.     gimp_signal_new ("remove",
  108.              GTK_RUN_FIRST,
  109.              object_class->type,
  110.                      GTK_SIGNAL_OFFSET (GimpSetClass,
  111.                     remove),
  112.              gimp_sigtype_pointer);
  113.  
  114.   gimp_set_signals[ACTIVE_CHANGED]=
  115.     gimp_signal_new ("active_changed",
  116.              GTK_RUN_FIRST,
  117.              object_class->type,
  118.                      GTK_SIGNAL_OFFSET (GimpSetClass,
  119.                     active_changed),
  120.              gimp_sigtype_pointer);
  121.  
  122.   gtk_object_class_add_signals (object_class, gimp_set_signals, LAST_SIGNAL);
  123.  
  124.   object_class->destroy = gimp_set_destroy;
  125.  
  126.   klass->add            = NULL;
  127.   klass->remove         = NULL;
  128.   klass->active_changed = NULL;
  129. }
  130.  
  131. GtkType
  132. gimp_set_get_type (void)
  133. {
  134.   static GtkType gimpset_type = 0;
  135.  
  136.   GIMP_TYPE_INIT (gimpset_type,
  137.           GimpSet,
  138.           GimpSetClass,
  139.           gimp_set_init,
  140.           gimp_set_class_init,
  141.           GIMP_TYPE_OBJECT);
  142.  
  143.   return gimpset_type;
  144. }
  145.  
  146.  
  147. GimpSet *
  148. gimp_set_new (GtkType  type,
  149.           gboolean weak)
  150. {
  151.   GimpSet *set;
  152.  
  153.   /*  untyped sets must not be weak, since we can't attach a
  154.    *  destroy handler
  155.    */
  156.   g_assert (!(type == GTK_TYPE_NONE && weak == TRUE));
  157.  
  158.   set = gtk_type_new (gimp_set_get_type ());
  159.   set->type = type;
  160.   set->weak = weak;
  161.  
  162.   return set;
  163. }
  164.  
  165. static void
  166. gimp_set_destroy_cb (GtkObject *object,
  167.              gpointer   data)
  168. {
  169.   GimpSet *set = GIMP_SET (data);
  170.  
  171.   gimp_set_remove (set, object);
  172. }
  173.  
  174. static Node *
  175. gimp_set_find_node (GimpSet  *set,
  176.             gpointer  object)
  177. {
  178.   GSList *list = set->list;
  179.  
  180.   for (list = set->list; list; list = list->next)
  181.     {
  182.       Node *node = list->data;
  183.  
  184.       if (node->object == object)
  185.     return node;
  186.     }
  187.  
  188.   return NULL;
  189. }
  190.  
  191. static Node *
  192. gimp_set_node_new (GimpSet  *set,
  193.            gpointer  object)
  194. {
  195.   gint i;
  196.   Node *node = g_new (Node, 1);
  197.  
  198.   node->object = object;
  199.   node->handlers = g_array_new (FALSE, FALSE, sizeof (guint));
  200.   g_array_set_size (node->handlers, set->handlers->len);
  201.  
  202.   for (i = 0; i < node->handlers->len; i++)
  203.     {
  204.       GimpSetHandler *handler =
  205.     &g_array_index (set->handlers, GimpSetHandler, i);
  206.  
  207.       if (handler->signame)
  208.     g_array_index (node->handlers, guint, i)
  209.       = gtk_signal_connect (GTK_OBJECT (object),
  210.                 handler->signame,
  211.                 handler->func,
  212.                 handler->user_data);
  213.     }
  214.  
  215.   if (set->weak)
  216.     node->destroy_handler =
  217.       gtk_signal_connect (GTK_OBJECT (object), "destroy",
  218.               GTK_SIGNAL_FUNC (gimp_set_destroy_cb),
  219.               set);
  220.  
  221.   return node;
  222. }
  223.  
  224. static void
  225. gimp_set_node_free (GimpSet *set,
  226.             Node    *node)
  227. {
  228.   gint i;
  229.   GimpObject *object = node->object;
  230.  
  231.   for (i = 0; i < set->handlers->len; i++)
  232.     {
  233.       GimpSetHandler *handler =
  234.     &g_array_index (set->handlers, GimpSetHandler, i);
  235.  
  236.       if (handler->signame)
  237.     gtk_signal_disconnect (GTK_OBJECT (object),
  238.                    g_array_index (node->handlers, guint, i));
  239.     }
  240.  
  241.   if (set->weak)
  242.     gtk_signal_disconnect (GTK_OBJECT (object),
  243.                node->destroy_handler);
  244.  
  245.   g_array_free (node->handlers, TRUE);
  246.   g_free (node);
  247. }
  248.  
  249. gboolean
  250. gimp_set_add (GimpSet  *set,
  251.           gpointer  object)
  252. {
  253.   g_return_val_if_fail (set, FALSE);
  254.  
  255.   if (set->type != GTK_TYPE_NONE)
  256.     g_return_val_if_fail (GTK_CHECK_TYPE (object, set->type), FALSE);
  257.  
  258.   if (gimp_set_find_node (set, object))
  259.     return FALSE;
  260.  
  261.   set->list = g_slist_prepend (set->list, gimp_set_node_new (set, object));
  262.  
  263.   gtk_signal_emit (GTK_OBJECT (set), gimp_set_signals[ADD], object);
  264.  
  265.   return TRUE;
  266. }
  267.  
  268. gboolean
  269. gimp_set_remove (GimpSet  *set,
  270.          gpointer  object)
  271. {
  272.   Node *node;
  273.  
  274.   g_return_val_if_fail (set, FALSE);
  275.  
  276.   node = gimp_set_find_node (set, object);
  277.   g_return_val_if_fail (node, FALSE);
  278.  
  279.   gimp_set_node_free (set, node);
  280.   set->list = g_slist_remove (set->list, node);
  281.  
  282.   gtk_signal_emit (GTK_OBJECT (set), gimp_set_signals[REMOVE], object);
  283.  
  284.   return TRUE;
  285. }
  286.  
  287. gboolean
  288. gimp_set_have (GimpSet  *set,
  289.            gpointer  object)
  290. {
  291.   return !!gimp_set_find_node (set, object);
  292. }
  293.  
  294. void
  295. gimp_set_foreach (GimpSet  *set,
  296.           GFunc     func,
  297.           gpointer  user_data)
  298. {
  299.   GSList *list;
  300.  
  301.   for (list = set->list; list; list = list->next)
  302.     {
  303.       Node *node = list->data;
  304.  
  305.       func (node->object, user_data);
  306.     }
  307. }
  308.  
  309. GtkType
  310. gimp_set_type (GimpSet* set)
  311. {
  312.   return set->type;
  313. }
  314.  
  315. void
  316. gimp_set_set_active (GimpSet  *set,
  317.              gpointer  object)
  318. {
  319.   if (object != set->active_element && gimp_set_have (set, object))
  320.     {
  321.       set->active_element = object;
  322.       gtk_signal_emit (GTK_OBJECT (set),
  323.                gimp_set_signals[ACTIVE_CHANGED],
  324.                object);
  325.     }
  326. }
  327.  
  328. gpointer
  329. gimp_set_get_active (GimpSet *set)
  330. {
  331.   if (gimp_set_have (set, set->active_element))
  332.     return set->active_element;
  333.  
  334.   return NULL;
  335. }
  336.  
  337. GimpSetHandlerId
  338. gimp_set_add_handler (GimpSet       *set,
  339.               const gchar   *signame,
  340.               GtkSignalFunc  handler,
  341.               gpointer       user_data)
  342. {
  343.   GimpSetHandler set_handler;
  344.   GSList *list;
  345.   guint a;
  346.  
  347.   g_assert (signame);
  348.  
  349.   /*  you can't set a handler on something that's not a GTK object  */
  350.   g_assert (set->type != GTK_TYPE_NONE);
  351.  
  352.   set_handler.signame   = signame;
  353.   set_handler.func      = handler;
  354.   set_handler.user_data = user_data;
  355.     
  356.   for (a = 0; a < set->handlers->len; a++)
  357.     if (! g_array_index (set->handlers, GimpSetHandler, a).signame)
  358.       break;
  359.  
  360.   if (a < set->handlers->len)
  361.     {
  362.       g_array_index (set->handlers, GimpSetHandler, a) = set_handler;
  363.  
  364.       for (list = set->list; list; list = list->next)
  365.     {
  366.       Node *node = list->data;
  367.       guint i = gtk_signal_connect (GTK_OBJECT (node->object), signame,
  368.                     handler,
  369.                     user_data);
  370.       g_array_index (node->handlers, guint, a) = i;
  371.     }
  372.     }
  373.   else
  374.     {
  375.       g_array_append_val (set->handlers, set_handler);
  376.  
  377.       for (list = set->list; list; list = list->next)
  378.     {
  379.       Node *node = list->data;
  380.  
  381.       guint i = gtk_signal_connect (GTK_OBJECT(node->object), signame,
  382.                     handler,
  383.                     user_data);
  384.       g_array_append_val (node->handlers, i);
  385.     }
  386.     }
  387.  
  388.   return a;
  389. }
  390.  
  391. void
  392. gimp_set_remove_handler (GimpSet          *set,
  393.              GimpSetHandlerId  id)
  394. {
  395.   GSList *list;
  396.  
  397.   /*  you can't remove a signal handler on something that's not a GTK object  */
  398.   g_return_if_fail (set->type != GTK_TYPE_NONE);
  399.  
  400.   for (list = set->list; list; list = list->next)
  401.     {
  402.       Node *node = list->data;
  403.  
  404.       gtk_signal_disconnect (GTK_OBJECT (node->object),
  405.                  g_array_index (node->handlers, guint, id));
  406.     }
  407.  
  408.   g_array_index (set->handlers, GimpSetHandler, id).signame = NULL;
  409. }
  410.