Code

Prevent localized doubles from being written into filter matrices
[inkscape.git] / src / libgdl / gdl-dock-item.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 
2  *
3  * gdl-dock-item.c
4  *
5  * Author: Gustavo Giráldez <gustavo.giraldez@gmx.net>
6  *         Naba Kumar  <naba@gnome.org>
7  *
8  * Based on GnomeDockItem/BonoboDockItem.  Original copyright notice follows.
9  *
10  * Copyright (C) 1998 Ettore Perazzoli
11  * Copyright (C) 1998 Elliot Lee
12  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald 
13  * All rights reserved.
14  *
15  * This library is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU Library General Public
17  * License as published by the Free Software Foundation; either
18  * version 2 of the License, or (at your option) any later version.
19  *
20  * This library is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23  * Library General Public License for more details.
24  *
25  * You should have received a copy of the GNU Library General Public
26  * License along with this library; if not, write to the
27  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
28  * Boston, MA 02111-1307, USA.
29  */
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
36 #include "gdl-i18n.h"
37 #include <string.h>
38 #include <gdk/gdkkeysyms.h>
40 #include "gdl-tools.h"
41 #include "gdl-dock.h"
42 #include "gdl-dock-item.h"
43 #include "gdl-dock-item-grip.h"
44 #include "gdl-dock-notebook.h"
45 #include "gdl-dock-paned.h"
46 #include "gdl-dock-tablabel.h"
47 #include "gdl-dock-placeholder.h"
48 #include "gdl-dock-master.h"
49 #include "libgdltypebuiltins.h"
50 #include "libgdlmarshal.h"
52 #define NEW_DOCK_ITEM_RATIO 0.3
54 /* ----- Private prototypes ----- */
56 static void  gdl_dock_item_class_init    (GdlDockItemClass *class);
57 static void  gdl_dock_item_instance_init (GdlDockItem *item);
59 static GObject *gdl_dock_item_constructor (GType                  type,
60                                            guint                  n_construct_properties,
61                                            GObjectConstructParam *construct_param);
63 static void  gdl_dock_item_set_property  (GObject      *object,
64                                           guint         prop_id,
65                                           const GValue *value,
66                                           GParamSpec   *pspec);
67 static void  gdl_dock_item_get_property  (GObject      *object,
68                                           guint         prop_id,
69                                           GValue       *value,
70                                           GParamSpec   *pspec);
72 static void  gdl_dock_item_destroy       (GtkObject *object);
74 static void  gdl_dock_item_add           (GtkContainer *container,
75                                           GtkWidget    *widget);
76 static void  gdl_dock_item_remove        (GtkContainer *container,
77                                           GtkWidget    *widget);
78 static void  gdl_dock_item_forall        (GtkContainer *container,
79                                           gboolean      include_internals,
80                                           GtkCallback   callback,
81                                           gpointer      callback_data);
82 static GtkType gdl_dock_item_child_type  (GtkContainer *container);
84 static void  gdl_dock_item_set_focus_child (GtkContainer *container,
85                                             GtkWidget    *widget,
86                                             gpointer      callback_data);
88 static void  gdl_dock_item_size_request  (GtkWidget *widget,
89                                           GtkRequisition *requisition);
90 static void  gdl_dock_item_size_allocate (GtkWidget *widget,
91                                           GtkAllocation *allocation);
92 static void  gdl_dock_item_map           (GtkWidget *widget);
93 static void  gdl_dock_item_unmap         (GtkWidget *widget);
94 static void  gdl_dock_item_realize       (GtkWidget *widget);
95 static void  gdl_dock_item_style_set     (GtkWidget *widget,
96                                           GtkStyle  *previous_style);
97 static gint  gdl_dock_item_expose        (GtkWidget *widget,
98                                           GdkEventExpose *event);
100 static void  gdl_dock_item_move_focus_child (GdlDockItem      *item,
101                                              GtkDirectionType  dir);
103 static gint  gdl_dock_item_button_changed (GtkWidget *widget,
104                                            GdkEventButton *event);
105 static gint  gdl_dock_item_motion         (GtkWidget *widget,
106                                            GdkEventMotion *event);
107 static gboolean  gdl_dock_item_key_press  (GtkWidget *widget,
108                                            GdkEventKey *event);
110 static gboolean gdl_dock_item_dock_request (GdlDockObject    *object,
111                                             gint              x,
112                                             gint              y,
113                                             GdlDockRequest   *request);
114 static void     gdl_dock_item_dock         (GdlDockObject    *object,
115                                             GdlDockObject    *requestor,
116                                             GdlDockPlacement  position,
117                                             GValue           *other_data);
119 static void  gdl_dock_item_popup_menu    (GdlDockItem *item, 
120                                           guint        button,
121                                           guint32      time);
122 static void  gdl_dock_item_drag_start    (GdlDockItem *item);
123 static void  gdl_dock_item_drag_end      (GdlDockItem *item,
124                                           gboolean     cancel);
126 static void  gdl_dock_item_tab_button    (GtkWidget      *widget,
127                                           GdkEventButton *event,
128                                           gpointer        data);
129                                           
130 static void  gdl_dock_item_hide_cb       (GtkWidget   *widget,
131                                           GdlDockItem *item);
133 static void  gdl_dock_item_lock_cb       (GtkWidget   *widget,
134                                           GdlDockItem *item);
136 static void  gdl_dock_item_unlock_cb     (GtkWidget   *widget,
137                                           GdlDockItem *item);
139 static void  gdl_dock_item_showhide_grip (GdlDockItem *item);
141 static void  gdl_dock_item_real_set_orientation (GdlDockItem    *item,
142                                                  GtkOrientation  orientation);
144 static void gdl_dock_param_export_gtk_orientation (const GValue *src,
145                                                    GValue       *dst);
146 static void gdl_dock_param_import_gtk_orientation (const GValue *src,
147                                                    GValue       *dst);
151 /* ----- Class variables and definitions ----- */
153 enum {
154     PROP_0,
155     PROP_ORIENTATION,
156     PROP_RESIZE,
157     PROP_BEHAVIOR,
158     PROP_LOCKED,
159     PROP_PREFERRED_WIDTH,
160     PROP_PREFERRED_HEIGHT
161 };
163 enum {
164     DOCK_DRAG_BEGIN,
165     DOCK_DRAG_MOTION,
166     DOCK_DRAG_END,
167     MOVE_FOCUS_CHILD,
168     LAST_SIGNAL
169 };
171 static guint gdl_dock_item_signals [LAST_SIGNAL] = { 0 };
173 #define GDL_DOCK_ITEM_GRIP_SHOWN(item) \
174     (GDL_DOCK_ITEM_HAS_GRIP (item)) 
176 struct _GdlDockItemPrivate {
177     GtkWidget *menu;
179     gboolean   grip_shown;
180     GtkWidget *grip;
181     guint      grip_size;
182     
183     GtkWidget *tab_label;
185     gint       preferred_width;
186     gint       preferred_height;
188     GdlDockPlaceholder *ph;
190     gint       start_x, start_y;
191 };
193 /* FIXME: implement the rest of the behaviors */
195 #define SPLIT_RATIO  0.4
198 /* ----- Private functions ----- */
200 GDL_CLASS_BOILERPLATE (GdlDockItem, gdl_dock_item, GdlDockObject, GDL_TYPE_DOCK_OBJECT);
202 static void
203 add_tab_bindings (GtkBindingSet    *binding_set,
204                   GdkModifierType   modifiers,
205                   GtkDirectionType  direction)
207     gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
208                                   "move_focus_child", 1,
209                                   GTK_TYPE_DIRECTION_TYPE, direction);
210     gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
211                                   "move_focus_child", 1,
212                                   GTK_TYPE_DIRECTION_TYPE, direction);
215 static void
216 add_arrow_bindings (GtkBindingSet    *binding_set,
217                     guint             keysym,
218                     GtkDirectionType  direction)
220     guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
222     gtk_binding_entry_add_signal (binding_set, keysym, 0,
223                                   "move_focus_child", 1,
224                                   GTK_TYPE_DIRECTION_TYPE, direction);
225     gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
226                                   "move_focus_child", 1,
227                                   GTK_TYPE_DIRECTION_TYPE, direction);
228     gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
229                                   "move_focus_child", 1,
230                                   GTK_TYPE_DIRECTION_TYPE, direction);
231     gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
232                                   "move_focus_child", 1,
233                                   GTK_TYPE_DIRECTION_TYPE, direction);
236 static void
237 gdl_dock_item_class_init (GdlDockItemClass *klass)
239     static gboolean style_initialized = FALSE;
240     
241     GObjectClass       *g_object_class;
242     GtkObjectClass     *gtk_object_class;
243     GtkWidgetClass     *widget_class;
244     GtkContainerClass  *container_class;
245     GdlDockObjectClass *object_class;
246     GtkBindingSet      *binding_set;
247     
248     g_object_class = G_OBJECT_CLASS (klass);
249     gtk_object_class = GTK_OBJECT_CLASS (klass);
250     widget_class = GTK_WIDGET_CLASS (klass);
251     container_class = GTK_CONTAINER_CLASS (klass);
252     object_class = GDL_DOCK_OBJECT_CLASS (klass);
254     g_object_class->constructor = gdl_dock_item_constructor;
255     g_object_class->set_property = gdl_dock_item_set_property;
256     g_object_class->get_property = gdl_dock_item_get_property;
258     gtk_object_class->destroy = gdl_dock_item_destroy;
260     widget_class->realize = gdl_dock_item_realize;
261     widget_class->map = gdl_dock_item_map;
262     widget_class->unmap = gdl_dock_item_unmap;
263     widget_class->size_request = gdl_dock_item_size_request;
264     widget_class->size_allocate = gdl_dock_item_size_allocate;
265     widget_class->style_set = gdl_dock_item_style_set;
266     widget_class->expose_event = gdl_dock_item_expose;
267     widget_class->button_press_event = gdl_dock_item_button_changed;
268     widget_class->button_release_event = gdl_dock_item_button_changed;
269     widget_class->motion_notify_event = gdl_dock_item_motion;
270     widget_class->key_press_event = gdl_dock_item_key_press;
271     
272     container_class->add = gdl_dock_item_add;
273     container_class->remove = gdl_dock_item_remove;
274     container_class->forall = gdl_dock_item_forall;
275     container_class->child_type = gdl_dock_item_child_type;
276     container_class->set_focus_child = gdl_dock_item_set_focus_child;
277     
278     object_class->is_compound = FALSE;
280     object_class->dock_request = gdl_dock_item_dock_request;
281     object_class->dock = gdl_dock_item_dock;
283     /* properties */
285     g_object_class_install_property (
286         g_object_class, PROP_ORIENTATION,
287         g_param_spec_enum ("orientation", _("Orientation"),
288                            _("Orientation of the docking item"),
289                            GTK_TYPE_ORIENTATION,
290                            GTK_ORIENTATION_VERTICAL,
291                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
292                            GDL_DOCK_PARAM_EXPORT));
294     /* --- register exporter/importer for GTK_ORIENTATION */
295     g_value_register_transform_func (GTK_TYPE_ORIENTATION, GDL_TYPE_DOCK_PARAM,
296                                      gdl_dock_param_export_gtk_orientation);
297     g_value_register_transform_func (GDL_TYPE_DOCK_PARAM, GTK_TYPE_ORIENTATION,
298                                      gdl_dock_param_import_gtk_orientation);
299     /* --- end of registration */
300     
301     g_object_class_install_property (
302         g_object_class, PROP_RESIZE,
303         g_param_spec_boolean ("resize", _("Resizable"),
304                               _("If set, the dock item can be resized when "
305                                 "docked in a panel"),
306                               TRUE,
307                               G_PARAM_READWRITE));
308                                      
309     g_object_class_install_property (
310         g_object_class, PROP_BEHAVIOR,
311         g_param_spec_flags ("behavior", _("Item behavior"),
312                             _("General behavior for the dock item (i.e. "
313                               "whether it can float, if it's locked, etc.)"),
314                             GDL_TYPE_DOCK_ITEM_BEHAVIOR,
315                             GDL_DOCK_ITEM_BEH_NORMAL,
316                             G_PARAM_READWRITE));
317                                      
318     g_object_class_install_property (
319         g_object_class, PROP_LOCKED,
320         g_param_spec_boolean ("locked", _("Locked"),
321                               _("If set, the dock item cannot be dragged around "
322                                 "and it doesn't show a grip"),
323                               FALSE,
324                               G_PARAM_READWRITE |
325                               GDL_DOCK_PARAM_EXPORT));
327     g_object_class_install_property (
328         g_object_class, PROP_PREFERRED_WIDTH,
329         g_param_spec_int ("preferred-width", _("Preferred width"),
330                           _("Preferred width for the dock item"),
331                           -1, G_MAXINT, -1,
332                           G_PARAM_READWRITE));
334     g_object_class_install_property (
335         g_object_class, PROP_PREFERRED_HEIGHT,
336         g_param_spec_int ("preferred-height", _("Preferred height"),
337                           _("Preferred height for the dock item"),
338                           -1, G_MAXINT, -1,
339                           G_PARAM_READWRITE));
341     /* signals */
342     
343     gdl_dock_item_signals [DOCK_DRAG_BEGIN] = 
344         g_signal_new ("dock-drag-begin",
345                       G_TYPE_FROM_CLASS (klass),
346                       G_SIGNAL_RUN_FIRST,
347                       G_STRUCT_OFFSET (GdlDockItemClass, dock_drag_begin),
348                       NULL, /* accumulator */
349                       NULL, /* accu_data */
350                       gdl_marshal_VOID__VOID,
351                       G_TYPE_NONE, 
352                       0);
354     gdl_dock_item_signals [DOCK_DRAG_MOTION] = 
355         g_signal_new ("dock-drag-motion",
356                       G_TYPE_FROM_CLASS (klass),
357                       G_SIGNAL_RUN_FIRST,
358                       G_STRUCT_OFFSET (GdlDockItemClass, dock_drag_motion),
359                       NULL, /* accumulator */
360                       NULL, /* accu_data */
361                       gdl_marshal_VOID__INT_INT,
362                       G_TYPE_NONE, 
363                       2,
364                       G_TYPE_INT,
365                       G_TYPE_INT);
367     gdl_dock_item_signals [DOCK_DRAG_END] = 
368         g_signal_new ("dock_drag_end",
369                       G_TYPE_FROM_CLASS (klass),
370                       G_SIGNAL_RUN_FIRST,
371                       G_STRUCT_OFFSET (GdlDockItemClass, dock_drag_end),
372                       NULL, /* accumulator */
373                       NULL, /* accu_data */
374                       gdl_marshal_VOID__BOOLEAN,
375                       G_TYPE_NONE, 
376                       1,
377                       G_TYPE_BOOLEAN);
379     gdl_dock_item_signals [MOVE_FOCUS_CHILD] =
380         g_signal_new ("move_focus_child",
381                       G_TYPE_FROM_CLASS (klass),
382                       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
383                       G_STRUCT_OFFSET (GdlDockItemClass, move_focus_child),
384                       NULL, /* accumulator */
385                       NULL, /* accu_data */
386                       gdl_marshal_VOID__ENUM,
387                       G_TYPE_NONE,
388                       1,
389                       GTK_TYPE_DIRECTION_TYPE);
392     /* key bindings */
394     binding_set = gtk_binding_set_by_class (klass);
396     add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
397     add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
398     add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
399     add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
401     add_tab_bindings (binding_set, 0, GTK_DIR_TAB_FORWARD);
402     add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
403     add_tab_bindings (binding_set, GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
404     add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
406     klass->has_grip = TRUE;
407     klass->dock_drag_begin = NULL;
408     klass->dock_drag_motion = NULL;
409     klass->dock_drag_end = NULL;
410     klass->move_focus_child = gdl_dock_item_move_focus_child;
411     klass->set_orientation = gdl_dock_item_real_set_orientation;
413     if (!style_initialized)
414     {
415         style_initialized = TRUE;
416         gtk_rc_parse_string (
417             "style \"gdl-dock-item-default\" {\n"
418             "xthickness = 0\n"
419             "ythickness = 0\n"
420             "}\n"
421             "class \"GdlDockItem\" "
422             "style : gtk \"gdl-dock-item-default\"\n");
423     }
426 static void
427 gdl_dock_item_instance_init (GdlDockItem *item)
429     GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (item), GTK_NO_WINDOW);
430     GTK_WIDGET_SET_FLAGS (GTK_WIDGET (item), GTK_CAN_FOCUS);
432     item->child = NULL;
433     
434     item->orientation = GTK_ORIENTATION_VERTICAL;
435     item->behavior = GDL_DOCK_ITEM_BEH_NORMAL;
437     item->resize = TRUE;
439     item->dragoff_x = item->dragoff_y = 0;
441     item->_priv = g_new0 (GdlDockItemPrivate, 1);
442     item->_priv->menu = NULL;
444     item->_priv->preferred_width = item->_priv->preferred_height = -1;
445     item->_priv->tab_label = NULL;
447     item->_priv->ph = NULL;
450 static GObject *
451 gdl_dock_item_constructor (GType                  type,
452                            guint                  n_construct_properties,
453                            GObjectConstructParam *construct_param)
455     GObject *g_object;
456     
457     g_object = GDL_CALL_PARENT_WITH_DEFAULT (G_OBJECT_CLASS, 
458                                                constructor, 
459                                                (type,
460                                                 n_construct_properties,
461                                                 construct_param),
462                                                NULL);
463     if (g_object) {
464         GdlDockItem *item = GDL_DOCK_ITEM (g_object);
466         if (GDL_DOCK_ITEM_HAS_GRIP (item)) {
467             item->_priv->grip_shown = TRUE;
468             item->_priv->grip = gdl_dock_item_grip_new (item);
469             gtk_widget_set_parent (item->_priv->grip, GTK_WIDGET (item));
470             gtk_widget_show (item->_priv->grip);
471         }
472         else {
473             item->_priv->grip_shown = FALSE;
474         }
475     }
477     return g_object;
480 static void
481 gdl_dock_item_set_property  (GObject      *g_object,
482                              guint         prop_id,
483                              const GValue *value,
484                              GParamSpec   *pspec)
486     GdlDockItem *item = GDL_DOCK_ITEM (g_object);
488     switch (prop_id) {
489         case PROP_ORIENTATION:
490             gdl_dock_item_set_orientation (item, g_value_get_enum (value));
491             break;
492         case PROP_RESIZE:
493             item->resize = g_value_get_boolean (value);
494             gtk_widget_queue_resize (GTK_WIDGET (item));
495             break;
496         case PROP_BEHAVIOR:
497         {
498             GdlDockItemBehavior old_beh = item->behavior;
499             item->behavior = g_value_get_flags (value);
501             if ((old_beh ^ item->behavior) & GDL_DOCK_ITEM_BEH_LOCKED) {
502                 if (GDL_DOCK_OBJECT_GET_MASTER (item))
503                     g_signal_emit_by_name (GDL_DOCK_OBJECT_GET_MASTER (item),
504                                            "layout-changed");
505                 g_object_notify (g_object, "locked");
506                 gdl_dock_item_showhide_grip (item);
507             }
508             
509             break;
510         }
511         case PROP_LOCKED:
512         {
513             GdlDockItemBehavior old_beh = item->behavior;
515             if (g_value_get_boolean (value))
516                 item->behavior |= GDL_DOCK_ITEM_BEH_LOCKED;
517             else
518                 item->behavior &= ~GDL_DOCK_ITEM_BEH_LOCKED;
520             if (old_beh ^ item->behavior) {
521                 gdl_dock_item_showhide_grip (item);
522                 g_object_notify (g_object, "behavior");
524                 if (GDL_DOCK_OBJECT_GET_MASTER (item))
525                     g_signal_emit_by_name (GDL_DOCK_OBJECT_GET_MASTER (item),
526                                            "layout-changed");
527             }
528             break;
529         }
530         case PROP_PREFERRED_WIDTH:
531             item->_priv->preferred_width = g_value_get_int (value);
532             break;
533         case PROP_PREFERRED_HEIGHT:
534             item->_priv->preferred_height = g_value_get_int (value);
535             break;
536         default:
537             G_OBJECT_WARN_INVALID_PROPERTY_ID (g_object, prop_id, pspec);
538             break;
539     }
542 static void
543 gdl_dock_item_get_property  (GObject      *g_object,
544                              guint         prop_id,
545                              GValue       *value,
546                              GParamSpec   *pspec)
548     GdlDockItem *item = GDL_DOCK_ITEM (g_object);
549     
550     switch (prop_id) {
551         case PROP_ORIENTATION:
552             g_value_set_enum (value, item->orientation);
553             break;
554         case PROP_RESIZE:
555             g_value_set_boolean (value, item->resize);
556             break;
557         case PROP_BEHAVIOR:
558             g_value_set_flags (value, item->behavior);
559             break;
560         case PROP_LOCKED:
561             g_value_set_boolean (value, !GDL_DOCK_ITEM_NOT_LOCKED (item));
562             break;
563         case PROP_PREFERRED_WIDTH:
564             g_value_set_int (value, item->_priv->preferred_width);
565             break;
566         case PROP_PREFERRED_HEIGHT:
567             g_value_set_int (value, item->_priv->preferred_height);
568             break;
569         default:
570             G_OBJECT_WARN_INVALID_PROPERTY_ID (g_object, prop_id, pspec);
571             break;
572     }
575 static void
576 gdl_dock_item_destroy (GtkObject *object)
578     GdlDockItem *item = GDL_DOCK_ITEM (object);
580     if (item->_priv) {
581         GdlDockItemPrivate *priv = item->_priv;
582         
583         if (priv->tab_label) {
584             gdl_dock_item_set_tablabel (item, NULL);
585         };
586         if (priv->menu) {
587             gtk_menu_detach (GTK_MENU (priv->menu));
588             priv->menu = NULL;
589         };
590         if (priv->grip) {
591             gtk_container_remove (GTK_CONTAINER (item), priv->grip);
592             priv->grip = NULL;
593         }
594         if (priv->ph) {
595             g_object_unref (priv->ph);
596             priv->ph = NULL;
597         }
598         
599         item->_priv = NULL;
600         g_free (priv);
601     }
603     GDL_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
606 static void 
607 gdl_dock_item_add (GtkContainer *container,
608                    GtkWidget    *widget)
610     GdlDockItem *item;
611     
612     g_return_if_fail (GDL_IS_DOCK_ITEM (container));
614     item = GDL_DOCK_ITEM (container);
615     if (GDL_IS_DOCK_OBJECT (widget)) {
616         g_warning (_("You can't add a dock object (%p of type %s) inside a %s. "
617                      "Use a GdlDock or some other compound dock object."),
618                    widget, G_OBJECT_TYPE_NAME (widget), G_OBJECT_TYPE_NAME (item));
619         return;
620     }
622     if (item->child != NULL) {
623         g_warning (_("Attempting to add a widget with type %s to a %s, "
624                      "but it can only contain one widget at a time; "
625                      "it already contains a widget of type %s"),
626                      G_OBJECT_TYPE_NAME (widget),
627                      G_OBJECT_TYPE_NAME (item),
628                      G_OBJECT_TYPE_NAME (item->child));
629         return;
630     }
632     gtk_widget_set_parent (widget, GTK_WIDGET (item));
633     item->child = widget;
636 static void  
637 gdl_dock_item_remove (GtkContainer *container,
638                       GtkWidget    *widget)
640     GdlDockItem *item;
641     gboolean     was_visible;
642     
643     g_return_if_fail (GDL_IS_DOCK_ITEM (container));
644     
645     item = GDL_DOCK_ITEM (container);
646     if (item->_priv && widget == item->_priv->grip) {
647         gboolean grip_was_visible = GTK_WIDGET_VISIBLE (widget);
648         gtk_widget_unparent (widget);
649         item->_priv->grip = NULL;
650         if (grip_was_visible)
651             gtk_widget_queue_resize (GTK_WIDGET (item));
652         return;
653     }
654     
655     if (GDL_DOCK_ITEM_IN_DRAG (item)) {
656         gdl_dock_item_drag_end (item, TRUE);
657     }
658     
659     g_return_if_fail (item->child == widget);
660     
661     was_visible = GTK_WIDGET_VISIBLE (widget);
663     gtk_widget_unparent (widget);
664     item->child = NULL;
665     
666     if (was_visible)
667         gtk_widget_queue_resize (GTK_WIDGET (container));
670 static void
671 gdl_dock_item_forall (GtkContainer *container,
672                       gboolean      include_internals,
673                       GtkCallback   callback,
674                       gpointer      callback_data)
676     GdlDockItem *item = (GdlDockItem *) container;
677     
678     g_return_if_fail (callback != NULL);
679     
680     if (include_internals && item->_priv->grip)
681         (* callback) (item->_priv->grip, callback_data);
682     
683     if (item->child)
684         (* callback) (item->child, callback_data);
687 static GtkType
688 gdl_dock_item_child_type (GtkContainer *container)
690     g_return_val_if_fail (GDL_IS_DOCK_ITEM (container), G_TYPE_NONE);
691     
692     if (!GDL_DOCK_ITEM (container)->child)
693         return GTK_TYPE_WIDGET;
694     else
695         return G_TYPE_NONE;
698 static void
699 gdl_dock_item_set_focus_child (GtkContainer *container,
700                                GtkWidget    *child,
701                                gpointer      callback_data)
703     g_return_if_fail (GDL_IS_DOCK_ITEM (container));
704     
705     if (GTK_CONTAINER_CLASS (parent_class)->set_focus_child)
706         (* GTK_CONTAINER_CLASS (parent_class)->set_focus_child) (container, child);
708     gdl_dock_item_showhide_grip (GDL_DOCK_ITEM (container));
711 static void
712 gdl_dock_item_size_request (GtkWidget      *widget,
713                             GtkRequisition *requisition)
715     GtkRequisition  child_requisition;
716     GtkRequisition  grip_requisition;
717     GdlDockItem    *item;
719     g_return_if_fail (GDL_IS_DOCK_ITEM (widget));
720     g_return_if_fail (requisition != NULL);
722     item = GDL_DOCK_ITEM (widget);
724     /* If our child is not visible, we still request its size, since
725        we won't have any useful hint for our size otherwise.  */
726     if (item->child)
727         gtk_widget_size_request (item->child, &child_requisition);
728     else {
729         child_requisition.width = 0;
730         child_requisition.height = 0;
731     }
733     if (item->orientation == GTK_ORIENTATION_HORIZONTAL) {
734         if (GDL_DOCK_ITEM_GRIP_SHOWN (item)) {
735             gtk_widget_size_request (item->_priv->grip, &grip_requisition);
736             requisition->width = grip_requisition.width;
737         } else {
738             requisition->width = 0;
739         }
741         if (item->child) {
742             requisition->width += child_requisition.width;
743             requisition->height = child_requisition.height;
744         } else
745             requisition->height = 0;
746     } else {
747         if (GDL_DOCK_ITEM_GRIP_SHOWN (item)) {
748             gtk_widget_size_request (item->_priv->grip, &grip_requisition);
749             requisition->height = grip_requisition.height;
750         } else {
751             requisition->height = 0;
752         }
754         if (item->child) {
755             requisition->width = child_requisition.width;
756             requisition->height += child_requisition.height;
757         } else
758             requisition->width = 0;
759     }
761     requisition->width += (GTK_CONTAINER (widget)->border_width + widget->style->xthickness) * 2;
762     requisition->height += (GTK_CONTAINER (widget)->border_width + widget->style->ythickness) * 2;
764     widget->requisition = *requisition;
767 static void
768 gdl_dock_item_size_allocate (GtkWidget     *widget,
769                              GtkAllocation *allocation)
771     GdlDockItem *item;
772   
773     g_return_if_fail (GDL_IS_DOCK_ITEM (widget));
774     g_return_if_fail (allocation != NULL);
775   
776     item = GDL_DOCK_ITEM (widget);
778     widget->allocation = *allocation;
780     /* Once size is allocated, preferred size is no longer necessary */
781     item->_priv->preferred_height = -1;
782     item->_priv->preferred_width = -1;
783     
784     if (GTK_WIDGET_REALIZED (widget))
785         gdk_window_move_resize (widget->window,
786                                 widget->allocation.x,
787                                 widget->allocation.y,
788                                 widget->allocation.width,
789                                 widget->allocation.height);
791     if (item->child && GTK_WIDGET_VISIBLE (item->child)) {
792         GtkAllocation  child_allocation;
793         int            border_width;
795         border_width = GTK_CONTAINER (widget)->border_width;
797         child_allocation.x = border_width + widget->style->xthickness;
798         child_allocation.y = border_width + widget->style->ythickness;
799         child_allocation.width = allocation->width
800             - 2 * (border_width + widget->style->xthickness);
801         child_allocation.height = allocation->height
802             - 2 * (border_width + widget->style->ythickness);
803         
804         if (GDL_DOCK_ITEM_GRIP_SHOWN (item)) {
805             GtkAllocation grip_alloc = child_allocation;
806             GtkRequisition grip_req;
807             
808             gtk_widget_size_request (item->_priv->grip, &grip_req);
809             
810             if (item->orientation == GTK_ORIENTATION_HORIZONTAL) {
811                 child_allocation.x += grip_req.width;
812                 child_allocation.width -= grip_req.width;
813                 grip_alloc.width = grip_req.width;
814             } else {
815                 child_allocation.y += grip_req.height;
816                 child_allocation.height -= grip_req.height;
817                 grip_alloc.height = grip_req.height;
818             }
819             if (item->_priv->grip)
820                 gtk_widget_size_allocate (item->_priv->grip, &grip_alloc);
821         }
822         /* Allocation can't be negative */
823         if (child_allocation.width < 0)
824             child_allocation.width = 0;
825         if (child_allocation.height < 0)
826             child_allocation.height = 0;
827         gtk_widget_size_allocate (item->child, &child_allocation);
828     }
831 static void
832 gdl_dock_item_map (GtkWidget *widget)
834     GdlDockItem *item;
836     g_return_if_fail (widget != NULL);
837     g_return_if_fail (GDL_IS_DOCK_ITEM (widget));
839     GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
841     item = GDL_DOCK_ITEM (widget);
843     gdk_window_show (widget->window);
845     if (item->child
846         && GTK_WIDGET_VISIBLE (item->child)
847         && !GTK_WIDGET_MAPPED (item->child))
848         gtk_widget_map (item->child);
850     if (item->_priv->grip
851         && GTK_WIDGET_VISIBLE (item->_priv->grip)
852         && !GTK_WIDGET_MAPPED (item->_priv->grip))
853         gtk_widget_map (item->_priv->grip);
856 static void
857 gdl_dock_item_unmap (GtkWidget *widget)
859     GdlDockItem *item;
861     g_return_if_fail (widget != NULL);
862     g_return_if_fail (GDL_IS_DOCK_ITEM (widget));
864     GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
865     
866     item = GDL_DOCK_ITEM (widget);
868     gdk_window_hide (widget->window);
870     if (item->_priv->grip)
871         gtk_widget_unmap (item->_priv->grip);
874 static void
875 gdl_dock_item_realize (GtkWidget *widget)
877     GdkWindowAttr  attributes;
878     gint           attributes_mask;
879     GdlDockItem   *item;
881     g_return_if_fail (widget != NULL);
882     g_return_if_fail (GDL_IS_DOCK_ITEM (widget));
884     item = GDL_DOCK_ITEM (widget);
886     GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
888     /* widget window */
889     attributes.x = widget->allocation.x;
890     attributes.y = widget->allocation.y;
891     attributes.width = widget->allocation.width;
892     attributes.height = widget->allocation.height;
893     attributes.window_type = GDK_WINDOW_CHILD;
894     attributes.wclass = GDK_INPUT_OUTPUT;
895     attributes.visual = gtk_widget_get_visual (widget);
896     attributes.colormap = gtk_widget_get_colormap (widget);
897     attributes.event_mask = (gtk_widget_get_events (widget) |
898                              GDK_EXPOSURE_MASK |
899                              GDK_BUTTON1_MOTION_MASK |
900                              GDK_BUTTON_PRESS_MASK |
901                              GDK_BUTTON_RELEASE_MASK);
902     attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
903     widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), 
904                                      &attributes, attributes_mask);
905     gdk_window_set_user_data (widget->window, widget);
906   
907     widget->style = gtk_style_attach (widget->style, widget->window);
908     gtk_style_set_background (widget->style, widget->window, 
909                               GTK_WIDGET_STATE (item));
910     gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
912     if (item->child)
913         gtk_widget_set_parent_window (item->child, widget->window);
914     
915     if (item->_priv->grip)
916         gtk_widget_set_parent_window (item->_priv->grip, widget->window);
919 static void
920 gdl_dock_item_style_set (GtkWidget *widget,
921                          GtkStyle  *previous_style)
923     g_return_if_fail (widget != NULL);
924     g_return_if_fail (GDL_IS_DOCK_ITEM (widget));
926     if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_NO_WINDOW (widget)) {
927         gtk_style_set_background (widget->style, widget->window,
928                                   widget->state);
929         if (GTK_WIDGET_DRAWABLE (widget))
930             gdk_window_clear (widget->window);
931     }
934 static void
935 gdl_dock_item_paint (GtkWidget      *widget,
936                      GdkEventExpose *event)
938     GdlDockItem  *item;
940     item = GDL_DOCK_ITEM (widget);
942     gtk_paint_box (widget->style,
943                    widget->window,
944                    GTK_WIDGET_STATE (widget),
945                    GTK_SHADOW_NONE,
946                    &event->area, widget,
947                    "dockitem",
948                    0, 0, -1, -1);
951 static gint
952 gdl_dock_item_expose (GtkWidget      *widget,
953                       GdkEventExpose *event)
955     g_return_val_if_fail (widget != NULL, FALSE);
956     g_return_val_if_fail (GDL_IS_DOCK_ITEM (widget), FALSE);
957     g_return_val_if_fail (event != NULL, FALSE);
959     if (GTK_WIDGET_DRAWABLE (widget) && event->window == widget->window) {
960         gdl_dock_item_paint (widget, event);
961         GDL_CALL_PARENT_GBOOLEAN(GTK_WIDGET_CLASS, expose_event, (widget,event));
962     }
963   
964     return FALSE;
967 static void
968 gdl_dock_item_move_focus_child (GdlDockItem      *item,
969                                 GtkDirectionType  dir)
971     g_return_if_fail (GDL_IS_DOCK_ITEM (item));
972     gtk_widget_child_focus (GTK_WIDGET (item->child), dir);
975 #define EVENT_IN_GRIP_EVENT_WINDOW(ev,gr) \
976     ((gr) != NULL && (ev)->window == GDL_DOCK_ITEM_GRIP (gr)->title_window)
978 #define EVENT_IN_TABLABEL_EVENT_WINDOW(ev,tl) \
979     ((tl) != NULL && (ev)->window == GDL_DOCK_TABLABEL (tl)->event_window)
981 static gint
982 gdl_dock_item_button_changed (GtkWidget      *widget,
983                               GdkEventButton *event)
985     GdlDockItem *item;
986     gboolean     locked;
987     gboolean     event_handled;
988     gboolean     in_handle;
989     GdkCursor   *cursor;
990   
991     g_return_val_if_fail (widget != NULL, FALSE);
992     g_return_val_if_fail (GDL_IS_DOCK_ITEM (widget), FALSE);
993     g_return_val_if_fail (event != NULL, FALSE);
994     
995     item = GDL_DOCK_ITEM (widget);
997     if (!EVENT_IN_GRIP_EVENT_WINDOW (event, item->_priv->grip))
998         return FALSE;
999     
1000     locked = !GDL_DOCK_ITEM_NOT_LOCKED (item);
1002     event_handled = FALSE;
1004     /* Check if user clicked on the drag handle. */      
1005     switch (item->orientation) {
1006     case GTK_ORIENTATION_HORIZONTAL:
1007         in_handle = event->x < item->_priv->grip->allocation.width;
1008         break;
1009     case GTK_ORIENTATION_VERTICAL:
1010         in_handle = event->y < item->_priv->grip->allocation.height;
1011         break;
1012     default:
1013         in_handle = FALSE;
1014         break;
1015     }
1017     /* Left mousebutton click on dockitem. */
1018     if (!locked && event->button == 1 && event->type == GDK_BUTTON_PRESS) {
1020         if (!gdl_dock_item_or_child_has_focus (item))
1021             gtk_widget_grab_focus (GTK_WIDGET (item));
1022             
1023         /* Set in_drag flag, grab pointer and call begin drag operation. */      
1024         if (in_handle) {
1025             item->_priv->start_x = event->x;
1026             item->_priv->start_y = event->y;
1028             GDL_DOCK_ITEM_SET_FLAGS (item, GDL_DOCK_IN_PREDRAG);
1029             
1030             cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
1031                                                  GDK_FLEUR);
1032             gdk_window_set_cursor (GDL_DOCK_ITEM_GRIP (item->_priv->grip)->title_window,
1033                                    cursor);
1034             gdk_cursor_unref (cursor);
1035         
1036             event_handled = TRUE;
1037         };
1038         
1039     } else if (!locked &&event->type == GDK_BUTTON_RELEASE && event->button == 1) {
1040         if (GDL_DOCK_ITEM_IN_DRAG (item)) {
1041             /* User dropped widget somewhere. */
1042             gdl_dock_item_drag_end (item, FALSE);
1043             gtk_widget_grab_focus (GTK_WIDGET (item));
1044             event_handled = TRUE;
1045         }
1046         else if (GDL_DOCK_ITEM_IN_PREDRAG (item)) {
1047             GDL_DOCK_ITEM_UNSET_FLAGS (item, GDL_DOCK_IN_PREDRAG);
1048             event_handled = TRUE;
1049         }
1051         /* we check the window since if the item was redocked it's
1052            been unrealized and maybe it's not realized again yet */
1053         if (GDL_DOCK_ITEM_GRIP (item->_priv->grip)->title_window) {
1054             cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
1055                                                  GDK_HAND2);
1056             gdk_window_set_cursor (GDL_DOCK_ITEM_GRIP (item->_priv->grip)->title_window,
1057                                    cursor);
1058             gdk_cursor_unref (cursor);
1059         }
1061     } else if (event->button == 3 && event->type == GDK_BUTTON_PRESS && in_handle) {
1062         gdl_dock_item_popup_menu (item, event->button, event->time);
1063         event_handled = TRUE;           
1064     }
1066     return event_handled;
1069 static gint
1070 gdl_dock_item_motion (GtkWidget      *widget,
1071                       GdkEventMotion *event)
1073     GdlDockItem *item;
1074     gint         new_x, new_y;
1076     g_return_val_if_fail (widget != NULL, FALSE);
1077     g_return_val_if_fail (GDL_IS_DOCK_ITEM (widget), FALSE);
1078     g_return_val_if_fail (event != NULL, FALSE);
1080     item = GDL_DOCK_ITEM (widget);
1082     if (!EVENT_IN_GRIP_EVENT_WINDOW (event, item->_priv->grip))
1083         return FALSE;
1085     if (GDL_DOCK_ITEM_IN_PREDRAG (item)) {
1086         if (gtk_drag_check_threshold (widget,
1087                                       item->_priv->start_x,
1088                                       item->_priv->start_y,
1089                                       event->x,
1090                                       event->y)) {
1091             GDL_DOCK_ITEM_UNSET_FLAGS (item, GDL_DOCK_IN_PREDRAG);
1092             item->dragoff_x = item->_priv->start_x;
1093             item->dragoff_y = item->_priv->start_y;
1095             gdl_dock_item_drag_start (item);
1096         }
1097     }
1098     
1099     if (!GDL_DOCK_ITEM_IN_DRAG (item))
1100         return FALSE;
1102     new_x = event->x_root;
1103     new_y = event->y_root;
1104     
1105     g_signal_emit (item, gdl_dock_item_signals [DOCK_DRAG_MOTION], 
1106                    0, new_x, new_y);
1108     return TRUE;
1111 static gboolean
1112 gdl_dock_item_key_press (GtkWidget   *widget,
1113                          GdkEventKey *event)
1115     gboolean event_handled = FALSE;
1116     if (GDL_DOCK_ITEM_IN_DRAG (widget)) {
1117         if (event->keyval == GDK_Escape) {
1118             gdl_dock_item_drag_end (GDL_DOCK_ITEM (widget), TRUE);
1119             event_handled = TRUE;
1120         }
1121     }
1123     if (event_handled)
1124         return TRUE;
1125     else
1126         return GDL_CALL_PARENT_WITH_DEFAULT (GTK_WIDGET_CLASS,
1127                                                key_press_event,
1128                                                (widget, event),
1129                                                FALSE);
1132 static gboolean
1133 gdl_dock_item_dock_request (GdlDockObject  *object,
1134                             gint            x,
1135                             gint            y,
1136                             GdlDockRequest *request)
1138     GtkAllocation *alloc;
1139     gint           rel_x, rel_y;
1141     /* we get (x,y) in our allocation coordinates system */
1142     
1143     /* Get item's allocation. */
1144     alloc = &(GTK_WIDGET (object)->allocation);
1145     
1146     /* Get coordinates relative to our window. */
1147     rel_x = x - alloc->x;
1148     rel_y = y - alloc->y;
1150     /* Location is inside. */
1151     if (rel_x > 0 && rel_x < alloc->width &&
1152         rel_y > 0 && rel_y < alloc->height) {
1153         float rx, ry;
1154         GtkRequisition my, other;
1155         gint divider = -1;
1156         
1157         /* this are for calculating the extra docking parameter */
1158         gdl_dock_item_preferred_size (GDL_DOCK_ITEM (request->applicant), &other);
1159         gdl_dock_item_preferred_size (GDL_DOCK_ITEM (object), &my);
1160         
1161         /* Calculate location in terms of the available space (0-100%). */
1162         rx = (float) rel_x / alloc->width;
1163         ry = (float) rel_y / alloc->height;
1165         /* Determine dock location. */
1166         if (rx < SPLIT_RATIO) {
1167             request->position = GDL_DOCK_LEFT;
1168             divider = other.width;
1169         }
1170         else if (rx > (1 - SPLIT_RATIO)) {
1171             request->position = GDL_DOCK_RIGHT;
1172             rx = 1 - rx;
1173             divider = MAX (0, my.width - other.width);
1174         }
1175         else if (ry < SPLIT_RATIO && ry < rx) {
1176             request->position = GDL_DOCK_TOP;
1177             divider = other.height;
1178         }
1179         else if (ry > (1 - SPLIT_RATIO) && (1 - ry) < rx) {
1180             request->position = GDL_DOCK_BOTTOM;
1181             divider = MAX (0, my.height - other.height);
1182         }
1183         else
1184             request->position = GDL_DOCK_CENTER;
1186         /* Reset rectangle coordinates to entire item. */
1187         request->rect.x = 0;
1188         request->rect.y = 0;
1189         request->rect.width = alloc->width;
1190         request->rect.height = alloc->height;
1192         GdlDockItemBehavior behavior = GDL_DOCK_ITEM(object)->behavior;
1194         /* Calculate docking indicator rectangle size for new locations. Only
1195            do this when we're not over the item's current location. */
1196         if (request->applicant != object) {
1197             switch (request->position) {
1198                 case GDL_DOCK_TOP:
1199                     if (behavior & GDL_DOCK_ITEM_BEH_CANT_DOCK_TOP)
1200                         return FALSE;
1201                     request->rect.height *= SPLIT_RATIO;
1202                     break;
1203                 case GDL_DOCK_BOTTOM:
1204                     if (behavior & GDL_DOCK_ITEM_BEH_CANT_DOCK_BOTTOM)
1205                         return FALSE;
1206                     request->rect.y += request->rect.height * (1 - SPLIT_RATIO);
1207                     request->rect.height *= SPLIT_RATIO;
1208                     break;
1209                 case GDL_DOCK_LEFT:
1210                     if (behavior & GDL_DOCK_ITEM_BEH_CANT_DOCK_LEFT)
1211                         return FALSE;
1212                     request->rect.width *= SPLIT_RATIO;
1213                     break;
1214                 case GDL_DOCK_RIGHT:
1215                     if (behavior & GDL_DOCK_ITEM_BEH_CANT_DOCK_RIGHT)
1216                         return FALSE;
1217                     request->rect.x += request->rect.width * (1 - SPLIT_RATIO);
1218                     request->rect.width *= SPLIT_RATIO;
1219                     break;
1220                 case GDL_DOCK_CENTER:
1221                     if (behavior & GDL_DOCK_ITEM_BEH_CANT_DOCK_CENTER)
1222                         return FALSE;
1223                     request->rect.x = request->rect.width * SPLIT_RATIO/2;
1224                     request->rect.y = request->rect.height * SPLIT_RATIO/2;
1225                     request->rect.width = (request->rect.width *
1226                                            (1 - SPLIT_RATIO/2)) - request->rect.x;
1227                     request->rect.height = (request->rect.height *
1228                                             (1 - SPLIT_RATIO/2)) - request->rect.y;
1229                     break;
1230                 default:
1231                     break;
1232             }
1233         }
1235         /* adjust returned coordinates so they are have the same
1236            origin as our window */
1237         request->rect.x += alloc->x;
1238         request->rect.y += alloc->y;
1239         
1240         /* Set possible target location and return TRUE. */            
1241         request->target = object;
1243         /* fill-in other dock information */
1244         if (request->position != GDL_DOCK_CENTER && divider >= 0) {
1245             if (G_IS_VALUE (&request->extra))
1246                 g_value_unset (&request->extra);
1247             g_value_init (&request->extra, G_TYPE_UINT);
1248             g_value_set_uint (&request->extra, (guint) divider);
1249         }
1250         
1251         return TRUE;         
1252     }
1253     else /* No docking possible at this location. */            
1254         return FALSE;
1257 static void
1258 gdl_dock_item_dock (GdlDockObject    *object,
1259                     GdlDockObject    *requestor,
1260                     GdlDockPlacement  position,
1261                     GValue           *other_data)
1263     GdlDockObject *new_parent, *parent;
1264     gboolean       add_ourselves_first;
1266     guint          available_space=0;
1267     gint           pref_size=-1;
1268     guint          splitpos=0;
1269     GtkRequisition req, object_req, parent_req;
1270     
1271     parent = gdl_dock_object_get_parent_object (object);
1272     gdl_dock_item_preferred_size (GDL_DOCK_ITEM (requestor), &req);
1273     gdl_dock_item_preferred_size (GDL_DOCK_ITEM (object), &object_req);
1274     if (GDL_IS_DOCK_ITEM (parent))
1275         gdl_dock_item_preferred_size (GDL_DOCK_ITEM (parent), &parent_req);
1276     else
1277     {
1278         parent_req.height = GTK_WIDGET (parent)->allocation.height;
1279         parent_req.width = GTK_WIDGET (parent)->allocation.width;
1280     }
1281     
1282     /* If preferred size is not set on the requestor (perhaps a new item),
1283      * then estimate and set it. The default value (either 0 or 1 pixels) is
1284      * not any good.
1285      */
1286     switch (position) {
1287         case GDL_DOCK_TOP:
1288         case GDL_DOCK_BOTTOM:
1289             if (req.width < 2)
1290             {
1291                 req.width = object_req.width;
1292                 g_object_set (requestor, "preferred-width", req.width, NULL);
1293             }
1294             if (req.height < 2)
1295             {
1296                 req.height = NEW_DOCK_ITEM_RATIO * object_req.height;
1297                 g_object_set (requestor, "preferred-height", req.height, NULL);
1298             }
1299             if (req.width > 1)
1300                 g_object_set (object, "preferred-width", req.width, NULL);
1301             if (req.height > 1 && object_req.height > req.height)
1302                 g_object_set (object, "preferred-height",
1303                               object_req.height - req.height, NULL);
1304             break;
1305         case GDL_DOCK_LEFT:
1306         case GDL_DOCK_RIGHT:
1307             if (req.height < 2)
1308             {
1309                 req.height = object_req.height;
1310                 g_object_set (requestor, "preferred-height", req.height, NULL);
1311             }
1312             if (req.width < 2)
1313             {
1314                 req.width = NEW_DOCK_ITEM_RATIO * object_req.width;
1315                 g_object_set (requestor, "preferred-width", req.width, NULL);
1316             }
1317             if (req.height > 1)
1318                 g_object_set (object, "preferred-height", req.height, NULL);
1319             if (req.width > 1)
1320                 g_object_set (object, "preferred-width",
1321                           object_req.width - req.width, NULL);
1322             break;
1323         case GDL_DOCK_CENTER:
1324             if (req.height < 2)
1325             {
1326                 req.height = object_req.height;
1327                 g_object_set (requestor, "preferred-height", req.height, NULL);
1328             }
1329             if (req.width < 2)
1330             {
1331                 req.width = object_req.width;
1332                 g_object_set (requestor, "preferred-width", req.width, NULL);
1333             }
1334             if (req.height > 1)
1335                 g_object_set (object, "preferred-height", req.height, NULL);
1336             if (req.width > 1)
1337                 g_object_set (object, "preferred-width", req.width, NULL);
1338             break;
1339         default: 
1340         {
1341             GEnumClass *enum_class = G_ENUM_CLASS (g_type_class_ref (GDL_TYPE_DOCK_PLACEMENT));
1342             GEnumValue *enum_value = g_enum_get_value (enum_class, position);
1343             const gchar *name = enum_value ? enum_value->value_name : NULL;
1344             
1345             g_warning (_("Unsupported docking strategy %s in dock object of type %s"),
1346                        name,  G_OBJECT_TYPE_NAME (object));
1347             g_type_class_unref (enum_class);
1348             return;
1349         }
1350     }
1351     switch (position) {
1352         case GDL_DOCK_TOP:
1353         case GDL_DOCK_BOTTOM:
1354             /* get a paned style dock object */
1355             new_parent = g_object_new (gdl_dock_object_type_from_nick ("paned"),
1356                                        "orientation", GTK_ORIENTATION_VERTICAL,
1357                                        "preferred-width", object_req.width,
1358                                        "preferred-height", object_req.height,
1359                                        NULL);
1360             add_ourselves_first = (position == GDL_DOCK_BOTTOM);
1361             if (parent)
1362                 available_space = parent_req.height;
1363             pref_size = req.height;
1364             break;
1365         case GDL_DOCK_LEFT:
1366         case GDL_DOCK_RIGHT:
1367             new_parent = g_object_new (gdl_dock_object_type_from_nick ("paned"),
1368                                        "orientation", GTK_ORIENTATION_HORIZONTAL,
1369                                        "preferred-width", object_req.width,
1370                                        "preferred-height", object_req.height,
1371                                        NULL);
1372             add_ourselves_first = (position == GDL_DOCK_RIGHT);
1373             if(parent)
1374                 available_space = parent_req.width;
1375             pref_size = req.width;
1376             break;
1377         case GDL_DOCK_CENTER:
1378             new_parent = g_object_new (gdl_dock_object_type_from_nick ("notebook"),
1379                                        "preferred-width", object_req.width,
1380                                        "preferred-height", object_req.height,
1381                                        NULL);
1382             add_ourselves_first = TRUE;
1383             break;
1384         default: 
1385         {
1386             GEnumClass *enum_class = G_ENUM_CLASS (g_type_class_ref (GDL_TYPE_DOCK_PLACEMENT));
1387             GEnumValue *enum_value = g_enum_get_value (enum_class, position);
1388             const gchar *name = enum_value ? enum_value->value_name : NULL;
1389             
1390             g_warning (_("Unsupported docking strategy %s in dock object of type %s"),
1391                        name,  G_OBJECT_TYPE_NAME (object));
1392             g_type_class_unref (enum_class);
1393             return;
1394         }
1395     }
1397     /* freeze the parent so it doesn't reduce automatically */
1398     if (parent)
1399         gdl_dock_object_freeze (parent);
1401     /* ref ourselves since we could be destroyed when detached */
1402     g_object_ref (object);
1403     GDL_DOCK_OBJECT_SET_FLAGS (object, GDL_DOCK_IN_REFLOW);
1404     gdl_dock_object_detach (object, FALSE);
1406     /* freeze the new parent, so reduce won't get called before it's
1407        actually added to our parent */
1408     gdl_dock_object_freeze (new_parent);
1409     
1410     /* bind the new parent to our master, so the following adds work */
1411     gdl_dock_object_bind (new_parent, G_OBJECT (GDL_DOCK_OBJECT_GET_MASTER (object)));
1412     
1413     /* add the objects */
1414     if (add_ourselves_first) {
1415         gtk_container_add (GTK_CONTAINER (new_parent), GTK_WIDGET (object));
1416         gtk_container_add (GTK_CONTAINER (new_parent), GTK_WIDGET (requestor));
1417         splitpos = available_space - pref_size;
1418     } else {
1419         gtk_container_add (GTK_CONTAINER (new_parent), GTK_WIDGET (requestor));
1420         gtk_container_add (GTK_CONTAINER (new_parent), GTK_WIDGET (object));
1421         splitpos = pref_size;
1422     }
1424     /* add the new parent to the parent */
1425     if (parent)
1426         gtk_container_add (GTK_CONTAINER (parent), GTK_WIDGET (new_parent));
1428     /* show automatic object */
1429     if (GTK_WIDGET_VISIBLE (object))
1430         gtk_widget_show (GTK_WIDGET (new_parent));
1431     
1432     /* use extra docking parameter */
1433     if (position != GDL_DOCK_CENTER && other_data &&
1434         G_VALUE_HOLDS (other_data, G_TYPE_UINT)) {
1435         
1436         g_object_set (G_OBJECT (new_parent),
1437                       "position", g_value_get_uint (other_data),
1438                       NULL);
1439     } else if (splitpos > 0 && splitpos < available_space) {
1440         g_object_set (G_OBJECT (new_parent), "position", splitpos, NULL);
1441     }
1442     
1443     GDL_DOCK_OBJECT_UNSET_FLAGS (object, GDL_DOCK_IN_REFLOW);
1444     g_object_unref (object);
1446     gdl_dock_object_thaw (new_parent);
1447     if (parent)
1448         gdl_dock_object_thaw (parent);
1453 static void
1454 gdl_dock_item_detach_menu (GtkWidget *widget,
1455                            GtkMenu   *menu)
1457     GdlDockItem *item;
1458    
1459     item = GDL_DOCK_ITEM (widget);
1460     item->_priv->menu = NULL;
1463 static void
1464 gdl_dock_item_popup_menu (GdlDockItem  *item, 
1465                           guint         button,
1466                           guint32       time)
1468     GtkWidget *mitem;
1470     if (!item->_priv->menu) {
1471         /* Create popup menu and attach it to the dock item */
1472         item->_priv->menu = gtk_menu_new ();
1473         gtk_menu_attach_to_widget (GTK_MENU (item->_priv->menu),
1474                                    GTK_WIDGET (item),
1475                                    gdl_dock_item_detach_menu);
1476         
1477         if (item->behavior & GDL_DOCK_ITEM_BEH_LOCKED) {
1478             /* UnLock menuitem */
1479             mitem = gtk_menu_item_new_with_label (_("UnLock"));
1480             gtk_menu_shell_append (GTK_MENU_SHELL (item->_priv->menu), 
1481                                    mitem);
1482             g_signal_connect (mitem, "activate",
1483                               G_CALLBACK (gdl_dock_item_unlock_cb), item);
1484         } else {
1485             /* Hide menuitem. */
1486             mitem = gtk_menu_item_new_with_label (_("Hide"));
1487             gtk_menu_shell_append (GTK_MENU_SHELL (item->_priv->menu), mitem);
1488             g_signal_connect (mitem, "activate", 
1489                               G_CALLBACK (gdl_dock_item_hide_cb), item);
1490             /* Lock menuitem */
1491             mitem = gtk_menu_item_new_with_label (_("Lock"));
1492             gtk_menu_shell_append (GTK_MENU_SHELL (item->_priv->menu), mitem);
1493             g_signal_connect (mitem, "activate",
1494                               G_CALLBACK (gdl_dock_item_lock_cb), item);
1495         }
1496     }
1498     /* Show popup menu. */
1499     gtk_widget_show_all (item->_priv->menu);
1500     gtk_menu_popup (GTK_MENU (item->_priv->menu), NULL, NULL, NULL, NULL, 
1501                     button, time);
1504 static void
1505 gdl_dock_item_drag_start (GdlDockItem *item)
1507     GdkCursor *fleur;
1509     if (!GTK_WIDGET_REALIZED (item))
1510         gtk_widget_realize (GTK_WIDGET (item));
1511     
1512     GDL_DOCK_ITEM_SET_FLAGS (item, GDL_DOCK_IN_DRAG);
1513             
1514     /* grab the pointer so we receive all mouse events */
1515     fleur = gdk_cursor_new (GDK_FLEUR);
1517     /* grab the keyboard & pointer */
1518     gtk_grab_add (GTK_WIDGET (item));
1519     
1520     gdk_cursor_unref (fleur);
1521             
1522     g_signal_emit (item, gdl_dock_item_signals [DOCK_DRAG_BEGIN], 0);
1525 static void
1526 gdl_dock_item_drag_end (GdlDockItem *item,
1527                         gboolean     cancel)
1529     /* Release pointer & keyboard. */
1530     gtk_grab_remove (gtk_grab_get_current ());
1531     
1532     g_signal_emit (item, gdl_dock_item_signals [DOCK_DRAG_END], 0, cancel);
1533     
1534     GDL_DOCK_ITEM_UNSET_FLAGS (item, GDL_DOCK_IN_DRAG);
1537 static void 
1538 gdl_dock_item_tab_button (GtkWidget      *widget,
1539                           GdkEventButton *event,
1540                           gpointer        data)
1542     GdlDockItem *item;
1544     item = GDL_DOCK_ITEM (data);
1546     if (!GDL_DOCK_ITEM_NOT_LOCKED (item))
1547         return;
1549     switch (event->button) {
1550     case 1:
1551         /* set dragoff_{x,y} as we the user clicked on the middle of the 
1552            drag handle */
1553         switch (item->orientation) {
1554         case GTK_ORIENTATION_HORIZONTAL:
1555             /*item->dragoff_x = item->_priv->grip_size / 2;*/
1556             item->dragoff_y = GTK_WIDGET (data)->allocation.height / 2;
1557             break;
1558         case GTK_ORIENTATION_VERTICAL:
1559             /*item->dragoff_x = GTK_WIDGET (data)->allocation.width / 2;*/
1560             item->dragoff_y = item->_priv->grip_size / 2;
1561             break;
1562         };
1563         gdl_dock_item_drag_start (item);
1564         break;
1566     case 3:
1567         gdl_dock_item_popup_menu (item, event->button, event->time);
1568         break;
1570     default:
1571         break;
1572     };
1575 static void
1576 gdl_dock_item_hide_cb (GtkWidget   *widget, 
1577                        GdlDockItem *item)
1579     GdlDockMaster *master;
1580     
1581     g_return_if_fail (item != NULL);
1583     master = GDL_DOCK_OBJECT_GET_MASTER (item);
1584     gdl_dock_item_hide_item (item);
1587 static void
1588 gdl_dock_item_lock_cb (GtkWidget   *widget,
1589                        GdlDockItem *item)
1591     g_return_if_fail (item != NULL);
1593     gdl_dock_item_lock (item);
1596 static void
1597 gdl_dock_item_unlock_cb (GtkWidget   *widget,
1598                        GdlDockItem *item)
1600     g_return_if_fail (item != NULL);
1602     gdl_dock_item_unlock (item);
1605 static void
1606 gdl_dock_item_showhide_grip (GdlDockItem *item)
1608     GdkDisplay *display;
1609     GdkCursor *cursor;
1610     
1611     gdl_dock_item_detach_menu (GTK_WIDGET (item), NULL); 
1612     display = gtk_widget_get_display (GTK_WIDGET (item));
1613     cursor = NULL;
1614     
1615     if (item->_priv->grip) {
1616         if (GDL_DOCK_ITEM_GRIP_SHOWN (item) && 
1617             GDL_DOCK_ITEM_NOT_LOCKED(item))
1618              cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
1619     }
1620     if (item->_priv->grip && GDL_DOCK_ITEM_GRIP (item->_priv->grip)->title_window)
1621         gdk_window_set_cursor (GDL_DOCK_ITEM_GRIP (item->_priv->grip)->title_window, cursor);
1623     if (cursor)
1624         gdk_cursor_unref (cursor);
1625     
1626     gtk_widget_queue_resize (GTK_WIDGET (item));
1629 static void
1630 gdl_dock_item_real_set_orientation (GdlDockItem    *item,
1631                                     GtkOrientation  orientation)
1633     item->orientation = orientation;
1634     
1635     if (GTK_WIDGET_DRAWABLE (item))
1636         gtk_widget_queue_draw (GTK_WIDGET (item));
1637     gtk_widget_queue_resize (GTK_WIDGET (item));
1641 /* ----- Public interface ----- */
1643 GtkWidget *
1644 gdl_dock_item_new (const gchar         *name,
1645                    const gchar         *long_name,
1646                    GdlDockItemBehavior  behavior)
1648     GdlDockItem *item;
1650     item = GDL_DOCK_ITEM (g_object_new (GDL_TYPE_DOCK_ITEM, 
1651                                         "name", name, 
1652                                         "long-name", long_name,
1653                                         "behavior", behavior,
1654                                         NULL));
1655     GDL_DOCK_OBJECT_UNSET_FLAGS (item, GDL_DOCK_AUTOMATIC);
1656     gdl_dock_item_set_tablabel (item, gtk_label_new (long_name));
1657     return GTK_WIDGET (item);
1660 GtkWidget *
1661 gdl_dock_item_new_with_stock (const gchar         *name,
1662                               const gchar         *long_name,
1663                               const gchar         *stock_id,
1664                               GdlDockItemBehavior  behavior)
1666     GdlDockItem *item;
1668     item = GDL_DOCK_ITEM (g_object_new (GDL_TYPE_DOCK_ITEM, 
1669                                         "name", name, 
1670                                         "long-name", long_name,
1671                                         "stock-id", stock_id,
1672                                         "behavior", behavior,
1673                                         NULL));
1674     GDL_DOCK_OBJECT_UNSET_FLAGS (item, GDL_DOCK_AUTOMATIC);
1675     gdl_dock_item_set_tablabel (item, gtk_label_new (long_name));
1677     return GTK_WIDGET (item);
1680 GtkWidget *
1681 gdl_dock_item_new_with_pixbuf_icon (const gchar         *name,
1682                                     const gchar         *long_name,
1683                                     const GdkPixbuf     *pixbuf_icon,
1684                                     GdlDockItemBehavior  behavior)
1686     GdlDockItem *item;
1688     item = GDL_DOCK_ITEM (g_object_new (GDL_TYPE_DOCK_ITEM, 
1689                                         "name", name, 
1690                                         "long-name", long_name,
1691                                         "pixbuf-icon", pixbuf_icon,
1692                                         "behavior", behavior,
1693                                         NULL));
1695     GDL_DOCK_OBJECT_UNSET_FLAGS (item, GDL_DOCK_AUTOMATIC);
1696     gdl_dock_item_set_tablabel (item, gtk_label_new (long_name));
1698     return GTK_WIDGET (item);
1701 /* convenient function (and to preserve source compat) */
1702 void
1703 gdl_dock_item_dock_to (GdlDockItem      *item,
1704                        GdlDockItem      *target,
1705                        GdlDockPlacement  position,
1706                        gint              docking_param)
1708     g_return_if_fail (item != NULL);
1709     g_return_if_fail (item != target);
1710     g_return_if_fail (target != NULL || position == GDL_DOCK_FLOATING);
1711     g_return_if_fail ((item->behavior & GDL_DOCK_ITEM_BEH_NEVER_FLOATING) == 0 || position != GDL_DOCK_FLOATING);
1713     if (position == GDL_DOCK_FLOATING || !target) {
1714         GdlDockObject *controller;
1716         if (!gdl_dock_object_is_bound (GDL_DOCK_OBJECT (item))) {
1717             g_warning (_("Attempt to bind an unbound item %p"), item);
1718             return;
1719         }
1721         controller = gdl_dock_master_get_controller (GDL_DOCK_OBJECT_GET_MASTER (item));
1722         
1723         /* FIXME: save previous docking position for later
1724            re-docking... does this make sense now? */
1726         /* Create new floating dock for widget. */
1727         item->dragoff_x = item->dragoff_y = 0;
1728         gdl_dock_add_floating_item (GDL_DOCK (controller),
1729                                     item, 0, 0, -1, -1);
1731     } else
1732         gdl_dock_object_dock (GDL_DOCK_OBJECT (target),
1733                               GDL_DOCK_OBJECT (item),
1734                               position, NULL);
1737 void
1738 gdl_dock_item_set_orientation (GdlDockItem    *item,
1739                                GtkOrientation  orientation)
1741     GParamSpec *pspec;
1743     g_return_if_fail (item != NULL);
1745     if (item->orientation != orientation) {
1746         /* push the property down the hierarchy if our child supports it */
1747         if (item->child != NULL) {
1748             pspec = g_object_class_find_property (
1749                 G_OBJECT_GET_CLASS (item->child), "orientation");
1750             if (pspec && pspec->value_type == GTK_TYPE_ORIENTATION)
1751                 g_object_set (G_OBJECT (item->child),
1752                               "orientation", orientation,
1753                               NULL);
1754         };
1756         GDL_CALL_VIRTUAL (item, GDL_DOCK_ITEM_GET_CLASS, set_orientation, (item, orientation));
1757         g_object_notify (G_OBJECT (item), "orientation");
1758     }
1761 GtkWidget *
1762 gdl_dock_item_get_tablabel (GdlDockItem *item)
1764     g_return_val_if_fail (item != NULL, NULL);
1765     g_return_val_if_fail (GDL_IS_DOCK_ITEM (item), NULL);
1767     return item->_priv->tab_label;
1770 void
1771 gdl_dock_item_set_tablabel (GdlDockItem *item,
1772                             GtkWidget   *tablabel)
1774     g_return_if_fail (item != NULL);
1776     if (item->_priv->tab_label) {
1777         /* disconnect and unref the previous tablabel */
1778         if (GDL_IS_DOCK_TABLABEL (item->_priv->tab_label)) {
1779             g_signal_handlers_disconnect_matched (item->_priv->tab_label,
1780                                                   G_SIGNAL_MATCH_DATA,
1781                                                   0, 0, NULL,
1782                                                   NULL, item);
1783             g_object_set (item->_priv->tab_label, "item", NULL, NULL);
1784         }
1785         gtk_widget_unref (item->_priv->tab_label);
1786         item->_priv->tab_label = NULL;
1787     }
1788     
1789     if (tablabel) {
1790         gtk_widget_ref (tablabel);
1791         gtk_object_sink (GTK_OBJECT (tablabel));
1792         item->_priv->tab_label = tablabel;
1793         if (GDL_IS_DOCK_TABLABEL (tablabel)) {
1794             g_object_set (tablabel, "item", item, NULL);
1795             /* connect to tablabel signal */
1796             g_signal_connect (tablabel, "button_pressed_handle",
1797                               G_CALLBACK (gdl_dock_item_tab_button), item);
1798         }
1799     }
1802 void 
1803 gdl_dock_item_hide_grip (GdlDockItem *item)
1805     g_return_if_fail (item != NULL);
1806     if (item->_priv->grip_shown) {
1807         item->_priv->grip_shown = FALSE;
1808         gdl_dock_item_showhide_grip (item);
1809     };
1810     g_warning ("Grips always show unless GDL_DOCK_ITEM_BEH_NO_GRIP is set\n" );
1813 void
1814 gdl_dock_item_show_grip (GdlDockItem *item)
1816     g_return_if_fail (item != NULL);
1817     if (!item->_priv->grip_shown) {
1818         item->_priv->grip_shown = TRUE;
1819         gdl_dock_item_showhide_grip (item);
1820     };
1823 /* convenient function (and to preserve source compat) */
1824 void
1825 gdl_dock_item_bind (GdlDockItem *item,
1826                     GtkWidget   *dock)
1828     g_return_if_fail (item != NULL);
1829     g_return_if_fail (dock == NULL || GDL_IS_DOCK (dock));
1830     
1831     gdl_dock_object_bind (GDL_DOCK_OBJECT (item),
1832                           G_OBJECT (GDL_DOCK_OBJECT_GET_MASTER (dock)));
1835 /* convenient function (and to preserve source compat) */
1836 void
1837 gdl_dock_item_unbind (GdlDockItem *item)
1839     g_return_if_fail (item != NULL);
1841     gdl_dock_object_unbind (GDL_DOCK_OBJECT (item));
1844 void
1845 gdl_dock_item_hide_item (GdlDockItem *item)
1847     g_return_if_fail (item != NULL);
1849     if (!GDL_DOCK_OBJECT_ATTACHED (item))
1850         /* already hidden/detached */
1851         return;
1852        
1853     /* if the object is manual, create a new placeholder to be able to
1854        restore the position later */
1855     if (!GDL_DOCK_OBJECT_AUTOMATIC (item)) {
1856         if (item->_priv->ph)
1857             g_object_unref (item->_priv->ph); 
1858         
1859         gboolean isFloating = FALSE;
1860         gint width=0, height=0, x=0, y = 0;
1861         
1862         if (GDL_IS_DOCK (gdl_dock_object_get_parent_object (GDL_DOCK_OBJECT (item))))
1863         {
1864             GdlDock* dock = GDL_DOCK (gdl_dock_object_get_parent_object (GDL_DOCK_OBJECT (item)));
1865             g_object_get (dock,
1866                           "floating", &isFloating, 
1867                           "width", &width,
1868                           "height",&height,
1869                           "floatx",&x,
1870                           "floaty",&y,
1871                           NULL);
1872         } else {
1873             item->_priv->preferred_width=GTK_WIDGET (item)->allocation.width;
1874             item->_priv->preferred_height=GTK_WIDGET (item)->allocation.height;
1875         }
1876         item->_priv->ph = GDL_DOCK_PLACEHOLDER (
1877             g_object_new (GDL_TYPE_DOCK_PLACEHOLDER,
1878                           "sticky", FALSE,
1879                           "host", item,
1880                           "width", width,
1881                           "height", height,
1882                           "floating", isFloating,
1883                           "floatx", x,
1884                           "floaty", y,
1885                           NULL));
1886         g_object_ref (item->_priv->ph);
1887         gtk_object_sink (GTK_OBJECT (item->_priv->ph));
1888     }
1889     
1890     gdl_dock_object_freeze (GDL_DOCK_OBJECT (item));
1891     
1892     /* hide our children first, so they can also set placeholders */
1893     if (gdl_dock_object_is_compound (GDL_DOCK_OBJECT (item))) 
1894         gtk_container_foreach (GTK_CONTAINER (item),
1895                                (GtkCallback) gdl_dock_item_hide_item,
1896                                NULL);
1897     
1898     /* detach the item recursively */
1899     gdl_dock_object_detach (GDL_DOCK_OBJECT (item), TRUE);
1901     gtk_widget_hide (GTK_WIDGET (item));
1903     gdl_dock_object_thaw (GDL_DOCK_OBJECT (item));
1906 void
1907 gdl_dock_item_iconify_item (GdlDockItem *item)
1909     g_return_if_fail (item != NULL);
1910     
1911     GDL_DOCK_OBJECT_SET_FLAGS (item, GDL_DOCK_ICONIFIED);
1912     gdl_dock_item_hide_item (item);
1915 void
1916 gdl_dock_item_show_item (GdlDockItem *item)
1918     g_return_if_fail (item != NULL);
1920     GDL_DOCK_OBJECT_UNSET_FLAGS (item, GDL_DOCK_ICONIFIED);
1921     
1922     if (item->_priv->ph) {
1923         gboolean isFloating=FALSE;
1924         gint width = 0, height = 0, x= 0, y = 0;
1925         g_object_get (G_OBJECT(item->_priv->ph),
1926                       "width", &width,
1927                       "height", &height,
1928                       "floating",&isFloating,
1929                       "floatx", &x,
1930                       "floaty", &y,
1931                       NULL);
1932         if (isFloating) {
1933             GdlDockObject *controller =
1934                 gdl_dock_master_get_controller (GDL_DOCK_OBJECT_GET_MASTER (item));
1935             gdl_dock_add_floating_item (GDL_DOCK (controller),
1936                                         item, x, y, width, height);
1937         } else {
1938             gtk_container_add (GTK_CONTAINER (item->_priv->ph),
1939                                GTK_WIDGET (item));
1940         }
1941         g_object_unref (item->_priv->ph);
1942         item->_priv->ph = NULL;
1943         
1944     } else if (gdl_dock_object_is_bound (GDL_DOCK_OBJECT (item))) {
1945         GdlDockObject *toplevel;
1946         
1947         toplevel = gdl_dock_master_get_controller
1948                         (GDL_DOCK_OBJECT_GET_MASTER (item));
1949         
1950         if (item->behavior & GDL_DOCK_ITEM_BEH_NEVER_FLOATING) {
1951             g_warning("Object %s has no default position and flag GDL_DOCK_ITEM_BEH_NEVER_FLOATING is set.\n",
1952                       GDL_DOCK_OBJECT(item)->name);
1953         } else if (toplevel) {
1954             gdl_dock_object_dock (toplevel, GDL_DOCK_OBJECT (item),
1955                                   GDL_DOCK_FLOATING, NULL);
1956         } else
1957             g_warning("There is no toplevel window. GdlDockItem %s cannot be shown.\n", GDL_DOCK_OBJECT(item)->name);
1958         
1959     } else
1960         g_warning("GdlDockItem %s is not bound. It cannot be shown.\n",
1961                   GDL_DOCK_OBJECT(item)->name);
1962     
1963     gtk_widget_show (GTK_WIDGET (item));
1966 void
1967 gdl_dock_item_lock (GdlDockItem *item)
1969     g_object_set (item, "locked", TRUE, NULL);
1972 void
1973 gdl_dock_item_unlock (GdlDockItem *item)
1975     g_object_set (item, "locked", FALSE, NULL);
1978 void 
1979 gdl_dock_item_set_default_position (GdlDockItem   *item,
1980                                     GdlDockObject *reference)
1982     g_return_if_fail (item != NULL);
1984     if (item->_priv->ph) {
1985         g_object_unref (item->_priv->ph);
1986         item->_priv->ph = NULL;
1987     }
1989     if (reference && GDL_DOCK_OBJECT_ATTACHED (reference)) {
1990         if (GDL_IS_DOCK_PLACEHOLDER (reference)) {
1991             g_object_ref (reference);
1992             gtk_object_sink (GTK_OBJECT (reference));
1993             item->_priv->ph = GDL_DOCK_PLACEHOLDER (reference);
1994         } else {
1995             item->_priv->ph = GDL_DOCK_PLACEHOLDER (
1996                 g_object_new (GDL_TYPE_DOCK_PLACEHOLDER,
1997                               "sticky", TRUE,
1998                               "host", reference,
1999                               NULL));
2000             g_object_ref (item->_priv->ph);
2001             gtk_object_sink (GTK_OBJECT (item->_priv->ph));
2002         }
2003     }
2006 void 
2007 gdl_dock_item_preferred_size (GdlDockItem    *item,
2008                               GtkRequisition *req)
2010     if (!req)
2011         return;
2013     req->width = MAX (item->_priv->preferred_width,
2014                       GTK_WIDGET (item)->allocation.width);
2015     req->height = MAX (item->_priv->preferred_height,
2016                        GTK_WIDGET (item)->allocation.height);
2020 gboolean
2021 gdl_dock_item_or_child_has_focus (GdlDockItem *item)
2023     GtkWidget *item_child;
2024     gboolean item_or_child_has_focus;
2026     g_return_val_if_fail (GDL_IS_DOCK_ITEM (item), FALSE);
2028     for (item_child = GTK_CONTAINER (item)->focus_child;
2029          item_child && GTK_IS_CONTAINER (item_child) && GTK_CONTAINER (item_child)->focus_child;
2030          item_child = GTK_CONTAINER (item_child)->focus_child) ;
2031     
2032     item_or_child_has_focus =
2033         (GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (item)) || 
2034          (GTK_IS_WIDGET (item_child) && GTK_WIDGET_HAS_FOCUS (item_child)));
2035     
2036     return item_or_child_has_focus;
2040 /* ----- gtk orientation type exporter/importer ----- */
2042 static void 
2043 gdl_dock_param_export_gtk_orientation (const GValue *src,
2044                                        GValue       *dst)
2046     dst->data [0].v_pointer =
2047         g_strdup_printf ("%s", (src->data [0].v_int == GTK_ORIENTATION_HORIZONTAL) ?
2048                          "horizontal" : "vertical");
2051 static void 
2052 gdl_dock_param_import_gtk_orientation (const GValue *src,
2053                                        GValue       *dst)
2055     if (!strcmp (src->data [0].v_pointer, "horizontal"))
2056         dst->data [0].v_int = GTK_ORIENTATION_HORIZONTAL;
2057     else
2058         dst->data [0].v_int = GTK_ORIENTATION_VERTICAL;