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)
103 {
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));
153 object_class->destroy = gdl_dock_object_destroy;
155 widget_class->show = gdl_dock_object_show;
156 widget_class->hide = gdl_dock_object_hide;
158 klass->is_compound = TRUE;
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;
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);
193 }
195 static void
196 gdl_dock_object_instance_init (GdlDockObject *object)
197 {
198 object->flags = GDL_DOCK_AUTOMATIC;
199 object->freeze_count = 0;
200 }
202 static void
203 gdl_dock_object_set_property (GObject *g_object,
204 guint prop_id,
205 const GValue *value,
206 GParamSpec *pspec)
207 {
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 }
236 }
238 static void
239 gdl_dock_object_get_property (GObject *g_object,
240 guint prop_id,
241 GValue *value,
242 GParamSpec *pspec)
243 {
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 }
266 }
268 static void
269 gdl_dock_object_finalize (GObject *g_object)
270 {
271 GdlDockObject *object;
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));
286 }
288 static void
289 gdl_dock_object_foreach_detach (GdlDockObject *object,
290 gpointer user_data)
291 {
292 gdl_dock_object_detach (object, TRUE);
293 }
295 static void
296 gdl_dock_object_destroy (GtkObject *gtk_object)
297 {
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 }
318 /* finally unbind us */
319 if (object->master)
320 gdl_dock_object_unbind (object);
322 GDL_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (gtk_object));
323 }
325 static void
326 gdl_dock_object_foreach_automatic (GdlDockObject *object,
327 gpointer user_data)
328 {
329 void (* function) (GtkWidget *) = user_data;
331 if (GDL_DOCK_OBJECT_AUTOMATIC (object))
332 (* function) (GTK_WIDGET (object));
333 }
335 static void
336 gdl_dock_object_show (GtkWidget *widget)
337 {
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));
344 }
346 static void
347 gdl_dock_object_hide (GtkWidget *widget)
348 {
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));
355 }
357 static void
358 gdl_dock_object_real_detach (GdlDockObject *object,
359 gboolean recursive)
360 {
361 GdlDockObject *parent;
362 GtkWidget *widget;
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 }
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);
381 }
383 static void
384 gdl_dock_object_real_reduce (GdlDockObject *object)
385 {
386 GdlDockObject *parent;
387 GList *children;
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;
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);
426 }
428 static void
429 gdl_dock_object_dock_unimplemented (GdlDockObject *object,
430 GdlDockObject *requestor,
431 GdlDockPlacement position,
432 GValue *other_data)
433 {
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));
437 }
439 static void
440 gdl_dock_object_real_present (GdlDockObject *object,
441 GdlDockObject *child)
442 {
443 gtk_widget_show (GTK_WIDGET (object));
444 }
447 /* ----- Public interface ----- */
449 gboolean
450 gdl_dock_object_is_compound (GdlDockObject *object)
451 {
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;
459 }
461 void
462 gdl_dock_object_detach (GdlDockObject *object,
463 gboolean recursive)
464 {
465 g_return_if_fail (object != NULL);
467 if (!GDL_DOCK_OBJECT_ATTACHED (object))
468 return;
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);
476 }
478 GdlDockObject *
479 gdl_dock_object_get_parent_object (GdlDockObject *object)
480 {
481 GtkWidget *parent;
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 }
490 return parent ? GDL_DOCK_OBJECT (parent) : NULL;
491 }
493 void
494 gdl_dock_object_freeze (GdlDockObject *object)
495 {
496 g_return_if_fail (object != NULL);
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++;
503 }
505 void
506 gdl_dock_object_thaw (GdlDockObject *object)
507 {
508 g_return_if_fail (object != NULL);
509 g_return_if_fail (object->freeze_count > 0);
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 }
519 }
521 void
522 gdl_dock_object_reduce (GdlDockObject *object)
523 {
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));
532 }
534 gboolean
535 gdl_dock_object_dock_request (GdlDockObject *object,
536 gint x,
537 gint y,
538 GdlDockRequest *request)
539 {
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);
547 }
549 void
550 gdl_dock_object_dock (GdlDockObject *object,
551 GdlDockObject *requestor,
552 GdlDockPlacement position,
553 GValue *other_data)
554 {
555 GdlDockObject *parent;
557 g_return_if_fail (object != NULL && requestor != NULL);
559 if (object == requestor)
560 return;
562 if (!object->master)
563 g_warning (_("Dock operation requested in a non-bound object %p. "
564 "The application might crash"), object);
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 }
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);
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);
598 }
600 void
601 gdl_dock_object_bind (GdlDockObject *object,
602 GObject *master)
603 {
604 g_return_if_fail (object != NULL && master != NULL);
605 g_return_if_fail (GDL_IS_DOCK_MASTER (master));
607 if (object->master == master)
608 /* nothing to do here */
609 return;
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");
622 }
624 void
625 gdl_dock_object_unbind (GdlDockObject *object)
626 {
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);
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);
643 }
645 gboolean
646 gdl_dock_object_is_bound (GdlDockObject *object)
647 {
648 g_return_val_if_fail (object != NULL, FALSE);
649 return (object->master != NULL);
650 }
652 gboolean
653 gdl_dock_object_reorder (GdlDockObject *object,
654 GdlDockObject *child,
655 GdlDockPlacement new_position,
656 GValue *other_data)
657 {
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);
665 }
667 void
668 gdl_dock_object_present (GdlDockObject *object,
669 GdlDockObject *child)
670 {
671 GdlDockObject *parent;
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));
681 }
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)
706 {
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;
713 return GDL_CALL_VIRTUAL_WITH_DEFAULT (object, GDL_DOCK_OBJECT_GET_CLASS,
714 child_placement,
715 (object, child, placement),
716 FALSE);
717 }
720 /* ----- dock param type functions start here ------ */
722 static void
723 gdl_dock_param_export_int (const GValue *src,
724 GValue *dst)
725 {
726 dst->data [0].v_pointer = g_strdup_printf ("%d", src->data [0].v_int);
727 }
729 static void
730 gdl_dock_param_export_uint (const GValue *src,
731 GValue *dst)
732 {
733 dst->data [0].v_pointer = g_strdup_printf ("%u", src->data [0].v_uint);
734 }
736 static void
737 gdl_dock_param_export_string (const GValue *src,
738 GValue *dst)
739 {
740 dst->data [0].v_pointer = g_strdup (src->data [0].v_pointer);
741 }
743 static void
744 gdl_dock_param_export_bool (const GValue *src,
745 GValue *dst)
746 {
747 dst->data [0].v_pointer = g_strdup_printf ("%s", src->data [0].v_int ? "yes" : "no");
748 }
750 static void
751 gdl_dock_param_export_placement (const GValue *src,
752 GValue *dst)
753 {
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 }
777 }
779 static void
780 gdl_dock_param_import_int (const GValue *src,
781 GValue *dst)
782 {
783 dst->data [0].v_int = atoi (src->data [0].v_pointer);
784 }
786 static void
787 gdl_dock_param_import_uint (const GValue *src,
788 GValue *dst)
789 {
790 dst->data [0].v_uint = (guint) atoi (src->data [0].v_pointer);
791 }
793 static void
794 gdl_dock_param_import_string (const GValue *src,
795 GValue *dst)
796 {
797 dst->data [0].v_pointer = g_strdup (src->data [0].v_pointer);
798 }
800 static void
801 gdl_dock_param_import_bool (const GValue *src,
802 GValue *dst)
803 {
804 dst->data [0].v_int = !strcmp (src->data [0].v_pointer, "yes");
805 }
807 static void
808 gdl_dock_param_import_placement (const GValue *src,
809 GValue *dst)
810 {
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;
825 }
827 GType
828 gdl_dock_param_get_type (void)
829 {
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;
852 }
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)
865 {
866 if (dock_register)
867 return;
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);
880 }
882 G_CONST_RETURN gchar *
883 gdl_dock_object_nick_from_type (GType type)
884 {
885 GTuples *tuples;
886 gchar *nick = NULL;
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 }
897 return nick ? nick : g_type_name (type);
898 }
900 GType
901 gdl_dock_object_type_from_nick (const gchar *nick)
902 {
903 GTuples *tuples;
904 GType type = G_TYPE_NONE;
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 }
919 return type;
920 }
922 GType
923 gdl_dock_object_set_type_for_nick (const gchar *nick,
924 GType type)
925 {
926 GType old_type = G_TYPE_NONE;
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);
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 }
938 g_relation_insert (dock_register, nick, type);
940 return old_type;
941 }