mirror of https://github.com/GNOME/gimp.git
399 lines
8.5 KiB
C
399 lines
8.5 KiB
C
/* The GIMP -- an image manipulation program
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include "gimpsignal.h"
|
|
#include "gimpsetP.h"
|
|
|
|
/* Yep, this can be optimized quite a lot */
|
|
|
|
typedef struct _GimpSetHandler
|
|
{
|
|
const gchar *signame;
|
|
GtkSignalFunc func;
|
|
gpointer user_data;
|
|
} GimpSetHandler;
|
|
|
|
typedef struct
|
|
{
|
|
gpointer object;
|
|
GArray *handlers;
|
|
guint destroy_handler;
|
|
} Node;
|
|
|
|
enum
|
|
{
|
|
ADD,
|
|
REMOVE,
|
|
ACTIVE_CHANGED,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
static Node * gimp_set_find_node (GimpSet* set, gpointer object);
|
|
static Node * gimp_set_node_new (GimpSet* set, gpointer obbject);
|
|
static void gimp_set_node_free (GimpSet* set, Node* node);
|
|
|
|
static guint gimp_set_signals [LAST_SIGNAL];
|
|
|
|
static GimpObjectClass* parent_class;
|
|
|
|
static void
|
|
gimp_set_destroy (GtkObject* object)
|
|
{
|
|
GimpSet* set = GIMP_SET (object);
|
|
GSList* list;
|
|
|
|
for (list = set->list; list; list = list->next)
|
|
gimp_set_node_free (set, list->data);
|
|
|
|
g_slist_free (set->list);
|
|
g_array_free (set->handlers, TRUE);
|
|
|
|
if (GTK_OBJECT_CLASS (parent_class)->destroy)
|
|
(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
|
|
}
|
|
|
|
static void
|
|
gimp_set_init (GimpSet* set)
|
|
{
|
|
set->list = NULL;
|
|
set->type = GTK_TYPE_OBJECT;
|
|
set->handlers = g_array_new (FALSE, FALSE, sizeof (GimpSetHandler));
|
|
set->active_element = NULL;
|
|
}
|
|
|
|
static void
|
|
gimp_set_class_init (GimpSetClass* klass)
|
|
{
|
|
GtkObjectClass *object_class;
|
|
|
|
object_class = GTK_OBJECT_CLASS (klass);
|
|
|
|
parent_class = gtk_type_class (gimp_object_get_type ());
|
|
|
|
gimp_set_signals[ADD]=
|
|
gimp_signal_new ("add",
|
|
GTK_RUN_FIRST,
|
|
object_class->type,
|
|
GTK_SIGNAL_OFFSET (GimpSetClass,
|
|
add),
|
|
gimp_sigtype_pointer);
|
|
|
|
gimp_set_signals[REMOVE]=
|
|
gimp_signal_new ("remove",
|
|
GTK_RUN_FIRST,
|
|
object_class->type,
|
|
GTK_SIGNAL_OFFSET (GimpSetClass,
|
|
remove),
|
|
gimp_sigtype_pointer);
|
|
|
|
gimp_set_signals[ACTIVE_CHANGED]=
|
|
gimp_signal_new ("active_changed",
|
|
GTK_RUN_FIRST,
|
|
object_class->type,
|
|
GTK_SIGNAL_OFFSET (GimpSetClass,
|
|
active_changed),
|
|
gimp_sigtype_pointer);
|
|
|
|
gtk_object_class_add_signals (object_class, gimp_set_signals, LAST_SIGNAL);
|
|
|
|
object_class->destroy = gimp_set_destroy;
|
|
|
|
klass->add = NULL;
|
|
klass->remove = NULL;
|
|
klass->active_changed = NULL;
|
|
}
|
|
|
|
GtkType
|
|
gimp_set_get_type (void)
|
|
{
|
|
static GtkType gimpset_type = 0;
|
|
|
|
GIMP_TYPE_INIT(gimpset_type,
|
|
GimpSet,
|
|
GimpSetClass,
|
|
gimp_set_init,
|
|
gimp_set_class_init,
|
|
GIMP_TYPE_OBJECT);
|
|
|
|
return gimpset_type;
|
|
}
|
|
|
|
|
|
GimpSet *
|
|
gimp_set_new (GtkType type,
|
|
gboolean weak)
|
|
{
|
|
GimpSet *set;
|
|
|
|
/* untyped sets must not be weak, since we can't attach a
|
|
* destroy handler
|
|
*/
|
|
g_assert (!(type == GTK_TYPE_NONE && weak == TRUE));
|
|
|
|
set = gtk_type_new (gimp_set_get_type ());
|
|
set->type = type;
|
|
set->weak = weak;
|
|
|
|
return set;
|
|
}
|
|
|
|
static void
|
|
gimp_set_destroy_cb (GtkObject *object,
|
|
gpointer data)
|
|
{
|
|
GimpSet *set = GIMP_SET (data);
|
|
|
|
gimp_set_remove (set, object);
|
|
}
|
|
|
|
static Node *
|
|
gimp_set_find_node (GimpSet *set,
|
|
gpointer object)
|
|
{
|
|
GSList *list = set->list;
|
|
|
|
for(list = set->list; list; list = list->next)
|
|
{
|
|
Node *node = list->data;
|
|
|
|
if (node->object == object)
|
|
return node;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static Node*
|
|
gimp_set_node_new (GimpSet *set,
|
|
gpointer object)
|
|
{
|
|
gint i;
|
|
Node *node = g_new (Node, 1);
|
|
|
|
node->object = object;
|
|
node->handlers = g_array_new (FALSE, FALSE, sizeof (guint));
|
|
g_array_set_size (node->handlers, set->handlers->len);
|
|
|
|
for (i = 0; i < node->handlers->len; i++)
|
|
{
|
|
GimpSetHandler *handler =
|
|
&g_array_index (set->handlers, GimpSetHandler, i);
|
|
|
|
if (handler->signame)
|
|
g_array_index (node->handlers, guint, i)
|
|
= gtk_signal_connect (GTK_OBJECT(object),
|
|
handler->signame,
|
|
handler->func,
|
|
handler->user_data);
|
|
}
|
|
|
|
if(set->weak)
|
|
node->destroy_handler =
|
|
gtk_signal_connect(GTK_OBJECT (object), "destroy",
|
|
GTK_SIGNAL_FUNC (gimp_set_destroy_cb),
|
|
set);
|
|
|
|
return node;
|
|
}
|
|
|
|
static void
|
|
gimp_set_node_free (GimpSet *set,
|
|
Node *node)
|
|
{
|
|
gint i;
|
|
GimpObject *object = node->object;
|
|
|
|
for (i=0; i < set->handlers->len; i++)
|
|
{
|
|
GimpSetHandler* handler =
|
|
&g_array_index (set->handlers, GimpSetHandler, i);
|
|
|
|
if (handler->signame)
|
|
gtk_signal_disconnect (GTK_OBJECT (object),
|
|
g_array_index (node->handlers, guint, i));
|
|
}
|
|
|
|
if (set->weak)
|
|
gtk_signal_disconnect (GTK_OBJECT (object),
|
|
node->destroy_handler);
|
|
|
|
g_array_free (node->handlers, TRUE);
|
|
g_free (node);
|
|
}
|
|
|
|
gboolean
|
|
gimp_set_add (GimpSet *set,
|
|
gpointer val)
|
|
{
|
|
g_return_val_if_fail (set, FALSE);
|
|
|
|
if (set->type != GTK_TYPE_NONE)
|
|
g_return_val_if_fail (GTK_CHECK_TYPE (val, set->type), FALSE);
|
|
|
|
if (gimp_set_find_node (set, val))
|
|
return FALSE;
|
|
|
|
set->list = g_slist_prepend (set->list, gimp_set_node_new (set, val));
|
|
|
|
gtk_signal_emit (GTK_OBJECT (set), gimp_set_signals[ADD], val);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
gimp_set_remove (GimpSet *set,
|
|
gpointer val)
|
|
{
|
|
Node *node;
|
|
|
|
g_return_val_if_fail (set, FALSE);
|
|
|
|
node = gimp_set_find_node (set, val);
|
|
g_return_val_if_fail (node, FALSE);
|
|
|
|
gimp_set_node_free (set, node);
|
|
set->list = g_slist_remove (set->list, node);
|
|
|
|
gtk_signal_emit (GTK_OBJECT (set), gimp_set_signals[REMOVE], val);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean
|
|
gimp_set_have (GimpSet *set,
|
|
gpointer val)
|
|
{
|
|
return !!gimp_set_find_node (set, val);
|
|
}
|
|
|
|
void
|
|
gimp_set_foreach (GimpSet *set,
|
|
GFunc func,
|
|
gpointer user_data)
|
|
{
|
|
GSList* list;
|
|
|
|
for (list = set->list; list; list = list->next)
|
|
{
|
|
Node *node = list->data;
|
|
|
|
func (node->object, user_data);
|
|
}
|
|
}
|
|
|
|
GtkType
|
|
gimp_set_type (GimpSet* set)
|
|
{
|
|
return set->type;
|
|
}
|
|
|
|
void
|
|
gimp_set_set_active (GimpSet *set,
|
|
gpointer object)
|
|
{
|
|
if (object != set->active_element && gimp_set_have (set, object))
|
|
{
|
|
set->active_element = object;
|
|
gtk_signal_emit (GTK_OBJECT (set),
|
|
gimp_set_signals[ACTIVE_CHANGED],
|
|
object);
|
|
}
|
|
}
|
|
|
|
gpointer
|
|
gimp_set_get_active (GimpSet* set)
|
|
{
|
|
if (gimp_set_have (set, set->active_element))
|
|
return set->active_element;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
GimpSetHandlerId
|
|
gimp_set_add_handler (GimpSet *set,
|
|
const gchar *signame,
|
|
GtkSignalFunc handler,
|
|
gpointer user_data)
|
|
{
|
|
GimpSetHandler set_handler;
|
|
GSList *list;
|
|
guint a;
|
|
|
|
g_assert (signame);
|
|
|
|
/* you can't set a handler on something that's not a GTK object */
|
|
g_assert (set->type != GTK_TYPE_NONE);
|
|
|
|
set_handler.signame = signame;
|
|
set_handler.func = handler;
|
|
set_handler.user_data = user_data;
|
|
|
|
for (a = 0; a < set->handlers->len; a++)
|
|
if (! g_array_index (set->handlers, GimpSetHandler, a).signame)
|
|
break;
|
|
|
|
if (a < set->handlers->len)
|
|
{
|
|
g_array_index (set->handlers, GimpSetHandler, a) = set_handler;
|
|
for (list = set->list; list; list = list->next)
|
|
{
|
|
Node *node = list->data;
|
|
guint i = gtk_signal_connect (GTK_OBJECT (node->object), signame,
|
|
handler,
|
|
user_data);
|
|
g_array_index (node->handlers, guint, a) = i;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_array_append_val (set->handlers, set_handler);
|
|
|
|
for (list = set->list; list; list = list->next)
|
|
{
|
|
Node* node = list->data;
|
|
|
|
guint i = gtk_signal_connect (GTK_OBJECT(node->object), signame,
|
|
handler,
|
|
user_data);
|
|
g_array_append_val (node->handlers, i);
|
|
}
|
|
}
|
|
|
|
return a;
|
|
}
|
|
|
|
void
|
|
gimp_set_remove_handler (GimpSet *set,
|
|
GimpSetHandlerId id)
|
|
{
|
|
GSList* list;
|
|
|
|
/* you can't remove a signal handler on something that's not a GTK object */
|
|
g_return_if_fail (set->type != GTK_TYPE_NONE);
|
|
|
|
for (list = set->list; list; list = list->next)
|
|
{
|
|
Node *node = list->data;
|
|
|
|
gtk_signal_disconnect (GTK_OBJECT (node->object),
|
|
g_array_index (node->handlers, guint, id));
|
|
}
|
|
|
|
g_array_index (set->handlers, GimpSetHandler, id).signame = NULL;
|
|
}
|