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);
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;
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)
206 {
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);
213 }
215 static void
216 add_arrow_bindings (GtkBindingSet *binding_set,
217 guint keysym,
218 GtkDirectionType direction)
219 {
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);
234 }
236 static void
237 gdl_dock_item_class_init (GdlDockItemClass *klass)
238 {
239 static gboolean style_initialized = FALSE;
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;
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;
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;
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 */
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));
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));
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 */
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 }
424 }
426 static void
427 gdl_dock_item_instance_init (GdlDockItem *item)
428 {
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;
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;
448 }
450 static GObject *
451 gdl_dock_item_constructor (GType type,
452 guint n_construct_properties,
453 GObjectConstructParam *construct_param)
454 {
455 GObject *g_object;
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;
478 }
480 static void
481 gdl_dock_item_set_property (GObject *g_object,
482 guint prop_id,
483 const GValue *value,
484 GParamSpec *pspec)
485 {
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 }
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 }
540 }
542 static void
543 gdl_dock_item_get_property (GObject *g_object,
544 guint prop_id,
545 GValue *value,
546 GParamSpec *pspec)
547 {
548 GdlDockItem *item = GDL_DOCK_ITEM (g_object);
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 }
573 }
575 static void
576 gdl_dock_item_destroy (GtkObject *object)
577 {
578 GdlDockItem *item = GDL_DOCK_ITEM (object);
580 if (item->_priv) {
581 GdlDockItemPrivate *priv = item->_priv;
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 }
599 item->_priv = NULL;
600 g_free (priv);
601 }
603 GDL_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
604 }
606 static void
607 gdl_dock_item_add (GtkContainer *container,
608 GtkWidget *widget)
609 {
610 GdlDockItem *item;
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;
634 }
636 static void
637 gdl_dock_item_remove (GtkContainer *container,
638 GtkWidget *widget)
639 {
640 GdlDockItem *item;
641 gboolean was_visible;
643 g_return_if_fail (GDL_IS_DOCK_ITEM (container));
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 }
655 if (GDL_DOCK_ITEM_IN_DRAG (item)) {
656 gdl_dock_item_drag_end (item, TRUE);
657 }
659 g_return_if_fail (item->child == widget);
661 was_visible = GTK_WIDGET_VISIBLE (widget);
663 gtk_widget_unparent (widget);
664 item->child = NULL;
666 if (was_visible)
667 gtk_widget_queue_resize (GTK_WIDGET (container));
668 }
670 static void
671 gdl_dock_item_forall (GtkContainer *container,
672 gboolean include_internals,
673 GtkCallback callback,
674 gpointer callback_data)
675 {
676 GdlDockItem *item = (GdlDockItem *) container;
678 g_return_if_fail (callback != NULL);
680 if (include_internals && item->_priv->grip)
681 (* callback) (item->_priv->grip, callback_data);
683 if (item->child)
684 (* callback) (item->child, callback_data);
685 }
687 static GtkType
688 gdl_dock_item_child_type (GtkContainer *container)
689 {
690 g_return_val_if_fail (GDL_IS_DOCK_ITEM (container), G_TYPE_NONE);
692 if (!GDL_DOCK_ITEM (container)->child)
693 return GTK_TYPE_WIDGET;
694 else
695 return G_TYPE_NONE;
696 }
698 static void
699 gdl_dock_item_set_focus_child (GtkContainer *container,
700 GtkWidget *child,
701 gpointer callback_data)
702 {
703 g_return_if_fail (GDL_IS_DOCK_ITEM (container));
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));
709 }
711 static void
712 gdl_dock_item_size_request (GtkWidget *widget,
713 GtkRequisition *requisition)
714 {
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;
765 }
767 static void
768 gdl_dock_item_size_allocate (GtkWidget *widget,
769 GtkAllocation *allocation)
770 {
771 GdlDockItem *item;
773 g_return_if_fail (GDL_IS_DOCK_ITEM (widget));
774 g_return_if_fail (allocation != NULL);
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;
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);
804 if (GDL_DOCK_ITEM_GRIP_SHOWN (item)) {
805 GtkAllocation grip_alloc = child_allocation;
806 GtkRequisition grip_req;
808 gtk_widget_size_request (item->_priv->grip, &grip_req);
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 }
829 }
831 static void
832 gdl_dock_item_map (GtkWidget *widget)
833 {
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);
854 }
856 static void
857 gdl_dock_item_unmap (GtkWidget *widget)
858 {
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);
866 item = GDL_DOCK_ITEM (widget);
868 gdk_window_hide (widget->window);
870 if (item->_priv->grip)
871 gtk_widget_unmap (item->_priv->grip);
872 }
874 static void
875 gdl_dock_item_realize (GtkWidget *widget)
876 {
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);
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);
915 if (item->_priv->grip)
916 gtk_widget_set_parent_window (item->_priv->grip, widget->window);
917 }
919 static void
920 gdl_dock_item_style_set (GtkWidget *widget,
921 GtkStyle *previous_style)
922 {
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 }
932 }
934 static void
935 gdl_dock_item_paint (GtkWidget *widget,
936 GdkEventExpose *event)
937 {
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);
949 }
951 static gint
952 gdl_dock_item_expose (GtkWidget *widget,
953 GdkEventExpose *event)
954 {
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 }
964 return FALSE;
965 }
967 static void
968 gdl_dock_item_move_focus_child (GdlDockItem *item,
969 GtkDirectionType dir)
970 {
971 g_return_if_fail (GDL_IS_DOCK_ITEM (item));
972 gtk_widget_child_focus (GTK_WIDGET (item->child), dir);
973 }
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)
984 {
985 GdlDockItem *item;
986 gboolean locked;
987 gboolean event_handled;
988 gboolean in_handle;
989 GdkCursor *cursor;
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);
995 item = GDL_DOCK_ITEM (widget);
997 if (!EVENT_IN_GRIP_EVENT_WINDOW (event, item->_priv->grip))
998 return FALSE;
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));
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);
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);
1036 event_handled = TRUE;
1037 };
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;
1067 }
1069 static gint
1070 gdl_dock_item_motion (GtkWidget *widget,
1071 GdkEventMotion *event)
1072 {
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 }
1099 if (!GDL_DOCK_ITEM_IN_DRAG (item))
1100 return FALSE;
1102 new_x = event->x_root;
1103 new_y = event->y_root;
1105 g_signal_emit (item, gdl_dock_item_signals [DOCK_DRAG_MOTION],
1106 0, new_x, new_y);
1108 return TRUE;
1109 }
1111 static gboolean
1112 gdl_dock_item_key_press (GtkWidget *widget,
1113 GdkEventKey *event)
1114 {
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);
1130 }
1132 static gboolean
1133 gdl_dock_item_dock_request (GdlDockObject *object,
1134 gint x,
1135 gint y,
1136 GdlDockRequest *request)
1137 {
1138 GtkAllocation *alloc;
1139 gint rel_x, rel_y;
1141 /* we get (x,y) in our allocation coordinates system */
1143 /* Get item's allocation. */
1144 alloc = &(GTK_WIDGET (object)->allocation);
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;
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);
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;
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 }
1251 return TRUE;
1252 }
1253 else /* No docking possible at this location. */
1254 return FALSE;
1255 }
1257 static void
1258 gdl_dock_item_dock (GdlDockObject *object,
1259 GdlDockObject *requestor,
1260 GdlDockPlacement position,
1261 GValue *other_data)
1262 {
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;
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 }
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;
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;
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);
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)));
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));
1432 /* use extra docking parameter */
1433 if (position != GDL_DOCK_CENTER && other_data &&
1434 G_VALUE_HOLDS (other_data, G_TYPE_UINT)) {
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 }
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);
1451 }
1453 static void
1454 gdl_dock_item_detach_menu (GtkWidget *widget,
1455 GtkMenu *menu)
1456 {
1457 GdlDockItem *item;
1459 item = GDL_DOCK_ITEM (widget);
1460 item->_priv->menu = NULL;
1461 }
1463 static void
1464 gdl_dock_item_popup_menu (GdlDockItem *item,
1465 guint button,
1466 guint32 time)
1467 {
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);
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);
1502 }
1504 static void
1505 gdl_dock_item_drag_start (GdlDockItem *item)
1506 {
1507 GdkCursor *fleur;
1509 if (!GTK_WIDGET_REALIZED (item))
1510 gtk_widget_realize (GTK_WIDGET (item));
1512 GDL_DOCK_ITEM_SET_FLAGS (item, GDL_DOCK_IN_DRAG);
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));
1520 gdk_cursor_unref (fleur);
1522 g_signal_emit (item, gdl_dock_item_signals [DOCK_DRAG_BEGIN], 0);
1523 }
1525 static void
1526 gdl_dock_item_drag_end (GdlDockItem *item,
1527 gboolean cancel)
1528 {
1529 /* Release pointer & keyboard. */
1530 gtk_grab_remove (gtk_grab_get_current ());
1532 g_signal_emit (item, gdl_dock_item_signals [DOCK_DRAG_END], 0, cancel);
1534 GDL_DOCK_ITEM_UNSET_FLAGS (item, GDL_DOCK_IN_DRAG);
1535 }
1537 static void
1538 gdl_dock_item_tab_button (GtkWidget *widget,
1539 GdkEventButton *event,
1540 gpointer data)
1541 {
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 };
1573 }
1575 static void
1576 gdl_dock_item_hide_cb (GtkWidget *widget,
1577 GdlDockItem *item)
1578 {
1579 GdlDockMaster *master;
1581 g_return_if_fail (item != NULL);
1583 master = GDL_DOCK_OBJECT_GET_MASTER (item);
1584 gdl_dock_item_hide_item (item);
1585 }
1587 static void
1588 gdl_dock_item_lock_cb (GtkWidget *widget,
1589 GdlDockItem *item)
1590 {
1591 g_return_if_fail (item != NULL);
1593 gdl_dock_item_lock (item);
1594 }
1596 static void
1597 gdl_dock_item_unlock_cb (GtkWidget *widget,
1598 GdlDockItem *item)
1599 {
1600 g_return_if_fail (item != NULL);
1602 gdl_dock_item_unlock (item);
1603 }
1605 static void
1606 gdl_dock_item_showhide_grip (GdlDockItem *item)
1607 {
1608 GdkDisplay *display;
1609 GdkCursor *cursor;
1611 gdl_dock_item_detach_menu (GTK_WIDGET (item), NULL);
1612 display = gtk_widget_get_display (GTK_WIDGET (item));
1613 cursor = NULL;
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);
1626 gtk_widget_queue_resize (GTK_WIDGET (item));
1627 }
1629 static void
1630 gdl_dock_item_real_set_orientation (GdlDockItem *item,
1631 GtkOrientation orientation)
1632 {
1633 item->orientation = orientation;
1635 if (GTK_WIDGET_DRAWABLE (item))
1636 gtk_widget_queue_draw (GTK_WIDGET (item));
1637 gtk_widget_queue_resize (GTK_WIDGET (item));
1638 }
1641 /* ----- Public interface ----- */
1643 GtkWidget *
1644 gdl_dock_item_new (const gchar *name,
1645 const gchar *long_name,
1646 GdlDockItemBehavior behavior)
1647 {
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);
1658 }
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)
1665 {
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);
1678 }
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)
1685 {
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);
1699 }
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)
1707 {
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));
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);
1735 }
1737 void
1738 gdl_dock_item_set_orientation (GdlDockItem *item,
1739 GtkOrientation orientation)
1740 {
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 }
1759 }
1761 GtkWidget *
1762 gdl_dock_item_get_tablabel (GdlDockItem *item)
1763 {
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;
1768 }
1770 void
1771 gdl_dock_item_set_tablabel (GdlDockItem *item,
1772 GtkWidget *tablabel)
1773 {
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 }
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 }
1800 }
1802 void
1803 gdl_dock_item_hide_grip (GdlDockItem *item)
1804 {
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" );
1811 }
1813 void
1814 gdl_dock_item_show_grip (GdlDockItem *item)
1815 {
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 };
1821 }
1823 /* convenient function (and to preserve source compat) */
1824 void
1825 gdl_dock_item_bind (GdlDockItem *item,
1826 GtkWidget *dock)
1827 {
1828 g_return_if_fail (item != NULL);
1829 g_return_if_fail (dock == NULL || GDL_IS_DOCK (dock));
1831 gdl_dock_object_bind (GDL_DOCK_OBJECT (item),
1832 G_OBJECT (GDL_DOCK_OBJECT_GET_MASTER (dock)));
1833 }
1835 /* convenient function (and to preserve source compat) */
1836 void
1837 gdl_dock_item_unbind (GdlDockItem *item)
1838 {
1839 g_return_if_fail (item != NULL);
1841 gdl_dock_object_unbind (GDL_DOCK_OBJECT (item));
1842 }
1844 void
1845 gdl_dock_item_hide_item (GdlDockItem *item)
1846 {
1847 g_return_if_fail (item != NULL);
1849 if (!GDL_DOCK_OBJECT_ATTACHED (item))
1850 /* already hidden/detached */
1851 return;
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);
1859 gboolean isFloating = FALSE;
1860 gint width=0, height=0, x=0, y = 0;
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 }
1890 gdl_dock_object_freeze (GDL_DOCK_OBJECT (item));
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);
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));
1904 }
1906 void
1907 gdl_dock_item_iconify_item (GdlDockItem *item)
1908 {
1909 g_return_if_fail (item != NULL);
1911 GDL_DOCK_OBJECT_SET_FLAGS (item, GDL_DOCK_ICONIFIED);
1912 gdl_dock_item_hide_item (item);
1913 }
1915 void
1916 gdl_dock_item_show_item (GdlDockItem *item)
1917 {
1918 g_return_if_fail (item != NULL);
1920 GDL_DOCK_OBJECT_UNSET_FLAGS (item, GDL_DOCK_ICONIFIED);
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;
1944 } else if (gdl_dock_object_is_bound (GDL_DOCK_OBJECT (item))) {
1945 GdlDockObject *toplevel;
1947 toplevel = gdl_dock_master_get_controller
1948 (GDL_DOCK_OBJECT_GET_MASTER (item));
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);
1959 } else
1960 g_warning("GdlDockItem %s is not bound. It cannot be shown.\n",
1961 GDL_DOCK_OBJECT(item)->name);
1963 gtk_widget_show (GTK_WIDGET (item));
1964 }
1966 void
1967 gdl_dock_item_lock (GdlDockItem *item)
1968 {
1969 g_object_set (item, "locked", TRUE, NULL);
1970 }
1972 void
1973 gdl_dock_item_unlock (GdlDockItem *item)
1974 {
1975 g_object_set (item, "locked", FALSE, NULL);
1976 }
1978 void
1979 gdl_dock_item_set_default_position (GdlDockItem *item,
1980 GdlDockObject *reference)
1981 {
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 }
2004 }
2006 void
2007 gdl_dock_item_preferred_size (GdlDockItem *item,
2008 GtkRequisition *req)
2009 {
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);
2017 }
2020 gboolean
2021 gdl_dock_item_or_child_has_focus (GdlDockItem *item)
2022 {
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) ;
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)));
2036 return item_or_child_has_focus;
2037 }
2040 /* ----- gtk orientation type exporter/importer ----- */
2042 static void
2043 gdl_dock_param_export_gtk_orientation (const GValue *src,
2044 GValue *dst)
2045 {
2046 dst->data [0].v_pointer =
2047 g_strdup_printf ("%s", (src->data [0].v_int == GTK_ORIENTATION_HORIZONTAL) ?
2048 "horizontal" : "vertical");
2049 }
2051 static void
2052 gdl_dock_param_import_gtk_orientation (const GValue *src,
2053 GValue *dst)
2054 {
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;
2059 }