1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
5
* Author: Gustavo Gir�ldez <gustavo.giraldez@gmx.net>
6
* Naba Kumar <naba@gnome.org>
8
* Based on GnomeDockItem/BonoboDockItem. Original copyright notice follows.
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.
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.
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.
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.
38
#include <gdk/gdkkeysyms.h>
40
#include "gdl-tools.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,
67
static void gdl_dock_item_get_property (GObject *object,
72
static void gdl_dock_item_destroy (GtkObject *object);
74
static void gdl_dock_item_add (GtkContainer *container,
76
static void gdl_dock_item_remove (GtkContainer *container,
78
static void gdl_dock_item_forall (GtkContainer *container,
79
gboolean include_internals,
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,
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,
110
static gboolean gdl_dock_item_dock_request (GdlDockObject *object,
113
GdlDockRequest *request);
114
static void gdl_dock_item_dock (GdlDockObject *object,
115
GdlDockObject *requestor,
116
GdlDockPlacement position,
119
static void gdl_dock_item_popup_menu (GdlDockItem *item,
122
static void gdl_dock_item_drag_start (GdlDockItem *item);
123
static void gdl_dock_item_drag_end (GdlDockItem *item,
126
static void gdl_dock_item_tab_button (GtkWidget *widget,
127
GdkEventButton *event,
130
static void gdl_dock_item_hide_cb (GtkWidget *widget,
133
static void gdl_dock_item_lock_cb (GtkWidget *widget,
136
static void gdl_dock_item_unlock_cb (GtkWidget *widget,
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,
146
static void gdl_dock_param_import_gtk_orientation (const GValue *src,
151
/* ----- Class variables and definitions ----- */
159
PROP_PREFERRED_WIDTH,
160
PROP_PREFERRED_HEIGHT
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 {
183
GtkWidget *tab_label;
185
gint preferred_width;
186
gint preferred_height;
188
GdlDockPlaceholder *ph;
190
gint start_x, start_y;
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);
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);
216
add_arrow_bindings (GtkBindingSet *binding_set,
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);
237
gdl_dock_item_class_init (GdlDockItemClass *klass)
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;
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"),
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,
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"),
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"),
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"),
343
gdl_dock_item_signals [DOCK_DRAG_BEGIN] =
344
g_signal_new ("dock-drag-begin",
345
G_TYPE_FROM_CLASS (klass),
347
G_STRUCT_OFFSET (GdlDockItemClass, dock_drag_begin),
348
NULL, /* accumulator */
349
NULL, /* accu_data */
350
gdl_marshal_VOID__VOID,
354
gdl_dock_item_signals [DOCK_DRAG_MOTION] =
355
g_signal_new ("dock-drag-motion",
356
G_TYPE_FROM_CLASS (klass),
358
G_STRUCT_OFFSET (GdlDockItemClass, dock_drag_motion),
359
NULL, /* accumulator */
360
NULL, /* accu_data */
361
gdl_marshal_VOID__INT_INT,
367
gdl_dock_item_signals [DOCK_DRAG_END] =
368
g_signal_new ("dock_drag_end",
369
G_TYPE_FROM_CLASS (klass),
371
G_STRUCT_OFFSET (GdlDockItemClass, dock_drag_end),
372
NULL, /* accumulator */
373
NULL, /* accu_data */
374
gdl_marshal_VOID__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,
389
GTK_TYPE_DIRECTION_TYPE);
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)
415
style_initialized = TRUE;
416
gtk_rc_parse_string (
417
"style \"gdl-dock-item-default\" {\n"
421
"class \"GdlDockItem\" "
422
"style : gtk \"gdl-dock-item-default\"\n");
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);
434
item->orientation = GTK_ORIENTATION_VERTICAL;
435
item->behavior = GDL_DOCK_ITEM_BEH_NORMAL;
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;
451
gdl_dock_item_constructor (GType type,
452
guint n_construct_properties,
453
GObjectConstructParam *construct_param)
457
g_object = GDL_CALL_PARENT_WITH_DEFAULT (G_OBJECT_CLASS,
460
n_construct_properties,
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);
473
item->_priv->grip_shown = FALSE;
481
gdl_dock_item_set_property (GObject *g_object,
486
GdlDockItem *item = GDL_DOCK_ITEM (g_object);
489
case PROP_ORIENTATION:
490
gdl_dock_item_set_orientation (item, g_value_get_enum (value));
493
item->resize = g_value_get_boolean (value);
494
gtk_widget_queue_resize (GTK_WIDGET (item));
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),
505
g_object_notify (g_object, "locked");
506
gdl_dock_item_showhide_grip (item);
513
GdlDockItemBehavior old_beh = item->behavior;
515
if (g_value_get_boolean (value))
516
item->behavior |= GDL_DOCK_ITEM_BEH_LOCKED;
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),
530
case PROP_PREFERRED_WIDTH:
531
item->_priv->preferred_width = g_value_get_int (value);
533
case PROP_PREFERRED_HEIGHT:
534
item->_priv->preferred_height = g_value_get_int (value);
537
G_OBJECT_WARN_INVALID_PROPERTY_ID (g_object, prop_id, pspec);
543
gdl_dock_item_get_property (GObject *g_object,
548
GdlDockItem *item = GDL_DOCK_ITEM (g_object);
551
case PROP_ORIENTATION:
552
g_value_set_enum (value, item->orientation);
555
g_value_set_boolean (value, item->resize);
558
g_value_set_flags (value, item->behavior);
561
g_value_set_boolean (value, !GDL_DOCK_ITEM_NOT_LOCKED (item));
563
case PROP_PREFERRED_WIDTH:
564
g_value_set_int (value, item->_priv->preferred_width);
566
case PROP_PREFERRED_HEIGHT:
567
g_value_set_int (value, item->_priv->preferred_height);
570
G_OBJECT_WARN_INVALID_PROPERTY_ID (g_object, prop_id, pspec);
576
gdl_dock_item_destroy (GtkObject *object)
578
GdlDockItem *item = GDL_DOCK_ITEM (object);
581
GdlDockItemPrivate *priv = item->_priv;
583
if (priv->tab_label) {
584
gdl_dock_item_set_tablabel (item, NULL);
587
gtk_menu_detach (GTK_MENU (priv->menu));
591
gtk_container_remove (GTK_CONTAINER (item), priv->grip);
595
g_object_unref (priv->ph);
603
GDL_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
607
gdl_dock_item_add (GtkContainer *container,
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));
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));
632
gtk_widget_set_parent (widget, GTK_WIDGET (item));
633
item->child = widget;
637
gdl_dock_item_remove (GtkContainer *container,
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));
655
if (GDL_DOCK_ITEM_IN_DRAG (item)) {
656
gdl_dock_item_drag_end (item, TRUE);
659
g_return_if_fail (item->child == widget);
661
was_visible = GTK_WIDGET_VISIBLE (widget);
663
gtk_widget_unparent (widget);
667
gtk_widget_queue_resize (GTK_WIDGET (container));
671
gdl_dock_item_forall (GtkContainer *container,
672
gboolean include_internals,
673
GtkCallback callback,
674
gpointer callback_data)
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);
684
(* callback) (item->child, callback_data);
688
gdl_dock_item_child_type (GtkContainer *container)
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;
699
gdl_dock_item_set_focus_child (GtkContainer *container,
701
gpointer callback_data)
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));
712
gdl_dock_item_size_request (GtkWidget *widget,
713
GtkRequisition *requisition)
715
GtkRequisition child_requisition;
716
GtkRequisition grip_requisition;
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. */
727
gtk_widget_size_request (item->child, &child_requisition);
729
child_requisition.width = 0;
730
child_requisition.height = 0;
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;
738
requisition->width = 0;
742
requisition->width += child_requisition.width;
743
requisition->height = child_requisition.height;
745
requisition->height = 0;
747
if (GDL_DOCK_ITEM_GRIP_SHOWN (item)) {
748
gtk_widget_size_request (item->_priv->grip, &grip_requisition);
749
requisition->height = grip_requisition.height;
751
requisition->height = 0;
755
requisition->width = child_requisition.width;
756
requisition->height += child_requisition.height;
758
requisition->width = 0;
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;
768
gdl_dock_item_size_allocate (GtkWidget *widget,
769
GtkAllocation *allocation)
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;
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;
815
child_allocation.y += grip_req.height;
816
child_allocation.height -= grip_req.height;
817
grip_alloc.height = grip_req.height;
819
if (item->_priv->grip)
820
gtk_widget_size_allocate (item->_priv->grip, &grip_alloc);
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);
832
gdl_dock_item_map (GtkWidget *widget)
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);
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);
857
gdl_dock_item_unmap (GtkWidget *widget)
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);
875
gdl_dock_item_realize (GtkWidget *widget)
877
GdkWindowAttr attributes;
878
gint attributes_mask;
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);
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) |
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);
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);
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,
929
if (GTK_WIDGET_DRAWABLE (widget))
930
gdk_window_clear (widget->window);
935
gdl_dock_item_paint (GtkWidget *widget,
936
GdkEventExpose *event)
940
item = GDL_DOCK_ITEM (widget);
942
gtk_paint_box (widget->style,
944
GTK_WIDGET_STATE (widget),
946
&event->area, widget,
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));
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)
982
gdl_dock_item_button_changed (GtkWidget *widget,
983
GdkEventButton *event)
987
gboolean event_handled;
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))
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;
1009
case GTK_ORIENTATION_VERTICAL:
1010
in_handle = event->y < item->_priv->grip->allocation.height;
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. */
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),
1032
gdk_window_set_cursor (GDL_DOCK_ITEM_GRIP (item->_priv->grip)->title_window,
1034
gdk_cursor_unref (cursor);
1036
event_handled = TRUE;
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;
1046
else if (GDL_DOCK_ITEM_IN_PREDRAG (item)) {
1047
GDL_DOCK_ITEM_UNSET_FLAGS (item, GDL_DOCK_IN_PREDRAG);
1048
event_handled = TRUE;
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),
1056
gdk_window_set_cursor (GDL_DOCK_ITEM_GRIP (item->_priv->grip)->title_window,
1058
gdk_cursor_unref (cursor);
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;
1066
return event_handled;
1070
gdl_dock_item_motion (GtkWidget *widget,
1071
GdkEventMotion *event)
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))
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,
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);
1099
if (!GDL_DOCK_ITEM_IN_DRAG (item))
1102
new_x = event->x_root;
1103
new_y = event->y_root;
1105
g_signal_emit (item, gdl_dock_item_signals [DOCK_DRAG_MOTION],
1112
gdl_dock_item_key_press (GtkWidget *widget,
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;
1126
return GDL_CALL_PARENT_WITH_DEFAULT (GTK_WIDGET_CLASS,
1133
gdl_dock_item_dock_request (GdlDockObject *object,
1136
GdlDockRequest *request)
1138
GtkAllocation *alloc;
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) {
1154
GtkRequisition my, other;
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;
1170
else if (rx > (1 - SPLIT_RATIO)) {
1171
request->position = GDL_DOCK_RIGHT;
1173
divider = MAX (0, my.width - other.width);
1175
else if (ry < SPLIT_RATIO && ry < rx) {
1176
request->position = GDL_DOCK_TOP;
1177
divider = other.height;
1179
else if (ry > (1 - SPLIT_RATIO) && (1 - ry) < rx) {
1180
request->position = GDL_DOCK_BOTTOM;
1181
divider = MAX (0, my.height - other.height);
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) {
1199
if (behavior & GDL_DOCK_ITEM_BEH_CANT_DOCK_TOP)
1201
request->rect.height *= SPLIT_RATIO;
1203
case GDL_DOCK_BOTTOM:
1204
if (behavior & GDL_DOCK_ITEM_BEH_CANT_DOCK_BOTTOM)
1206
request->rect.y += request->rect.height * (1 - SPLIT_RATIO);
1207
request->rect.height *= SPLIT_RATIO;
1210
if (behavior & GDL_DOCK_ITEM_BEH_CANT_DOCK_LEFT)
1212
request->rect.width *= SPLIT_RATIO;
1214
case GDL_DOCK_RIGHT:
1215
if (behavior & GDL_DOCK_ITEM_BEH_CANT_DOCK_RIGHT)
1217
request->rect.x += request->rect.width * (1 - SPLIT_RATIO);
1218
request->rect.width *= SPLIT_RATIO;
1220
case GDL_DOCK_CENTER:
1221
if (behavior & GDL_DOCK_ITEM_BEH_CANT_DOCK_CENTER)
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;
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);
1253
else /* No docking possible at this location. */
1258
gdl_dock_item_dock (GdlDockObject *object,
1259
GdlDockObject *requestor,
1260
GdlDockPlacement position,
1263
GdlDockObject *new_parent, *parent;
1264
gboolean add_ourselves_first;
1266
guint available_space=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);
1278
parent_req.height = GTK_WIDGET (parent)->allocation.height;
1279
parent_req.width = GTK_WIDGET (parent)->allocation.width;
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
1288
case GDL_DOCK_BOTTOM:
1291
req.width = object_req.width;
1292
g_object_set (requestor, "preferred-width", req.width, NULL);
1296
req.height = NEW_DOCK_ITEM_RATIO * object_req.height;
1297
g_object_set (requestor, "preferred-height", req.height, NULL);
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);
1306
case GDL_DOCK_RIGHT:
1309
req.height = object_req.height;
1310
g_object_set (requestor, "preferred-height", req.height, NULL);
1314
req.width = NEW_DOCK_ITEM_RATIO * object_req.width;
1315
g_object_set (requestor, "preferred-width", req.width, NULL);
1318
g_object_set (object, "preferred-height", req.height, NULL);
1320
g_object_set (object, "preferred-width",
1321
object_req.width - req.width, NULL);
1323
case GDL_DOCK_CENTER:
1326
req.height = object_req.height;
1327
g_object_set (requestor, "preferred-height", req.height, NULL);
1331
req.width = object_req.width;
1332
g_object_set (requestor, "preferred-width", req.width, NULL);
1335
g_object_set (object, "preferred-height", req.height, NULL);
1337
g_object_set (object, "preferred-width", req.width, NULL);
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);
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,
1360
add_ourselves_first = (position == GDL_DOCK_BOTTOM);
1362
available_space = parent_req.height;
1363
pref_size = req.height;
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,
1372
add_ourselves_first = (position == GDL_DOCK_RIGHT);
1374
available_space = parent_req.width;
1375
pref_size = req.width;
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,
1382
add_ourselves_first = TRUE;
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);
1397
/* freeze the parent so it doesn't reduce automatically */
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;
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;
1424
/* add the new parent to the 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),
1439
} else if (splitpos > 0 && splitpos < available_space) {
1440
g_object_set (G_OBJECT (new_parent), "position", splitpos, NULL);
1443
GDL_DOCK_OBJECT_UNSET_FLAGS (object, GDL_DOCK_IN_REFLOW);
1444
g_object_unref (object);
1446
gdl_dock_object_thaw (new_parent);
1448
gdl_dock_object_thaw (parent);
1454
gdl_dock_item_detach_menu (GtkWidget *widget,
1459
item = GDL_DOCK_ITEM (widget);
1460
item->_priv->menu = NULL;
1464
gdl_dock_item_popup_menu (GdlDockItem *item,
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),
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),
1482
g_signal_connect (mitem, "activate",
1483
G_CALLBACK (gdl_dock_item_unlock_cb), item);
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);
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);
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,
1505
gdl_dock_item_drag_start (GdlDockItem *item)
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);
1526
gdl_dock_item_drag_end (GdlDockItem *item,
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);
1538
gdl_dock_item_tab_button (GtkWidget *widget,
1539
GdkEventButton *event,
1544
item = GDL_DOCK_ITEM (data);
1546
if (!GDL_DOCK_ITEM_NOT_LOCKED (item))
1549
switch (event->button) {
1551
/* set dragoff_{x,y} as we the user clicked on the middle of the
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;
1558
case GTK_ORIENTATION_VERTICAL:
1559
/*item->dragoff_x = GTK_WIDGET (data)->allocation.width / 2;*/
1560
item->dragoff_y = item->_priv->grip_size / 2;
1563
gdl_dock_item_drag_start (item);
1567
gdl_dock_item_popup_menu (item, event->button, event->time);
1576
gdl_dock_item_hide_cb (GtkWidget *widget,
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);
1588
gdl_dock_item_lock_cb (GtkWidget *widget,
1591
g_return_if_fail (item != NULL);
1593
gdl_dock_item_lock (item);
1597
gdl_dock_item_unlock_cb (GtkWidget *widget,
1600
g_return_if_fail (item != NULL);
1602
gdl_dock_item_unlock (item);
1606
gdl_dock_item_showhide_grip (GdlDockItem *item)
1608
GdkDisplay *display;
1611
gdl_dock_item_detach_menu (GTK_WIDGET (item), NULL);
1612
display = gtk_widget_get_display (GTK_WIDGET (item));
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);
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);
1624
gdk_cursor_unref (cursor);
1626
gtk_widget_queue_resize (GTK_WIDGET (item));
1630
gdl_dock_item_real_set_orientation (GdlDockItem *item,
1631
GtkOrientation orientation)
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));
1641
/* ----- Public interface ----- */
1644
gdl_dock_item_new (const gchar *name,
1645
const gchar *long_name,
1646
GdlDockItemBehavior behavior)
1650
item = GDL_DOCK_ITEM (g_object_new (GDL_TYPE_DOCK_ITEM,
1652
"long-name", long_name,
1653
"behavior", behavior,
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);
1661
gdl_dock_item_new_with_stock (const gchar *name,
1662
const gchar *long_name,
1663
const gchar *stock_id,
1664
GdlDockItemBehavior behavior)
1668
item = GDL_DOCK_ITEM (g_object_new (GDL_TYPE_DOCK_ITEM,
1670
"long-name", long_name,
1671
"stock-id", stock_id,
1672
"behavior", behavior,
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);
1681
gdl_dock_item_new_with_pixbuf_icon (const gchar *name,
1682
const gchar *long_name,
1683
const GdkPixbuf *pixbuf_icon,
1684
GdlDockItemBehavior behavior)
1688
item = GDL_DOCK_ITEM (g_object_new (GDL_TYPE_DOCK_ITEM,
1690
"long-name", long_name,
1691
"pixbuf-icon", pixbuf_icon,
1692
"behavior", behavior,
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) */
1703
gdl_dock_item_dock_to (GdlDockItem *item,
1704
GdlDockItem *target,
1705
GdlDockPlacement position,
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);
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);
1732
gdl_dock_object_dock (GDL_DOCK_OBJECT (target),
1733
GDL_DOCK_OBJECT (item),
1738
gdl_dock_item_set_orientation (GdlDockItem *item,
1739
GtkOrientation orientation)
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,
1756
GDL_CALL_VIRTUAL (item, GDL_DOCK_ITEM_GET_CLASS, set_orientation, (item, orientation));
1757
g_object_notify (G_OBJECT (item), "orientation");
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;
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,
1783
g_object_set (item->_priv->tab_label, "item", NULL, NULL);
1785
gtk_widget_unref (item->_priv->tab_label);
1786
item->_priv->tab_label = NULL;
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);
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);
1810
g_warning ("Grips always show unless GDL_DOCK_ITEM_BEH_NO_GRIP is set\n" );
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);
1823
/* convenient function (and to preserve source compat) */
1825
gdl_dock_item_bind (GdlDockItem *item,
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)));
1835
/* convenient function (and to preserve source compat) */
1837
gdl_dock_item_unbind (GdlDockItem *item)
1839
g_return_if_fail (item != NULL);
1841
gdl_dock_object_unbind (GDL_DOCK_OBJECT (item));
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 */
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))))
1864
GdlDock* dock = GDL_DOCK (gdl_dock_object_get_parent_object (GDL_DOCK_OBJECT (item)));
1866
"floating", &isFloating,
1873
item->_priv->preferred_width=GTK_WIDGET (item)->allocation.width;
1874
item->_priv->preferred_height=GTK_WIDGET (item)->allocation.height;
1876
item->_priv->ph = GDL_DOCK_PLACEHOLDER (
1877
g_object_new (GDL_TYPE_DOCK_PLACEHOLDER,
1882
"floating", isFloating,
1886
g_object_ref (item->_priv->ph);
1887
gtk_object_sink (GTK_OBJECT (item->_priv->ph));
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,
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));
1907
gdl_dock_item_iconify_item (GdlDockItem *item)
1909
g_return_if_fail (item != NULL);
1911
GDL_DOCK_OBJECT_SET_FLAGS (item, GDL_DOCK_ICONIFIED);
1912
gdl_dock_item_hide_item (item);
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);
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),
1928
"floating",&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);
1938
gtk_container_add (GTK_CONTAINER (item->_priv->ph),
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);
1957
g_warning("There is no toplevel window. GdlDockItem %s cannot be shown.\n", GDL_DOCK_OBJECT(item)->name);
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));
1967
gdl_dock_item_lock (GdlDockItem *item)
1969
g_object_set (item, "locked", TRUE, NULL);
1973
gdl_dock_item_unlock (GdlDockItem *item)
1975
g_object_set (item, "locked", FALSE, NULL);
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;
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);
1995
item->_priv->ph = GDL_DOCK_PLACEHOLDER (
1996
g_object_new (GDL_TYPE_DOCK_PLACEHOLDER,
2000
g_object_ref (item->_priv->ph);
2001
gtk_object_sink (GTK_OBJECT (item->_priv->ph));
2007
gdl_dock_item_preferred_size (GdlDockItem *item,
2008
GtkRequisition *req)
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);
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) ;
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;
2040
/* ----- gtk orientation type exporter/importer ----- */
2043
gdl_dock_param_export_gtk_orientation (const GValue *src,
2046
dst->data [0].v_pointer =
2047
g_strdup_printf ("%s", (src->data [0].v_int == GTK_ORIENTATION_HORIZONTAL) ?
2048
"horizontal" : "vertical");
2052
gdl_dock_param_import_gtk_orientation (const GValue *src,
2055
if (!strcmp (src->data [0].v_pointer, "horizontal"))
2056
dst->data [0].v_int = GTK_ORIENTATION_HORIZONTAL;
2058
dst->data [0].v_int = GTK_ORIENTATION_VERTICAL;