Code

Fix build failure
[inkscape.git] / src / libgdl / gdl-dock-object.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 
2  *
3  * gdl-dock-object.c - Abstract base class for all dock related objects
4  *
5  * This file is part of the GNOME Devtools Libraries.
6  *
7  * Copyright (C) 2002 Gustavo Giráldez <gustavo.giraldez@gmx.net>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  */
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
28 #include "gdl-i18n.h"
29 #include <stdlib.h>
30 #include <string.h>
32 #include "gdl-tools.h"
33 #include "gdl-dock-object.h"
34 #include "gdl-dock-master.h"
35 #include "libgdltypebuiltins.h"
36 #include "libgdlmarshal.h"
38 /* for later use by the registry */
39 #include "gdl-dock.h"
40 #include "gdl-dock-item.h"
41 #include "gdl-dock-paned.h"
42 #include "gdl-dock-notebook.h"
43 #include "gdl-dock-placeholder.h"
46 /* ----- Private prototypes ----- */
48 static void     gdl_dock_object_class_init         (GdlDockObjectClass *klass);
49 static void     gdl_dock_object_instance_init      (GdlDockObject      *object);
51 static void     gdl_dock_object_set_property       (GObject            *g_object,
52                                                     guint               prop_id,
53                                                     const GValue       *value,
54                                                     GParamSpec         *pspec);
55 static void     gdl_dock_object_get_property       (GObject            *g_object,
56                                                     guint               prop_id,
57                                                     GValue             *value,
58                                                     GParamSpec         *pspec);
59 static void     gdl_dock_object_finalize           (GObject            *g_object);
61 static void     gdl_dock_object_destroy            (GtkObject          *gtk_object);
63 static void     gdl_dock_object_show               (GtkWidget          *widget);
64 static void     gdl_dock_object_hide               (GtkWidget          *widget);
66 static void     gdl_dock_object_real_detach        (GdlDockObject      *object,
67                                                     gboolean            recursive);
68 static void     gdl_dock_object_real_reduce        (GdlDockObject      *object);
69 static void     gdl_dock_object_dock_unimplemented (GdlDockObject     *object,
70                                                     GdlDockObject     *requestor,
71                                                     GdlDockPlacement   position,
72                                                     GValue            *other_data);
73 static void     gdl_dock_object_real_present       (GdlDockObject     *object,
74                                                     GdlDockObject     *child);
77 /* ----- Private data types and variables ----- */
79 enum {
80     PROP_0,
81     PROP_NAME,
82     PROP_LONG_NAME,
83     PROP_STOCK_ID,
84     PROP_PIXBUF_ICON,
85     PROP_MASTER,
86     PROP_EXPORT_PROPERTIES
87 };
89 enum {
90     DETACH,
91     DOCK,
92     LAST_SIGNAL
93 };
95 static guint gdl_dock_object_signals [LAST_SIGNAL] = { 0 };
97 /* ----- Private interface ----- */
99 GDL_CLASS_BOILERPLATE (GdlDockObject, gdl_dock_object, GtkContainer, GTK_TYPE_CONTAINER);
101 static void
102 gdl_dock_object_class_init (GdlDockObjectClass *klass)
104     GObjectClass      *g_object_class;
105     GtkObjectClass    *object_class;
106     GtkWidgetClass    *widget_class;
107     GtkContainerClass *container_class;
109     g_object_class = G_OBJECT_CLASS (klass);
110     object_class = GTK_OBJECT_CLASS (klass);
111     widget_class = GTK_WIDGET_CLASS (klass);
112     container_class = GTK_CONTAINER_CLASS (klass);
114     g_object_class->set_property = gdl_dock_object_set_property;
115     g_object_class->get_property = gdl_dock_object_get_property;
116     g_object_class->finalize = gdl_dock_object_finalize;
118     g_object_class_install_property (
119         g_object_class, PROP_NAME,
120         g_param_spec_string (GDL_DOCK_NAME_PROPERTY, _("Name"),
121                              _("Unique name for identifying the dock object"),
122                              NULL,
123                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
124                              GDL_DOCK_PARAM_EXPORT));
126     g_object_class_install_property (
127         g_object_class, PROP_LONG_NAME,
128         g_param_spec_string ("long-name", _("Long name"),
129                              _("Human readable name for the dock object"),
130                              NULL,
131                              G_PARAM_READWRITE));
133     g_object_class_install_property (
134         g_object_class, PROP_STOCK_ID,
135         g_param_spec_string ("stock-id", _("Stock Icon"),
136                              _("Stock icon for the dock object"),
137                              NULL,
138                              G_PARAM_READWRITE));
140     g_object_class_install_property (
141         g_object_class, PROP_PIXBUF_ICON,
142         g_param_spec_pointer ("pixbuf-icon", _("Pixbuf Icon"),
143                               _("Pixbuf icon for the dock object"),
144                               G_PARAM_READWRITE));
146     g_object_class_install_property (
147         g_object_class, PROP_MASTER,
148         g_param_spec_object ("master", _("Dock master"),
149                              _("Dock master this dock object is bound to"),
150                              GDL_TYPE_DOCK_MASTER,
151                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
152     
153     object_class->destroy = gdl_dock_object_destroy;
154     
155     widget_class->show = gdl_dock_object_show;
156     widget_class->hide = gdl_dock_object_hide;
157     
158     klass->is_compound = TRUE;
159     
160     klass->detach = gdl_dock_object_real_detach;
161     klass->reduce = gdl_dock_object_real_reduce;
162     klass->dock_request = NULL;
163     klass->dock = gdl_dock_object_dock_unimplemented;
164     klass->reorder = NULL;
165     klass->present = gdl_dock_object_real_present;
166     klass->child_placement = NULL;
167     
168     gdl_dock_object_signals [DETACH] =
169         g_signal_new ("detach",
170                       G_TYPE_FROM_CLASS (klass),
171                       G_SIGNAL_RUN_LAST,
172                       G_STRUCT_OFFSET (GdlDockObjectClass, detach),
173                       NULL,
174                       NULL,
175                       gdl_marshal_VOID__BOOLEAN,
176                       G_TYPE_NONE,
177                       1,
178                       G_TYPE_BOOLEAN);
180     gdl_dock_object_signals [DOCK] =
181         g_signal_new ("dock",
182                       G_TYPE_FROM_CLASS (klass),
183                       G_SIGNAL_RUN_FIRST,
184                       G_STRUCT_OFFSET (GdlDockObjectClass, dock),
185                       NULL,
186                       NULL,
187                       gdl_marshal_VOID__OBJECT_ENUM_BOXED,
188                       G_TYPE_NONE,
189                       3,
190                       GDL_TYPE_DOCK_OBJECT,
191                       GDL_TYPE_DOCK_PLACEMENT,
192                       G_TYPE_VALUE);
195 static void
196 gdl_dock_object_instance_init (GdlDockObject *object)
198     object->flags = GDL_DOCK_AUTOMATIC;
199     object->freeze_count = 0;
202 static void
203 gdl_dock_object_set_property  (GObject      *g_object,
204                                guint         prop_id,
205                                const GValue *value,
206                                GParamSpec   *pspec)
208     GdlDockObject *object = GDL_DOCK_OBJECT (g_object);
210     switch (prop_id) {
211     case PROP_NAME:
212         g_free (object->name);
213         object->name = g_value_dup_string (value);
214         break;
215     case PROP_LONG_NAME:
216         g_free (object->long_name);
217         object->long_name = g_value_dup_string (value);
218         break;
219     case PROP_STOCK_ID:
220         g_free (object->stock_id);
221         object->stock_id = g_value_dup_string (value);
222         break;
223     case PROP_PIXBUF_ICON:
224         object->pixbuf_icon = g_value_get_pointer (value);
225         break;
226     case PROP_MASTER:
227         if (g_value_get_object (value)) 
228             gdl_dock_object_bind (object, g_value_get_object (value));
229         else
230             gdl_dock_object_unbind (object);
231         break;
232     default:
233         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
234         break;
235     }
238 static void
239 gdl_dock_object_get_property  (GObject      *g_object,
240                                guint         prop_id,
241                                GValue       *value,
242                                GParamSpec   *pspec)
244     GdlDockObject *object = GDL_DOCK_OBJECT (g_object);
246     switch (prop_id) {
247     case PROP_NAME:
248         g_value_set_string (value, object->name);
249         break;
250     case PROP_LONG_NAME:
251         g_value_set_string (value, object->long_name);
252         break;
253     case PROP_STOCK_ID:
254         g_value_set_string (value, object->stock_id);
255         break;
256     case PROP_PIXBUF_ICON:
257         g_value_set_pointer (value, object->pixbuf_icon);
258         break;
259     case PROP_MASTER:
260         g_value_set_object (value, object->master);
261         break;
262     default:
263         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
264         break;
265     }
268 static void
269 gdl_dock_object_finalize (GObject *g_object)
271     GdlDockObject *object;
272     
273     g_return_if_fail (g_object != NULL && GDL_IS_DOCK_OBJECT (g_object));
275     object = GDL_DOCK_OBJECT (g_object);
277     g_free (object->name);
278     object->name = NULL;
279     g_free (object->long_name);
280     object->long_name = NULL;
281     g_free (object->stock_id);
282     object->stock_id = NULL;
283     object->pixbuf_icon = NULL;
285     GDL_CALL_PARENT (G_OBJECT_CLASS, finalize, (g_object));
288 static void
289 gdl_dock_object_foreach_detach (GdlDockObject *object,
290                                 gpointer       user_data)
292     gdl_dock_object_detach (object, TRUE);
295 static void
296 gdl_dock_object_destroy (GtkObject *gtk_object)
298     GdlDockObject *object;
300     g_return_if_fail (GDL_IS_DOCK_OBJECT (gtk_object));
302     object = GDL_DOCK_OBJECT (gtk_object);
303     if (gdl_dock_object_is_compound (object)) {
304         /* detach our dock object children if we have some, and even
305            if we are not attached, so they can get notification */
306         gdl_dock_object_freeze (object);
307         gtk_container_foreach (GTK_CONTAINER (object),
308                                (GtkCallback) gdl_dock_object_foreach_detach,
309                                NULL);
310         object->reduce_pending = FALSE;
311         gdl_dock_object_thaw (object);
312     }
313     if (GDL_DOCK_OBJECT_ATTACHED (object)) {
314         /* detach ourselves */
315         gdl_dock_object_detach (object, FALSE);
316     }
317     
318     /* finally unbind us */
319     if (object->master)
320         gdl_dock_object_unbind (object);
321         
322     GDL_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (gtk_object));
325 static void
326 gdl_dock_object_foreach_automatic (GdlDockObject *object,
327                                    gpointer       user_data)
329     void (* function) (GtkWidget *) = user_data;
331     if (GDL_DOCK_OBJECT_AUTOMATIC (object))
332         (* function) (GTK_WIDGET (object));
335 static void
336 gdl_dock_object_show (GtkWidget *widget)
338     if (gdl_dock_object_is_compound (GDL_DOCK_OBJECT (widget))) {
339         gtk_container_foreach (GTK_CONTAINER (widget),
340                                (GtkCallback) gdl_dock_object_foreach_automatic,
341                                gtk_widget_show);
342     }
343     GDL_CALL_PARENT (GTK_WIDGET_CLASS, show, (widget));
346 static void
347 gdl_dock_object_hide (GtkWidget *widget)
349     if (gdl_dock_object_is_compound (GDL_DOCK_OBJECT (widget))) {
350         gtk_container_foreach (GTK_CONTAINER (widget),
351                                (GtkCallback) gdl_dock_object_foreach_automatic,
352                                gtk_widget_hide);
353     }
354     GDL_CALL_PARENT (GTK_WIDGET_CLASS, hide, (widget));
357 static void
358 gdl_dock_object_real_detach (GdlDockObject *object,
359                              gboolean       recursive)
361     GdlDockObject *parent;
362     GtkWidget     *widget;
363     
364     g_return_if_fail (object != NULL);
366     /* detach children */
367     if (recursive && gdl_dock_object_is_compound (object)) {
368         gtk_container_foreach (GTK_CONTAINER (object),
369                                (GtkCallback) gdl_dock_object_detach,
370                                GINT_TO_POINTER (recursive));
371     }
372     
373     /* detach the object itself */
374     GDL_DOCK_OBJECT_UNSET_FLAGS (object, GDL_DOCK_ATTACHED);
375     parent = gdl_dock_object_get_parent_object (object);
376     widget = GTK_WIDGET (object);
377     if (widget->parent)
378         gtk_container_remove (GTK_CONTAINER (widget->parent), widget);
379     if (parent)
380         gdl_dock_object_reduce (parent);
383 static void
384 gdl_dock_object_real_reduce (GdlDockObject *object)
386     GdlDockObject *parent;
387     GList         *children;
388     
389     g_return_if_fail (object != NULL);
391     if (!gdl_dock_object_is_compound (object))
392         return;
394     parent = gdl_dock_object_get_parent_object (object);
395     children = gtk_container_get_children (GTK_CONTAINER (object));
396     if (g_list_length (children) <= 1) {
397         GList *l;
398         
399         /* detach ourselves and then re-attach our children to our
400            current parent.  if we are not currently attached, the
401            children are detached */
402         if (parent)
403             gdl_dock_object_freeze (parent);
404         gdl_dock_object_freeze (object);
405         gdl_dock_object_detach (object, FALSE);
406         for (l = children; l; l = l->next) {
407             GdlDockObject *child = GDL_DOCK_OBJECT (l->data);
409             g_object_ref (child);
410             GDL_DOCK_OBJECT_SET_FLAGS (child, GDL_DOCK_IN_REFLOW);
411             gdl_dock_object_detach (child, FALSE);
412             if (parent)
413                 gtk_container_add (GTK_CONTAINER (parent), GTK_WIDGET (child));
414             GDL_DOCK_OBJECT_UNSET_FLAGS (child, GDL_DOCK_IN_REFLOW);
415             g_object_unref (child);
416         }
417         /* sink the widget, so any automatic floating widget is destroyed */
418         gtk_object_sink (GTK_OBJECT (object));
419         /* don't reenter */
420         object->reduce_pending = FALSE;
421         gdl_dock_object_thaw (object);
422         if (parent)
423             gdl_dock_object_thaw (parent);
424     }
425     g_list_free (children);
428 static void
429 gdl_dock_object_dock_unimplemented (GdlDockObject    *object,
430                                     GdlDockObject    *requestor,
431                                     GdlDockPlacement  position,
432                                     GValue           *other_data)
434     g_warning (_("Call to gdl_dock_object_dock in a dock object %p "
435                  "(object type is %s) which hasn't implemented this method"),
436                object, G_OBJECT_TYPE_NAME (object));
439 static void 
440 gdl_dock_object_real_present (GdlDockObject *object,
441                               GdlDockObject *child)
443     gtk_widget_show (GTK_WIDGET (object));
447 /* ----- Public interface ----- */
449 gboolean
450 gdl_dock_object_is_compound (GdlDockObject *object)
452     GdlDockObjectClass *klass;
454     g_return_val_if_fail (object != NULL, FALSE);
455     g_return_val_if_fail (GDL_IS_DOCK_OBJECT (object), FALSE);
457     klass = GDL_DOCK_OBJECT_GET_CLASS (object);
458     return klass->is_compound;
461 void
462 gdl_dock_object_detach (GdlDockObject *object,
463                         gboolean       recursive)
465     g_return_if_fail (object != NULL);
467     if (!GDL_DOCK_OBJECT_ATTACHED (object))
468         return;
469     
470     /* freeze the object to avoid reducing while detaching children */
471     gdl_dock_object_freeze (object);
472     GDL_DOCK_OBJECT_SET_FLAGS (object, GDL_DOCK_IN_DETACH);
473     g_signal_emit (object, gdl_dock_object_signals [DETACH], 0, recursive);
474     GDL_DOCK_OBJECT_UNSET_FLAGS (object, GDL_DOCK_IN_DETACH);
475     gdl_dock_object_thaw (object);
478 GdlDockObject *
479 gdl_dock_object_get_parent_object (GdlDockObject *object)
481     GtkWidget *parent;
482     
483     g_return_val_if_fail (object != NULL, NULL);
485     parent = GTK_WIDGET (object)->parent;
486     while (parent && !GDL_IS_DOCK_OBJECT (parent)) {
487         parent = parent->parent;
488     }
489     
490     return parent ? GDL_DOCK_OBJECT (parent) : NULL;
493 void
494 gdl_dock_object_freeze (GdlDockObject *object)
496     g_return_if_fail (object != NULL);
497     
498     if (object->freeze_count == 0) {
499         g_object_ref (object);   /* dock objects shouldn't be
500                                     destroyed if they are frozen */
501     }
502     object->freeze_count++;
505 void
506 gdl_dock_object_thaw (GdlDockObject *object)
508     g_return_if_fail (object != NULL);
509     g_return_if_fail (object->freeze_count > 0);
510     
511     object->freeze_count--;
512     if (object->freeze_count == 0) {
513         if (object->reduce_pending) {
514             object->reduce_pending = FALSE;
515             gdl_dock_object_reduce (object);
516         }
517         g_object_unref (object);
518     }
521 void
522 gdl_dock_object_reduce (GdlDockObject *object)
524     g_return_if_fail (object != NULL);
526     if (GDL_DOCK_OBJECT_FROZEN (object)) {
527         object->reduce_pending = TRUE;
528         return;
529     }
531     GDL_CALL_VIRTUAL (object, GDL_DOCK_OBJECT_GET_CLASS, reduce, (object));
534 gboolean
535 gdl_dock_object_dock_request (GdlDockObject  *object,
536                               gint            x,
537                               gint            y,
538                               GdlDockRequest *request)
540     g_return_val_if_fail (object != NULL && request != NULL, FALSE);
542     return GDL_CALL_VIRTUAL_WITH_DEFAULT (object,
543                                           GDL_DOCK_OBJECT_GET_CLASS,
544                                           dock_request,
545                                           (object, x, y, request),
546                                           FALSE);
549 void
550 gdl_dock_object_dock (GdlDockObject    *object,
551                       GdlDockObject    *requestor,
552                       GdlDockPlacement  position,
553                       GValue           *other_data)
555     GdlDockObject *parent;
556     
557     g_return_if_fail (object != NULL && requestor != NULL);
558         
559     if (object == requestor)
560         return;
561     
562     if (!object->master)
563         g_warning (_("Dock operation requested in a non-bound object %p. "
564                      "The application might crash"), object);
565         
566     if (!gdl_dock_object_is_bound (requestor))
567         gdl_dock_object_bind (requestor, object->master);
569     if (requestor->master != object->master) {
570         g_warning (_("Cannot dock %p to %p because they belong to different masters"),
571                    requestor, object);
572         return;
573     }
575     /* first, see if we can optimize things by reordering */
576     if (position != GDL_DOCK_NONE) {
577         parent = gdl_dock_object_get_parent_object (object);
578         if (gdl_dock_object_reorder (object, requestor, position, other_data) ||
579             (parent && gdl_dock_object_reorder (parent, requestor, position, other_data)))
580             return;
581     }
582     
583     /* freeze the object, since under some conditions it might be destroyed when
584        detaching the requestor */
585     gdl_dock_object_freeze (object);
587     /* detach the requestor before docking */
588     g_object_ref (requestor);
589     if (GDL_DOCK_OBJECT_ATTACHED (requestor))
590         gdl_dock_object_detach (requestor, FALSE);
591     
592     if (position != GDL_DOCK_NONE)
593         g_signal_emit (object, gdl_dock_object_signals [DOCK], 0,
594                        requestor, position, other_data);
596     g_object_unref (requestor);
597     gdl_dock_object_thaw (object);
600 void
601 gdl_dock_object_bind (GdlDockObject *object,
602                       GObject       *master)
604     g_return_if_fail (object != NULL && master != NULL);
605     g_return_if_fail (GDL_IS_DOCK_MASTER (master));
606     
607     if (object->master == master)
608         /* nothing to do here */
609         return;
610     
611     if (object->master) {
612         g_warning (_("Attempt to bind to %p an already bound dock object %p "
613                      "(current master: %p)"), master, object, object->master);
614         return;
615     }
617     gdl_dock_master_add (GDL_DOCK_MASTER (master), object);
618     object->master = master;
619     g_object_add_weak_pointer (master, (gpointer *) &object->master);
621     g_object_notify (G_OBJECT (object), "master");
624 void
625 gdl_dock_object_unbind (GdlDockObject *object)
627     g_return_if_fail (object != NULL);
629     g_object_ref (object);
631     /* detach the object first */
632     if (GDL_DOCK_OBJECT_ATTACHED (object))
633         gdl_dock_object_detach (object, TRUE);
634     
635     if (object->master) {
636         GObject *master = object->master;
637         g_object_remove_weak_pointer (master, (gpointer *) &object->master);
638         object->master = NULL;
639         gdl_dock_master_remove (GDL_DOCK_MASTER (master), object);
640         g_object_notify (G_OBJECT (object), "master");
641     }
642     g_object_unref (object);
645 gboolean
646 gdl_dock_object_is_bound (GdlDockObject *object)
648     g_return_val_if_fail (object != NULL, FALSE);
649     return (object->master != NULL);
652 gboolean
653 gdl_dock_object_reorder (GdlDockObject    *object,
654                          GdlDockObject    *child,
655                          GdlDockPlacement  new_position,
656                          GValue           *other_data)
658     g_return_val_if_fail (object != NULL && child != NULL, FALSE);
660     return GDL_CALL_VIRTUAL_WITH_DEFAULT (object,
661                                           GDL_DOCK_OBJECT_GET_CLASS,
662                                           reorder,
663                                           (object, child, new_position, other_data),
664                                           FALSE);
667 void 
668 gdl_dock_object_present (GdlDockObject *object,
669                          GdlDockObject *child)
671     GdlDockObject *parent;
672     
673     g_return_if_fail (object != NULL && GDL_IS_DOCK_OBJECT (object));
675     parent = gdl_dock_object_get_parent_object (object);
676     if (parent)
677         /* chain the call to our parent */
678         gdl_dock_object_present (parent, object);
680     GDL_CALL_VIRTUAL (object, GDL_DOCK_OBJECT_GET_CLASS, present, (object, child));
683 /**
684  * gdl_dock_object_child_placement:
685  * @object: the dock object we are asking for child placement
686  * @child: the child of the @object we want the placement for
687  * @placement: where to return the placement information
688  *
689  * This function returns information about placement of a child dock
690  * object inside another dock object.  The function returns %TRUE if
691  * @child is effectively a child of @object.  @placement should
692  * normally be initially setup to %GDL_DOCK_NONE.  If it's set to some
693  * other value, this function will not touch the stored value if the
694  * specified placement is "compatible" with the actual placement of
695  * the child.
696  *
697  * @placement can be %NULL, in which case the function simply tells if
698  * @child is attached to @object.
699  *
700  * Returns: %TRUE if @child is a child of @object.
701  */
702 gboolean 
703 gdl_dock_object_child_placement (GdlDockObject    *object,
704                                  GdlDockObject    *child,
705                                  GdlDockPlacement *placement)
707     g_return_val_if_fail (object != NULL && child != NULL, FALSE);
709     /* simple case */
710     if (!gdl_dock_object_is_compound (object))
711         return FALSE;
712     
713     return GDL_CALL_VIRTUAL_WITH_DEFAULT (object, GDL_DOCK_OBJECT_GET_CLASS,
714                                           child_placement,
715                                           (object, child, placement),
716                                           FALSE);
720 /* ----- dock param type functions start here ------ */
722 static void 
723 gdl_dock_param_export_int (const GValue *src,
724                            GValue       *dst)
726     dst->data [0].v_pointer = g_strdup_printf ("%d", src->data [0].v_int);
729 static void 
730 gdl_dock_param_export_uint (const GValue *src,
731                             GValue       *dst)
733     dst->data [0].v_pointer = g_strdup_printf ("%u", src->data [0].v_uint);
736 static void 
737 gdl_dock_param_export_string (const GValue *src,
738                               GValue       *dst)
740     dst->data [0].v_pointer = g_strdup (src->data [0].v_pointer);
743 static void 
744 gdl_dock_param_export_bool (const GValue *src,
745                             GValue       *dst)
747     dst->data [0].v_pointer = g_strdup_printf ("%s", src->data [0].v_int ? "yes" : "no");
750 static void 
751 gdl_dock_param_export_placement (const GValue *src,
752                                  GValue       *dst)
754     switch (src->data [0].v_int) {
755         case GDL_DOCK_NONE:
756             dst->data [0].v_pointer = g_strdup ("");
757             break;
758         case GDL_DOCK_TOP:
759             dst->data [0].v_pointer = g_strdup ("top");
760             break;
761         case GDL_DOCK_BOTTOM:
762             dst->data [0].v_pointer = g_strdup ("bottom");
763             break;
764         case GDL_DOCK_LEFT:
765             dst->data [0].v_pointer = g_strdup ("left");
766             break;
767         case GDL_DOCK_RIGHT:
768             dst->data [0].v_pointer = g_strdup ("right");
769             break;
770         case GDL_DOCK_CENTER:
771             dst->data [0].v_pointer = g_strdup ("center");
772             break;
773         case GDL_DOCK_FLOATING:
774             dst->data [0].v_pointer = g_strdup ("floating");
775             break;
776     }
779 static void 
780 gdl_dock_param_import_int (const GValue *src,
781                            GValue       *dst)
783     dst->data [0].v_int = atoi (src->data [0].v_pointer);
786 static void 
787 gdl_dock_param_import_uint (const GValue *src,
788                             GValue       *dst)
790     dst->data [0].v_uint = (guint) atoi (src->data [0].v_pointer);
793 static void 
794 gdl_dock_param_import_string (const GValue *src,
795                               GValue       *dst)
797     dst->data [0].v_pointer = g_strdup (src->data [0].v_pointer);
800 static void 
801 gdl_dock_param_import_bool (const GValue *src,
802                             GValue       *dst)
804     dst->data [0].v_int = !strcmp (src->data [0].v_pointer, "yes");
807 static void 
808 gdl_dock_param_import_placement (const GValue *src,
809                                  GValue       *dst)
811     if (!strcmp (src->data [0].v_pointer, "top"))
812         dst->data [0].v_int = GDL_DOCK_TOP;
813     else if (!strcmp (src->data [0].v_pointer, "bottom"))
814         dst->data [0].v_int = GDL_DOCK_BOTTOM;
815     else if (!strcmp (src->data [0].v_pointer, "center"))
816         dst->data [0].v_int = GDL_DOCK_CENTER;
817     else if (!strcmp (src->data [0].v_pointer, "left"))
818         dst->data [0].v_int = GDL_DOCK_LEFT;
819     else if (!strcmp (src->data [0].v_pointer, "right"))
820         dst->data [0].v_int = GDL_DOCK_RIGHT;
821     else if (!strcmp (src->data [0].v_pointer, "floating"))
822         dst->data [0].v_int = GDL_DOCK_FLOATING;
823     else
824         dst->data [0].v_int = GDL_DOCK_NONE;
827 GType
828 gdl_dock_param_get_type (void)
830     static GType our_type = 0;
832     if (our_type == 0) {
833         GTypeInfo tinfo = { 0, };
834         our_type = g_type_register_static (G_TYPE_STRING, "GdlDockParam", &tinfo, 0);
836         /* register known transform functions */
837         /* exporters */
838         g_value_register_transform_func (G_TYPE_INT, our_type, gdl_dock_param_export_int);
839         g_value_register_transform_func (G_TYPE_UINT, our_type, gdl_dock_param_export_uint);
840         g_value_register_transform_func (G_TYPE_STRING, our_type, gdl_dock_param_export_string);
841         g_value_register_transform_func (G_TYPE_BOOLEAN, our_type, gdl_dock_param_export_bool);
842         g_value_register_transform_func (GDL_TYPE_DOCK_PLACEMENT, our_type, gdl_dock_param_export_placement);
843         /* importers */
844         g_value_register_transform_func (our_type, G_TYPE_INT, gdl_dock_param_import_int);
845         g_value_register_transform_func (our_type, G_TYPE_UINT, gdl_dock_param_import_uint);
846         g_value_register_transform_func (our_type, G_TYPE_STRING, gdl_dock_param_import_string);
847         g_value_register_transform_func (our_type, G_TYPE_BOOLEAN, gdl_dock_param_import_bool);
848         g_value_register_transform_func (our_type, GDL_TYPE_DOCK_PLACEMENT, gdl_dock_param_import_placement);
849     }
851     return our_type;
854 /* -------------- nick <-> type conversion functions --------------- */
856 static GRelation *dock_register = NULL;
858 enum {
859     INDEX_NICK = 0,
860     INDEX_TYPE
861 };
863 static void
864 gdl_dock_object_register_init (void)
866     if (dock_register)
867         return;
868     
869     /* FIXME: i don't know if GRelation is efficient */
870     dock_register = g_relation_new (2);
871     g_relation_index (dock_register, INDEX_NICK, g_str_hash, g_str_equal);
872     g_relation_index (dock_register, INDEX_TYPE, g_direct_hash, g_direct_equal);
874     /* add known types */
875     g_relation_insert (dock_register, "dock", (gpointer) GDL_TYPE_DOCK);
876     g_relation_insert (dock_register, "item", (gpointer) GDL_TYPE_DOCK_ITEM);
877     g_relation_insert (dock_register, "paned", (gpointer) GDL_TYPE_DOCK_PANED);
878     g_relation_insert (dock_register, "notebook", (gpointer) GDL_TYPE_DOCK_NOTEBOOK);
879     g_relation_insert (dock_register, "placeholder", (gpointer) GDL_TYPE_DOCK_PLACEHOLDER);
882 G_CONST_RETURN gchar *
883 gdl_dock_object_nick_from_type (GType type)
885     GTuples *tuples;
886     gchar *nick = NULL;
887     
888     if (!dock_register)
889         gdl_dock_object_register_init ();
891     if (g_relation_count (dock_register, (gpointer) type, INDEX_TYPE) > 0) {
892         tuples = g_relation_select (dock_register, (gpointer) type, INDEX_TYPE);
893         nick = (gchar *) g_tuples_index (tuples, 0, INDEX_NICK);
894         g_tuples_destroy (tuples);
895     }
896     
897     return nick ? nick : g_type_name (type);
900 GType
901 gdl_dock_object_type_from_nick (const gchar *nick)
903     GTuples *tuples;
904     GType type = G_TYPE_NONE;
905     
906     if (!dock_register)
907         gdl_dock_object_register_init ();
909     if (g_relation_count (dock_register, (gpointer) nick, INDEX_NICK) > 0) {
910         tuples = g_relation_select (dock_register, (gpointer) nick, INDEX_NICK);
911         type = (GType) g_tuples_index (tuples, 0, INDEX_TYPE);
912         g_tuples_destroy (tuples);
913     }
914     else {
915         /* try searching in the glib type system */
916         type = g_type_from_name (nick);
917     }
918     
919     return type;
922 GType
923 gdl_dock_object_set_type_for_nick (const gchar *nick,
924                                    GType        type)
926     GType old_type = G_TYPE_NONE;
927     
928     if (!dock_register)
929         gdl_dock_object_register_init ();
931     g_return_val_if_fail (g_type_is_a (type, GDL_TYPE_DOCK_OBJECT), G_TYPE_NONE);
932     
933     if (g_relation_count (dock_register, (gpointer) nick, INDEX_NICK) > 0) {
934         old_type = gdl_dock_object_type_from_nick (nick);
935         g_relation_delete (dock_register, (gpointer) nick, INDEX_NICK);
936     }
937     
938     g_relation_insert (dock_register, nick, type);
940     return old_type;