~valavanisalex/ubuntu/precise/inkscape/fix-943984

« back to all changes in this revision

Viewing changes to inkscape-0.47pre1/src/libgdl/gdl-dock-item.c

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2009-07-02 17:09:45 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20090702170945-nn6d6zswovbwju1t
Tags: 0.47~pre1-0ubuntu1
* New upstream release.
  - Don't constrain maximization on small resolution devices (pre0)
    (LP: #348842)
  - Fixes segfault on startup (pre0)
    (LP: #391149)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 */
 
30
 
 
31
 
 
32
#ifdef HAVE_CONFIG_H
 
33
#include <config.h>
 
34
#endif
 
35
 
 
36
#include "gdl-i18n.h"
 
37
#include <string.h>
 
38
#include <gdk/gdkkeysyms.h>
 
39
 
 
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"
 
51
 
 
52
#define NEW_DOCK_ITEM_RATIO 0.3
 
53
 
 
54
/* ----- Private prototypes ----- */
 
55
 
 
56
static void  gdl_dock_item_class_init    (GdlDockItemClass *class);
 
57
static void  gdl_dock_item_instance_init (GdlDockItem *item);
 
58
 
 
59
static GObject *gdl_dock_item_constructor (GType                  type,
 
60
                                           guint                  n_construct_properties,
 
61
                                           GObjectConstructParam *construct_param);
 
62
 
 
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);
 
71
 
 
72
static void  gdl_dock_item_destroy       (GtkObject *object);
 
73
 
 
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);
 
83
 
 
84
static void  gdl_dock_item_set_focus_child (GtkContainer *container,
 
85
                                            GtkWidget    *widget,
 
86
                                            gpointer      callback_data);
 
87
 
 
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);
 
99
 
 
100
static void  gdl_dock_item_move_focus_child (GdlDockItem      *item,
 
101
                                             GtkDirectionType  dir);
 
102
 
 
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);
 
109
 
 
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);
 
118
 
 
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);
 
125
 
 
126
static void  gdl_dock_item_tab_button    (GtkWidget      *widget,
 
127
                                          GdkEventButton *event,
 
128
                                          gpointer        data);
 
129
                                          
 
130
static void  gdl_dock_item_hide_cb       (GtkWidget   *widget,
 
131
                                          GdlDockItem *item);
 
132
 
 
133
static void  gdl_dock_item_lock_cb       (GtkWidget   *widget,
 
134
                                          GdlDockItem *item);
 
135
 
 
136
static void  gdl_dock_item_unlock_cb     (GtkWidget   *widget,
 
137
                                          GdlDockItem *item);
 
138
 
 
139
static void  gdl_dock_item_showhide_grip (GdlDockItem *item);
 
140
 
 
141
static void  gdl_dock_item_real_set_orientation (GdlDockItem    *item,
 
142
                                                 GtkOrientation  orientation);
 
143
 
 
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);
 
148
 
 
149
 
 
150
 
 
151
/* ----- Class variables and definitions ----- */
 
152
 
 
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
};
 
162
 
 
163
enum {
 
164
    DOCK_DRAG_BEGIN,
 
165
    DOCK_DRAG_MOTION,
 
166
    DOCK_DRAG_END,
 
167
    MOVE_FOCUS_CHILD,
 
168
    LAST_SIGNAL
 
169
};
 
170
 
 
171
static guint gdl_dock_item_signals [LAST_SIGNAL] = { 0 };
 
172
 
 
173
#define GDL_DOCK_ITEM_GRIP_SHOWN(item) \
 
174
    (GDL_DOCK_ITEM_HAS_GRIP (item)) 
 
175
 
 
176
struct _GdlDockItemPrivate {
 
177
    GtkWidget *menu;
 
178
 
 
179
    gboolean   grip_shown;
 
180
    GtkWidget *grip;
 
181
    guint      grip_size;
 
182
    
 
183
    GtkWidget *tab_label;
 
184
 
 
185
    gint       preferred_width;
 
186
    gint       preferred_height;
 
187
 
 
188
    GdlDockPlaceholder *ph;
 
189
 
 
190
    gint       start_x, start_y;
 
191
};
 
192
 
 
193
/* FIXME: implement the rest of the behaviors */
 
194
 
 
195
#define SPLIT_RATIO  0.4
 
196
 
 
197
 
 
198
/* ----- Private functions ----- */
 
199
 
 
200
GDL_CLASS_BOILERPLATE (GdlDockItem, gdl_dock_item, GdlDockObject, GDL_TYPE_DOCK_OBJECT);
 
201
 
 
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
}
 
214
 
 
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;
 
221
 
 
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
}
 
235
 
 
236
static void
 
237
gdl_dock_item_class_init (GdlDockItemClass *klass)
 
238
{
 
239
    static gboolean style_initialized = FALSE;
 
240
    
 
241
    GObjectClass       *g_object_class;
 
242
    GtkObjectClass     *gtk_object_class;
 
243
    GtkWidgetClass     *widget_class;
 
244
    GtkContainerClass  *container_class;
 
245
    GdlDockObjectClass *object_class;
 
246
    GtkBindingSet      *binding_set;
 
247
    
 
248
    g_object_class = G_OBJECT_CLASS (klass);
 
249
    gtk_object_class = GTK_OBJECT_CLASS (klass);
 
250
    widget_class = GTK_WIDGET_CLASS (klass);
 
251
    container_class = GTK_CONTAINER_CLASS (klass);
 
252
    object_class = GDL_DOCK_OBJECT_CLASS (klass);
 
253
 
 
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;
 
257
 
 
258
    gtk_object_class->destroy = gdl_dock_item_destroy;
 
259
 
 
260
    widget_class->realize = gdl_dock_item_realize;
 
261
    widget_class->map = gdl_dock_item_map;
 
262
    widget_class->unmap = gdl_dock_item_unmap;
 
263
    widget_class->size_request = gdl_dock_item_size_request;
 
264
    widget_class->size_allocate = gdl_dock_item_size_allocate;
 
265
    widget_class->style_set = gdl_dock_item_style_set;
 
266
    widget_class->expose_event = gdl_dock_item_expose;
 
267
    widget_class->button_press_event = gdl_dock_item_button_changed;
 
268
    widget_class->button_release_event = gdl_dock_item_button_changed;
 
269
    widget_class->motion_notify_event = gdl_dock_item_motion;
 
270
    widget_class->key_press_event = gdl_dock_item_key_press;
 
271
    
 
272
    container_class->add = gdl_dock_item_add;
 
273
    container_class->remove = gdl_dock_item_remove;
 
274
    container_class->forall = gdl_dock_item_forall;
 
275
    container_class->child_type = gdl_dock_item_child_type;
 
276
    container_class->set_focus_child = gdl_dock_item_set_focus_child;
 
277
    
 
278
    object_class->is_compound = FALSE;
 
279
 
 
280
    object_class->dock_request = gdl_dock_item_dock_request;
 
281
    object_class->dock = gdl_dock_item_dock;
 
282
 
 
283
    /* properties */
 
284
 
 
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));
 
293
 
 
294
    /* --- register exporter/importer for GTK_ORIENTATION */
 
295
    g_value_register_transform_func (GTK_TYPE_ORIENTATION, GDL_TYPE_DOCK_PARAM,
 
296
                                     gdl_dock_param_export_gtk_orientation);
 
297
    g_value_register_transform_func (GDL_TYPE_DOCK_PARAM, GTK_TYPE_ORIENTATION,
 
298
                                     gdl_dock_param_import_gtk_orientation);
 
299
    /* --- end of registration */
 
300
    
 
301
    g_object_class_install_property (
 
302
        g_object_class, PROP_RESIZE,
 
303
        g_param_spec_boolean ("resize", _("Resizable"),
 
304
                              _("If set, the dock item can be resized when "
 
305
                                "docked in a panel"),
 
306
                              TRUE,
 
307
                              G_PARAM_READWRITE));
 
308
                                     
 
309
    g_object_class_install_property (
 
310
        g_object_class, PROP_BEHAVIOR,
 
311
        g_param_spec_flags ("behavior", _("Item behavior"),
 
312
                            _("General behavior for the dock item (i.e. "
 
313
                              "whether it can float, if it's locked, etc.)"),
 
314
                            GDL_TYPE_DOCK_ITEM_BEHAVIOR,
 
315
                            GDL_DOCK_ITEM_BEH_NORMAL,
 
316
                            G_PARAM_READWRITE));
 
317
                                     
 
318
    g_object_class_install_property (
 
319
        g_object_class, PROP_LOCKED,
 
320
        g_param_spec_boolean ("locked", _("Locked"),
 
321
                              _("If set, the dock item cannot be dragged around "
 
322
                                "and it doesn't show a grip"),
 
323
                              FALSE,
 
324
                              G_PARAM_READWRITE |
 
325
                              GDL_DOCK_PARAM_EXPORT));
 
326
 
 
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));
 
333
 
 
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));
 
340
 
 
341
    /* signals */
 
342
    
 
343
    gdl_dock_item_signals [DOCK_DRAG_BEGIN] = 
 
344
        g_signal_new ("dock-drag-begin",
 
345
                      G_TYPE_FROM_CLASS (klass),
 
346
                      G_SIGNAL_RUN_FIRST,
 
347
                      G_STRUCT_OFFSET (GdlDockItemClass, dock_drag_begin),
 
348
                      NULL, /* accumulator */
 
349
                      NULL, /* accu_data */
 
350
                      gdl_marshal_VOID__VOID,
 
351
                      G_TYPE_NONE, 
 
352
                      0);
 
353
 
 
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);
 
366
 
 
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);
 
378
 
 
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);
 
390
 
 
391
 
 
392
    /* key bindings */
 
393
 
 
394
    binding_set = gtk_binding_set_by_class (klass);
 
395
 
 
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);
 
400
 
 
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);
 
405
 
 
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;
 
412
 
 
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
}
 
425
 
 
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);
 
431
 
 
432
    item->child = NULL;
 
433
    
 
434
    item->orientation = GTK_ORIENTATION_VERTICAL;
 
435
    item->behavior = GDL_DOCK_ITEM_BEH_NORMAL;
 
436
 
 
437
    item->resize = TRUE;
 
438
 
 
439
    item->dragoff_x = item->dragoff_y = 0;
 
440
 
 
441
    item->_priv = g_new0 (GdlDockItemPrivate, 1);
 
442
    item->_priv->menu = NULL;
 
443
 
 
444
    item->_priv->preferred_width = item->_priv->preferred_height = -1;
 
445
    item->_priv->tab_label = NULL;
 
446
 
 
447
    item->_priv->ph = NULL;
 
448
}
 
449
 
 
450
static GObject *
 
451
gdl_dock_item_constructor (GType                  type,
 
452
                           guint                  n_construct_properties,
 
453
                           GObjectConstructParam *construct_param)
 
454
{
 
455
    GObject *g_object;
 
456
    
 
457
    g_object = GDL_CALL_PARENT_WITH_DEFAULT (G_OBJECT_CLASS, 
 
458
                                               constructor, 
 
459
                                               (type,
 
460
                                                n_construct_properties,
 
461
                                                construct_param),
 
462
                                               NULL);
 
463
    if (g_object) {
 
464
        GdlDockItem *item = GDL_DOCK_ITEM (g_object);
 
465
 
 
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
    }
 
476
 
 
477
    return g_object;
 
478
}
 
479
 
 
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);
 
487
 
 
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);
 
500
 
 
501
            if ((old_beh ^ item->behavior) & GDL_DOCK_ITEM_BEH_LOCKED) {
 
502
                if (GDL_DOCK_OBJECT_GET_MASTER (item))
 
503
                    g_signal_emit_by_name (GDL_DOCK_OBJECT_GET_MASTER (item),
 
504
                                           "layout-changed");
 
505
                g_object_notify (g_object, "locked");
 
506
                gdl_dock_item_showhide_grip (item);
 
507
            }
 
508
            
 
509
            break;
 
510
        }
 
511
        case PROP_LOCKED:
 
512
        {
 
513
            GdlDockItemBehavior old_beh = item->behavior;
 
514
 
 
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;
 
519
 
 
520
            if (old_beh ^ item->behavior) {
 
521
                gdl_dock_item_showhide_grip (item);
 
522
                g_object_notify (g_object, "behavior");
 
523
 
 
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
}
 
541
 
 
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);
 
549
    
 
550
    switch (prop_id) {
 
551
        case PROP_ORIENTATION:
 
552
            g_value_set_enum (value, item->orientation);
 
553
            break;
 
554
        case PROP_RESIZE:
 
555
            g_value_set_boolean (value, item->resize);
 
556
            break;
 
557
        case PROP_BEHAVIOR:
 
558
            g_value_set_flags (value, item->behavior);
 
559
            break;
 
560
        case PROP_LOCKED:
 
561
            g_value_set_boolean (value, !GDL_DOCK_ITEM_NOT_LOCKED (item));
 
562
            break;
 
563
        case PROP_PREFERRED_WIDTH:
 
564
            g_value_set_int (value, item->_priv->preferred_width);
 
565
            break;
 
566
        case PROP_PREFERRED_HEIGHT:
 
567
            g_value_set_int (value, item->_priv->preferred_height);
 
568
            break;
 
569
        default:
 
570
            G_OBJECT_WARN_INVALID_PROPERTY_ID (g_object, prop_id, pspec);
 
571
            break;
 
572
    }
 
573
}
 
574
 
 
575
static void
 
576
gdl_dock_item_destroy (GtkObject *object)
 
577
{
 
578
    GdlDockItem *item = GDL_DOCK_ITEM (object);
 
579
 
 
580
    if (item->_priv) {
 
581
        GdlDockItemPrivate *priv = item->_priv;
 
582
        
 
583
        if (priv->tab_label) {
 
584
            gdl_dock_item_set_tablabel (item, NULL);
 
585
        };
 
586
        if (priv->menu) {
 
587
            gtk_menu_detach (GTK_MENU (priv->menu));
 
588
            priv->menu = NULL;
 
589
        };
 
590
        if (priv->grip) {
 
591
            gtk_container_remove (GTK_CONTAINER (item), priv->grip);
 
592
            priv->grip = NULL;
 
593
        }
 
594
        if (priv->ph) {
 
595
            g_object_unref (priv->ph);
 
596
            priv->ph = NULL;
 
597
        }
 
598
        
 
599
        item->_priv = NULL;
 
600
        g_free (priv);
 
601
    }
 
602
 
 
603
    GDL_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
 
604
}
 
605
 
 
606
static void 
 
607
gdl_dock_item_add (GtkContainer *container,
 
608
                   GtkWidget    *widget)
 
609
{
 
610
    GdlDockItem *item;
 
611
    
 
612
    g_return_if_fail (GDL_IS_DOCK_ITEM (container));
 
613
 
 
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
    }
 
621
 
 
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
    }
 
631
 
 
632
    gtk_widget_set_parent (widget, GTK_WIDGET (item));
 
633
    item->child = widget;
 
634
}
 
635
 
 
636
static void  
 
637
gdl_dock_item_remove (GtkContainer *container,
 
638
                      GtkWidget    *widget)
 
639
{
 
640
    GdlDockItem *item;
 
641
    gboolean     was_visible;
 
642
    
 
643
    g_return_if_fail (GDL_IS_DOCK_ITEM (container));
 
644
    
 
645
    item = GDL_DOCK_ITEM (container);
 
646
    if (item->_priv && widget == item->_priv->grip) {
 
647
        gboolean grip_was_visible = GTK_WIDGET_VISIBLE (widget);
 
648
        gtk_widget_unparent (widget);
 
649
        item->_priv->grip = NULL;
 
650
        if (grip_was_visible)
 
651
            gtk_widget_queue_resize (GTK_WIDGET (item));
 
652
        return;
 
653
    }
 
654
    
 
655
    if (GDL_DOCK_ITEM_IN_DRAG (item)) {
 
656
        gdl_dock_item_drag_end (item, TRUE);
 
657
    }
 
658
    
 
659
    g_return_if_fail (item->child == widget);
 
660
    
 
661
    was_visible = GTK_WIDGET_VISIBLE (widget);
 
662
 
 
663
    gtk_widget_unparent (widget);
 
664
    item->child = NULL;
 
665
    
 
666
    if (was_visible)
 
667
        gtk_widget_queue_resize (GTK_WIDGET (container));
 
668
}
 
669
 
 
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;
 
677
    
 
678
    g_return_if_fail (callback != NULL);
 
679
    
 
680
    if (include_internals && item->_priv->grip)
 
681
        (* callback) (item->_priv->grip, callback_data);
 
682
    
 
683
    if (item->child)
 
684
        (* callback) (item->child, callback_data);
 
685
}
 
686
 
 
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);
 
691
    
 
692
    if (!GDL_DOCK_ITEM (container)->child)
 
693
        return GTK_TYPE_WIDGET;
 
694
    else
 
695
        return G_TYPE_NONE;
 
696
}
 
697
 
 
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));
 
704
    
 
705
    if (GTK_CONTAINER_CLASS (parent_class)->set_focus_child)
 
706
        (* GTK_CONTAINER_CLASS (parent_class)->set_focus_child) (container, child);
 
707
 
 
708
    gdl_dock_item_showhide_grip (GDL_DOCK_ITEM (container));
 
709
}
 
710
 
 
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;
 
718
 
 
719
    g_return_if_fail (GDL_IS_DOCK_ITEM (widget));
 
720
    g_return_if_fail (requisition != NULL);
 
721
 
 
722
    item = GDL_DOCK_ITEM (widget);
 
723
 
 
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
    }
 
732
 
 
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
        }
 
740
 
 
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
        }
 
753
 
 
754
        if (item->child) {
 
755
            requisition->width = child_requisition.width;
 
756
            requisition->height += child_requisition.height;
 
757
        } else
 
758
            requisition->width = 0;
 
759
    }
 
760
 
 
761
    requisition->width += (GTK_CONTAINER (widget)->border_width + widget->style->xthickness) * 2;
 
762
    requisition->height += (GTK_CONTAINER (widget)->border_width + widget->style->ythickness) * 2;
 
763
 
 
764
    widget->requisition = *requisition;
 
765
}
 
766
 
 
767
static void
 
768
gdl_dock_item_size_allocate (GtkWidget     *widget,
 
769
                             GtkAllocation *allocation)
 
770
{
 
771
    GdlDockItem *item;
 
772
  
 
773
    g_return_if_fail (GDL_IS_DOCK_ITEM (widget));
 
774
    g_return_if_fail (allocation != NULL);
 
775
  
 
776
    item = GDL_DOCK_ITEM (widget);
 
777
 
 
778
    widget->allocation = *allocation;
 
779
 
 
780
    /* Once size is allocated, preferred size is no longer necessary */
 
781
    item->_priv->preferred_height = -1;
 
782
    item->_priv->preferred_width = -1;
 
783
    
 
784
    if (GTK_WIDGET_REALIZED (widget))
 
785
        gdk_window_move_resize (widget->window,
 
786
                                widget->allocation.x,
 
787
                                widget->allocation.y,
 
788
                                widget->allocation.width,
 
789
                                widget->allocation.height);
 
790
 
 
791
    if (item->child && GTK_WIDGET_VISIBLE (item->child)) {
 
792
        GtkAllocation  child_allocation;
 
793
        int            border_width;
 
794
 
 
795
        border_width = GTK_CONTAINER (widget)->border_width;
 
796
 
 
797
        child_allocation.x = border_width + widget->style->xthickness;
 
798
        child_allocation.y = border_width + widget->style->ythickness;
 
799
        child_allocation.width = allocation->width
 
800
            - 2 * (border_width + widget->style->xthickness);
 
801
        child_allocation.height = allocation->height
 
802
            - 2 * (border_width + widget->style->ythickness);
 
803
        
 
804
        if (GDL_DOCK_ITEM_GRIP_SHOWN (item)) {
 
805
            GtkAllocation grip_alloc = child_allocation;
 
806
            GtkRequisition grip_req;
 
807
            
 
808
            gtk_widget_size_request (item->_priv->grip, &grip_req);
 
809
            
 
810
            if (item->orientation == GTK_ORIENTATION_HORIZONTAL) {
 
811
                child_allocation.x += grip_req.width;
 
812
                child_allocation.width -= grip_req.width;
 
813
                grip_alloc.width = grip_req.width;
 
814
            } else {
 
815
                child_allocation.y += grip_req.height;
 
816
                child_allocation.height -= grip_req.height;
 
817
                grip_alloc.height = grip_req.height;
 
818
            }
 
819
            if (item->_priv->grip)
 
820
                gtk_widget_size_allocate (item->_priv->grip, &grip_alloc);
 
821
        }
 
822
        /* Allocation can't be negative */
 
823
        if (child_allocation.width < 0)
 
824
            child_allocation.width = 0;
 
825
        if (child_allocation.height < 0)
 
826
            child_allocation.height = 0;
 
827
        gtk_widget_size_allocate (item->child, &child_allocation);
 
828
    }
 
829
}
 
830
 
 
831
static void
 
832
gdl_dock_item_map (GtkWidget *widget)
 
833
{
 
834
    GdlDockItem *item;
 
835
 
 
836
    g_return_if_fail (widget != NULL);
 
837
    g_return_if_fail (GDL_IS_DOCK_ITEM (widget));
 
838
 
 
839
    GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
 
840
 
 
841
    item = GDL_DOCK_ITEM (widget);
 
842
 
 
843
    gdk_window_show (widget->window);
 
844
 
 
845
    if (item->child
 
846
        && GTK_WIDGET_VISIBLE (item->child)
 
847
        && !GTK_WIDGET_MAPPED (item->child))
 
848
        gtk_widget_map (item->child);
 
849
 
 
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
}
 
855
 
 
856
static void
 
857
gdl_dock_item_unmap (GtkWidget *widget)
 
858
{
 
859
    GdlDockItem *item;
 
860
 
 
861
    g_return_if_fail (widget != NULL);
 
862
    g_return_if_fail (GDL_IS_DOCK_ITEM (widget));
 
863
 
 
864
    GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
 
865
    
 
866
    item = GDL_DOCK_ITEM (widget);
 
867
 
 
868
    gdk_window_hide (widget->window);
 
869
 
 
870
    if (item->_priv->grip)
 
871
        gtk_widget_unmap (item->_priv->grip);
 
872
}
 
873
 
 
874
static void
 
875
gdl_dock_item_realize (GtkWidget *widget)
 
876
{
 
877
    GdkWindowAttr  attributes;
 
878
    gint           attributes_mask;
 
879
    GdlDockItem   *item;
 
880
 
 
881
    g_return_if_fail (widget != NULL);
 
882
    g_return_if_fail (GDL_IS_DOCK_ITEM (widget));
 
883
 
 
884
    item = GDL_DOCK_ITEM (widget);
 
885
 
 
886
    GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
 
887
 
 
888
    /* widget window */
 
889
    attributes.x = widget->allocation.x;
 
890
    attributes.y = widget->allocation.y;
 
891
    attributes.width = widget->allocation.width;
 
892
    attributes.height = widget->allocation.height;
 
893
    attributes.window_type = GDK_WINDOW_CHILD;
 
894
    attributes.wclass = GDK_INPUT_OUTPUT;
 
895
    attributes.visual = gtk_widget_get_visual (widget);
 
896
    attributes.colormap = gtk_widget_get_colormap (widget);
 
897
    attributes.event_mask = (gtk_widget_get_events (widget) |
 
898
                             GDK_EXPOSURE_MASK |
 
899
                             GDK_BUTTON1_MOTION_MASK |
 
900
                             GDK_BUTTON_PRESS_MASK |
 
901
                             GDK_BUTTON_RELEASE_MASK);
 
902
    attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
 
903
    widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), 
 
904
                                     &attributes, attributes_mask);
 
905
    gdk_window_set_user_data (widget->window, widget);
 
906
  
 
907
    widget->style = gtk_style_attach (widget->style, widget->window);
 
908
    gtk_style_set_background (widget->style, widget->window, 
 
909
                              GTK_WIDGET_STATE (item));
 
910
    gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
 
911
 
 
912
    if (item->child)
 
913
        gtk_widget_set_parent_window (item->child, widget->window);
 
914
    
 
915
    if (item->_priv->grip)
 
916
        gtk_widget_set_parent_window (item->_priv->grip, widget->window);
 
917
}
 
918
 
 
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));
 
925
 
 
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
}
 
933
 
 
934
static void
 
935
gdl_dock_item_paint (GtkWidget      *widget,
 
936
                     GdkEventExpose *event)
 
937
{
 
938
    GdlDockItem  *item;
 
939
 
 
940
    item = GDL_DOCK_ITEM (widget);
 
941
 
 
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
}
 
950
 
 
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);
 
958
 
 
959
    if (GTK_WIDGET_DRAWABLE (widget) && event->window == widget->window) {
 
960
        gdl_dock_item_paint (widget, event);
 
961
        GDL_CALL_PARENT_GBOOLEAN(GTK_WIDGET_CLASS, expose_event, (widget,event));
 
962
    }
 
963
  
 
964
    return FALSE;
 
965
}
 
966
 
 
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
}
 
974
 
 
975
#define EVENT_IN_GRIP_EVENT_WINDOW(ev,gr) \
 
976
    ((gr) != NULL && (ev)->window == GDL_DOCK_ITEM_GRIP (gr)->title_window)
 
977
 
 
978
#define EVENT_IN_TABLABEL_EVENT_WINDOW(ev,tl) \
 
979
    ((tl) != NULL && (ev)->window == GDL_DOCK_TABLABEL (tl)->event_window)
 
980
 
 
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;
 
990
  
 
991
    g_return_val_if_fail (widget != NULL, FALSE);
 
992
    g_return_val_if_fail (GDL_IS_DOCK_ITEM (widget), FALSE);
 
993
    g_return_val_if_fail (event != NULL, FALSE);
 
994
    
 
995
    item = GDL_DOCK_ITEM (widget);
 
996
 
 
997
    if (!EVENT_IN_GRIP_EVENT_WINDOW (event, item->_priv->grip))
 
998
        return FALSE;
 
999
    
 
1000
    locked = !GDL_DOCK_ITEM_NOT_LOCKED (item);
 
1001
 
 
1002
    event_handled = FALSE;
 
1003
 
 
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
    }
 
1016
 
 
1017
    /* Left mousebutton click on dockitem. */
 
1018
    if (!locked && event->button == 1 && event->type == GDK_BUTTON_PRESS) {
 
1019
 
 
1020
        if (!gdl_dock_item_or_child_has_focus (item))
 
1021
            gtk_widget_grab_focus (GTK_WIDGET (item));
 
1022
            
 
1023
        /* Set in_drag flag, grab pointer and call begin drag operation. */      
 
1024
        if (in_handle) {
 
1025
            item->_priv->start_x = event->x;
 
1026
            item->_priv->start_y = event->y;
 
1027
 
 
1028
            GDL_DOCK_ITEM_SET_FLAGS (item, GDL_DOCK_IN_PREDRAG);
 
1029
            
 
1030
            cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
 
1031
                                                 GDK_FLEUR);
 
1032
            gdk_window_set_cursor (GDL_DOCK_ITEM_GRIP (item->_priv->grip)->title_window,
 
1033
                                   cursor);
 
1034
            gdk_cursor_unref (cursor);
 
1035
        
 
1036
            event_handled = TRUE;
 
1037
        };
 
1038
        
 
1039
    } else if (!locked &&event->type == GDK_BUTTON_RELEASE && event->button == 1) {
 
1040
        if (GDL_DOCK_ITEM_IN_DRAG (item)) {
 
1041
            /* User dropped widget somewhere. */
 
1042
            gdl_dock_item_drag_end (item, FALSE);
 
1043
            gtk_widget_grab_focus (GTK_WIDGET (item));
 
1044
            event_handled = TRUE;
 
1045
        }
 
1046
        else if (GDL_DOCK_ITEM_IN_PREDRAG (item)) {
 
1047
            GDL_DOCK_ITEM_UNSET_FLAGS (item, GDL_DOCK_IN_PREDRAG);
 
1048
            event_handled = TRUE;
 
1049
        }
 
1050
 
 
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
        }
 
1060
 
 
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
    }
 
1065
 
 
1066
    return event_handled;
 
1067
}
 
1068
 
 
1069
static gint
 
1070
gdl_dock_item_motion (GtkWidget      *widget,
 
1071
                      GdkEventMotion *event)
 
1072
{
 
1073
    GdlDockItem *item;
 
1074
    gint         new_x, new_y;
 
1075
 
 
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);
 
1079
 
 
1080
    item = GDL_DOCK_ITEM (widget);
 
1081
 
 
1082
    if (!EVENT_IN_GRIP_EVENT_WINDOW (event, item->_priv->grip))
 
1083
        return FALSE;
 
1084
 
 
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;
 
1094
 
 
1095
            gdl_dock_item_drag_start (item);
 
1096
        }
 
1097
    }
 
1098
    
 
1099
    if (!GDL_DOCK_ITEM_IN_DRAG (item))
 
1100
        return FALSE;
 
1101
 
 
1102
    new_x = event->x_root;
 
1103
    new_y = event->y_root;
 
1104
    
 
1105
    g_signal_emit (item, gdl_dock_item_signals [DOCK_DRAG_MOTION], 
 
1106
                   0, new_x, new_y);
 
1107
 
 
1108
    return TRUE;
 
1109
}
 
1110
 
 
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
    }
 
1122
 
 
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
}
 
1131
 
 
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;
 
1140
 
 
1141
    /* we get (x,y) in our allocation coordinates system */
 
1142
    
 
1143
    /* Get item's allocation. */
 
1144
    alloc = &(GTK_WIDGET (object)->allocation);
 
1145
    
 
1146
    /* Get coordinates relative to our window. */
 
1147
    rel_x = x - alloc->x;
 
1148
    rel_y = y - alloc->y;
 
1149
 
 
1150
    /* Location is inside. */
 
1151
    if (rel_x > 0 && rel_x < alloc->width &&
 
1152
        rel_y > 0 && rel_y < alloc->height) {
 
1153
        float rx, ry;
 
1154
        GtkRequisition my, other;
 
1155
        gint divider = -1;
 
1156
        
 
1157
        /* this are for calculating the extra docking parameter */
 
1158
        gdl_dock_item_preferred_size (GDL_DOCK_ITEM (request->applicant), &other);
 
1159
        gdl_dock_item_preferred_size (GDL_DOCK_ITEM (object), &my);
 
1160
        
 
1161
        /* Calculate location in terms of the available space (0-100%). */
 
1162
        rx = (float) rel_x / alloc->width;
 
1163
        ry = (float) rel_y / alloc->height;
 
1164
 
 
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;
 
1185
 
 
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;
 
1191
 
 
1192
        GdlDockItemBehavior behavior = GDL_DOCK_ITEM(object)->behavior;
 
1193
 
 
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
        }
 
1234
 
 
1235
        /* adjust returned coordinates so they are have the same
 
1236
           origin as our window */
 
1237
        request->rect.x += alloc->x;
 
1238
        request->rect.y += alloc->y;
 
1239
        
 
1240
        /* Set possible target location and return TRUE. */            
 
1241
        request->target = object;
 
1242
 
 
1243
        /* fill-in other dock information */
 
1244
        if (request->position != GDL_DOCK_CENTER && divider >= 0) {
 
1245
            if (G_IS_VALUE (&request->extra))
 
1246
                g_value_unset (&request->extra);
 
1247
            g_value_init (&request->extra, G_TYPE_UINT);
 
1248
            g_value_set_uint (&request->extra, (guint) divider);
 
1249
        }
 
1250
        
 
1251
        return TRUE;         
 
1252
    }
 
1253
    else /* No docking possible at this location. */            
 
1254
        return FALSE;
 
1255
}
 
1256
 
 
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;
 
1265
 
 
1266
    guint          available_space=0;
 
1267
    gint           pref_size=-1;
 
1268
    guint          splitpos=0;
 
1269
    GtkRequisition req, object_req, parent_req;
 
1270
    
 
1271
    parent = gdl_dock_object_get_parent_object (object);
 
1272
    gdl_dock_item_preferred_size (GDL_DOCK_ITEM (requestor), &req);
 
1273
    gdl_dock_item_preferred_size (GDL_DOCK_ITEM (object), &object_req);
 
1274
    if (GDL_IS_DOCK_ITEM (parent))
 
1275
        gdl_dock_item_preferred_size (GDL_DOCK_ITEM (parent), &parent_req);
 
1276
    else
 
1277
    {
 
1278
        parent_req.height = GTK_WIDGET (parent)->allocation.height;
 
1279
        parent_req.width = GTK_WIDGET (parent)->allocation.width;
 
1280
    }
 
1281
    
 
1282
    /* If preferred size is not set on the requestor (perhaps a new item),
 
1283
     * then estimate and set it. The default value (either 0 or 1 pixels) is
 
1284
     * not any good.
 
1285
     */
 
1286
    switch (position) {
 
1287
        case GDL_DOCK_TOP:
 
1288
        case GDL_DOCK_BOTTOM:
 
1289
            if (req.width < 2)
 
1290
            {
 
1291
                req.width = object_req.width;
 
1292
                g_object_set (requestor, "preferred-width", req.width, NULL);
 
1293
            }
 
1294
            if (req.height < 2)
 
1295
            {
 
1296
                req.height = NEW_DOCK_ITEM_RATIO * object_req.height;
 
1297
                g_object_set (requestor, "preferred-height", req.height, NULL);
 
1298
            }
 
1299
            if (req.width > 1)
 
1300
                g_object_set (object, "preferred-width", req.width, NULL);
 
1301
            if (req.height > 1 && object_req.height > req.height)
 
1302
                g_object_set (object, "preferred-height",
 
1303
                              object_req.height - req.height, NULL);
 
1304
            break;
 
1305
        case GDL_DOCK_LEFT:
 
1306
        case GDL_DOCK_RIGHT:
 
1307
            if (req.height < 2)
 
1308
            {
 
1309
                req.height = object_req.height;
 
1310
                g_object_set (requestor, "preferred-height", req.height, NULL);
 
1311
            }
 
1312
            if (req.width < 2)
 
1313
            {
 
1314
                req.width = NEW_DOCK_ITEM_RATIO * object_req.width;
 
1315
                g_object_set (requestor, "preferred-width", req.width, NULL);
 
1316
            }
 
1317
            if (req.height > 1)
 
1318
                g_object_set (object, "preferred-height", req.height, NULL);
 
1319
            if (req.width > 1)
 
1320
                g_object_set (object, "preferred-width",
 
1321
                          object_req.width - req.width, NULL);
 
1322
            break;
 
1323
        case GDL_DOCK_CENTER:
 
1324
            if (req.height < 2)
 
1325
            {
 
1326
                req.height = object_req.height;
 
1327
                g_object_set (requestor, "preferred-height", req.height, NULL);
 
1328
            }
 
1329
            if (req.width < 2)
 
1330
            {
 
1331
                req.width = object_req.width;
 
1332
                g_object_set (requestor, "preferred-width", req.width, NULL);
 
1333
            }
 
1334
            if (req.height > 1)
 
1335
                g_object_set (object, "preferred-height", req.height, NULL);
 
1336
            if (req.width > 1)
 
1337
                g_object_set (object, "preferred-width", req.width, NULL);
 
1338
            break;
 
1339
        default: 
 
1340
        {
 
1341
            GEnumClass *enum_class = G_ENUM_CLASS (g_type_class_ref (GDL_TYPE_DOCK_PLACEMENT));
 
1342
            GEnumValue *enum_value = g_enum_get_value (enum_class, position);
 
1343
            const gchar *name = enum_value ? enum_value->value_name : NULL;
 
1344
            
 
1345
            g_warning (_("Unsupported docking strategy %s in dock object of type %s"),
 
1346
                       name,  G_OBJECT_TYPE_NAME (object));
 
1347
            g_type_class_unref (enum_class);
 
1348
            return;
 
1349
        }
 
1350
    }
 
1351
    switch (position) {
 
1352
        case GDL_DOCK_TOP:
 
1353
        case GDL_DOCK_BOTTOM:
 
1354
            /* get a paned style dock object */
 
1355
            new_parent = g_object_new (gdl_dock_object_type_from_nick ("paned"),
 
1356
                                       "orientation", GTK_ORIENTATION_VERTICAL,
 
1357
                                       "preferred-width", object_req.width,
 
1358
                                       "preferred-height", object_req.height,
 
1359
                                       NULL);
 
1360
            add_ourselves_first = (position == GDL_DOCK_BOTTOM);
 
1361
            if (parent)
 
1362
                available_space = parent_req.height;
 
1363
            pref_size = req.height;
 
1364
            break;
 
1365
        case GDL_DOCK_LEFT:
 
1366
        case GDL_DOCK_RIGHT:
 
1367
            new_parent = g_object_new (gdl_dock_object_type_from_nick ("paned"),
 
1368
                                       "orientation", GTK_ORIENTATION_HORIZONTAL,
 
1369
                                       "preferred-width", object_req.width,
 
1370
                                       "preferred-height", object_req.height,
 
1371
                                       NULL);
 
1372
            add_ourselves_first = (position == GDL_DOCK_RIGHT);
 
1373
            if(parent)
 
1374
                available_space = parent_req.width;
 
1375
            pref_size = req.width;
 
1376
            break;
 
1377
        case GDL_DOCK_CENTER:
 
1378
            new_parent = g_object_new (gdl_dock_object_type_from_nick ("notebook"),
 
1379
                                       "preferred-width", object_req.width,
 
1380
                                       "preferred-height", object_req.height,
 
1381
                                       NULL);
 
1382
            add_ourselves_first = TRUE;
 
1383
            break;
 
1384
        default: 
 
1385
        {
 
1386
            GEnumClass *enum_class = G_ENUM_CLASS (g_type_class_ref (GDL_TYPE_DOCK_PLACEMENT));
 
1387
            GEnumValue *enum_value = g_enum_get_value (enum_class, position);
 
1388
            const gchar *name = enum_value ? enum_value->value_name : NULL;
 
1389
            
 
1390
            g_warning (_("Unsupported docking strategy %s in dock object of type %s"),
 
1391
                       name,  G_OBJECT_TYPE_NAME (object));
 
1392
            g_type_class_unref (enum_class);
 
1393
            return;
 
1394
        }
 
1395
    }
 
1396
 
 
1397
    /* freeze the parent so it doesn't reduce automatically */
 
1398
    if (parent)
 
1399
        gdl_dock_object_freeze (parent);
 
1400
 
 
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);
 
1405
 
 
1406
    /* freeze the new parent, so reduce won't get called before it's
 
1407
       actually added to our parent */
 
1408
    gdl_dock_object_freeze (new_parent);
 
1409
    
 
1410
    /* bind the new parent to our master, so the following adds work */
 
1411
    gdl_dock_object_bind (new_parent, G_OBJECT (GDL_DOCK_OBJECT_GET_MASTER (object)));
 
1412
    
 
1413
    /* add the objects */
 
1414
    if (add_ourselves_first) {
 
1415
        gtk_container_add (GTK_CONTAINER (new_parent), GTK_WIDGET (object));
 
1416
        gtk_container_add (GTK_CONTAINER (new_parent), GTK_WIDGET (requestor));
 
1417
        splitpos = available_space - pref_size;
 
1418
    } else {
 
1419
        gtk_container_add (GTK_CONTAINER (new_parent), GTK_WIDGET (requestor));
 
1420
        gtk_container_add (GTK_CONTAINER (new_parent), GTK_WIDGET (object));
 
1421
        splitpos = pref_size;
 
1422
    }
 
1423
 
 
1424
    /* add the new parent to the parent */
 
1425
    if (parent)
 
1426
        gtk_container_add (GTK_CONTAINER (parent), GTK_WIDGET (new_parent));
 
1427
 
 
1428
    /* show automatic object */
 
1429
    if (GTK_WIDGET_VISIBLE (object))
 
1430
        gtk_widget_show (GTK_WIDGET (new_parent));
 
1431
    
 
1432
    /* use extra docking parameter */
 
1433
    if (position != GDL_DOCK_CENTER && other_data &&
 
1434
        G_VALUE_HOLDS (other_data, G_TYPE_UINT)) {
 
1435
        
 
1436
        g_object_set (G_OBJECT (new_parent),
 
1437
                      "position", g_value_get_uint (other_data),
 
1438
                      NULL);
 
1439
    } else if (splitpos > 0 && splitpos < available_space) {
 
1440
        g_object_set (G_OBJECT (new_parent), "position", splitpos, NULL);
 
1441
    }
 
1442
    
 
1443
    GDL_DOCK_OBJECT_UNSET_FLAGS (object, GDL_DOCK_IN_REFLOW);
 
1444
    g_object_unref (object);
 
1445
 
 
1446
    gdl_dock_object_thaw (new_parent);
 
1447
    if (parent)
 
1448
        gdl_dock_object_thaw (parent);
 
1449
 
 
1450
 
 
1451
}
 
1452
 
 
1453
static void
 
1454
gdl_dock_item_detach_menu (GtkWidget *widget,
 
1455
                           GtkMenu   *menu)
 
1456
{
 
1457
    GdlDockItem *item;
 
1458
   
 
1459
    item = GDL_DOCK_ITEM (widget);
 
1460
    item->_priv->menu = NULL;
 
1461
}
 
1462
 
 
1463
static void
 
1464
gdl_dock_item_popup_menu (GdlDockItem  *item, 
 
1465
                          guint         button,
 
1466
                          guint32       time)
 
1467
{
 
1468
    GtkWidget *mitem;
 
1469
 
 
1470
    if (!item->_priv->menu) {
 
1471
        /* Create popup menu and attach it to the dock item */
 
1472
        item->_priv->menu = gtk_menu_new ();
 
1473
        gtk_menu_attach_to_widget (GTK_MENU (item->_priv->menu),
 
1474
                                   GTK_WIDGET (item),
 
1475
                                   gdl_dock_item_detach_menu);
 
1476
        
 
1477
        if (item->behavior & GDL_DOCK_ITEM_BEH_LOCKED) {
 
1478
            /* UnLock menuitem */
 
1479
            mitem = gtk_menu_item_new_with_label (_("UnLock"));
 
1480
            gtk_menu_shell_append (GTK_MENU_SHELL (item->_priv->menu), 
 
1481
                                   mitem);
 
1482
            g_signal_connect (mitem, "activate",
 
1483
                              G_CALLBACK (gdl_dock_item_unlock_cb), item);
 
1484
        } else {
 
1485
            /* Hide menuitem. */
 
1486
            mitem = gtk_menu_item_new_with_label (_("Hide"));
 
1487
            gtk_menu_shell_append (GTK_MENU_SHELL (item->_priv->menu), mitem);
 
1488
            g_signal_connect (mitem, "activate", 
 
1489
                              G_CALLBACK (gdl_dock_item_hide_cb), item);
 
1490
            /* Lock menuitem */
 
1491
            mitem = gtk_menu_item_new_with_label (_("Lock"));
 
1492
            gtk_menu_shell_append (GTK_MENU_SHELL (item->_priv->menu), mitem);
 
1493
            g_signal_connect (mitem, "activate",
 
1494
                              G_CALLBACK (gdl_dock_item_lock_cb), item);
 
1495
        }
 
1496
    }
 
1497
 
 
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
}
 
1503
 
 
1504
static void
 
1505
gdl_dock_item_drag_start (GdlDockItem *item)
 
1506
{
 
1507
    GdkCursor *fleur;
 
1508
 
 
1509
    if (!GTK_WIDGET_REALIZED (item))
 
1510
        gtk_widget_realize (GTK_WIDGET (item));
 
1511
    
 
1512
    GDL_DOCK_ITEM_SET_FLAGS (item, GDL_DOCK_IN_DRAG);
 
1513
            
 
1514
    /* grab the pointer so we receive all mouse events */
 
1515
    fleur = gdk_cursor_new (GDK_FLEUR);
 
1516
 
 
1517
    /* grab the keyboard & pointer */
 
1518
    gtk_grab_add (GTK_WIDGET (item));
 
1519
    
 
1520
    gdk_cursor_unref (fleur);
 
1521
            
 
1522
    g_signal_emit (item, gdl_dock_item_signals [DOCK_DRAG_BEGIN], 0);
 
1523
}
 
1524
 
 
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 ());
 
1531
    
 
1532
    g_signal_emit (item, gdl_dock_item_signals [DOCK_DRAG_END], 0, cancel);
 
1533
    
 
1534
    GDL_DOCK_ITEM_UNSET_FLAGS (item, GDL_DOCK_IN_DRAG);
 
1535
}
 
1536
 
 
1537
static void 
 
1538
gdl_dock_item_tab_button (GtkWidget      *widget,
 
1539
                          GdkEventButton *event,
 
1540
                          gpointer        data)
 
1541
{
 
1542
    GdlDockItem *item;
 
1543
 
 
1544
    item = GDL_DOCK_ITEM (data);
 
1545
 
 
1546
    if (!GDL_DOCK_ITEM_NOT_LOCKED (item))
 
1547
        return;
 
1548
 
 
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;
 
1565
 
 
1566
    case 3:
 
1567
        gdl_dock_item_popup_menu (item, event->button, event->time);
 
1568
        break;
 
1569
 
 
1570
    default:
 
1571
        break;
 
1572
    };
 
1573
}
 
1574
 
 
1575
static void
 
1576
gdl_dock_item_hide_cb (GtkWidget   *widget, 
 
1577
                       GdlDockItem *item)
 
1578
{
 
1579
    GdlDockMaster *master;
 
1580
    
 
1581
    g_return_if_fail (item != NULL);
 
1582
 
 
1583
    master = GDL_DOCK_OBJECT_GET_MASTER (item);
 
1584
    gdl_dock_item_hide_item (item);
 
1585
}
 
1586
 
 
1587
static void
 
1588
gdl_dock_item_lock_cb (GtkWidget   *widget,
 
1589
                       GdlDockItem *item)
 
1590
{
 
1591
    g_return_if_fail (item != NULL);
 
1592
 
 
1593
    gdl_dock_item_lock (item);
 
1594
}
 
1595
 
 
1596
static void
 
1597
gdl_dock_item_unlock_cb (GtkWidget   *widget,
 
1598
                       GdlDockItem *item)
 
1599
{
 
1600
    g_return_if_fail (item != NULL);
 
1601
 
 
1602
    gdl_dock_item_unlock (item);
 
1603
}
 
1604
 
 
1605
static void
 
1606
gdl_dock_item_showhide_grip (GdlDockItem *item)
 
1607
{
 
1608
    GdkDisplay *display;
 
1609
    GdkCursor *cursor;
 
1610
    
 
1611
    gdl_dock_item_detach_menu (GTK_WIDGET (item), NULL); 
 
1612
    display = gtk_widget_get_display (GTK_WIDGET (item));
 
1613
    cursor = NULL;
 
1614
    
 
1615
    if (item->_priv->grip) {
 
1616
        if (GDL_DOCK_ITEM_GRIP_SHOWN (item) && 
 
1617
            GDL_DOCK_ITEM_NOT_LOCKED(item))
 
1618
             cursor = gdk_cursor_new_for_display (display, GDK_HAND2);
 
1619
    }
 
1620
    if (item->_priv->grip && GDL_DOCK_ITEM_GRIP (item->_priv->grip)->title_window)
 
1621
        gdk_window_set_cursor (GDL_DOCK_ITEM_GRIP (item->_priv->grip)->title_window, cursor);
 
1622
 
 
1623
    if (cursor)
 
1624
        gdk_cursor_unref (cursor);
 
1625
    
 
1626
    gtk_widget_queue_resize (GTK_WIDGET (item));
 
1627
}
 
1628
 
 
1629
static void
 
1630
gdl_dock_item_real_set_orientation (GdlDockItem    *item,
 
1631
                                    GtkOrientation  orientation)
 
1632
{
 
1633
    item->orientation = orientation;
 
1634
    
 
1635
    if (GTK_WIDGET_DRAWABLE (item))
 
1636
        gtk_widget_queue_draw (GTK_WIDGET (item));
 
1637
    gtk_widget_queue_resize (GTK_WIDGET (item));
 
1638
}
 
1639
 
 
1640
 
 
1641
/* ----- Public interface ----- */
 
1642
 
 
1643
GtkWidget *
 
1644
gdl_dock_item_new (const gchar         *name,
 
1645
                   const gchar         *long_name,
 
1646
                   GdlDockItemBehavior  behavior)
 
1647
{
 
1648
    GdlDockItem *item;
 
1649
 
 
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
}
 
1659
 
 
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;
 
1667
 
 
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));
 
1676
 
 
1677
    return GTK_WIDGET (item);
 
1678
}
 
1679
 
 
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;
 
1687
 
 
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));
 
1694
 
 
1695
    GDL_DOCK_OBJECT_UNSET_FLAGS (item, GDL_DOCK_AUTOMATIC);
 
1696
    gdl_dock_item_set_tablabel (item, gtk_label_new (long_name));
 
1697
 
 
1698
    return GTK_WIDGET (item);
 
1699
}
 
1700
 
 
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);
 
1712
 
 
1713
    if (position == GDL_DOCK_FLOATING || !target) {
 
1714
        GdlDockObject *controller;
 
1715
 
 
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
        }
 
1720
 
 
1721
        controller = gdl_dock_master_get_controller (GDL_DOCK_OBJECT_GET_MASTER (item));
 
1722
        
 
1723
        /* FIXME: save previous docking position for later
 
1724
           re-docking... does this make sense now? */
 
1725
 
 
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);
 
1730
 
 
1731
    } else
 
1732
        gdl_dock_object_dock (GDL_DOCK_OBJECT (target),
 
1733
                              GDL_DOCK_OBJECT (item),
 
1734
                              position, NULL);
 
1735
}
 
1736
 
 
1737
void
 
1738
gdl_dock_item_set_orientation (GdlDockItem    *item,
 
1739
                               GtkOrientation  orientation)
 
1740
{
 
1741
    GParamSpec *pspec;
 
1742
 
 
1743
    g_return_if_fail (item != NULL);
 
1744
 
 
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
        };
 
1755
 
 
1756
        GDL_CALL_VIRTUAL (item, GDL_DOCK_ITEM_GET_CLASS, set_orientation, (item, orientation));
 
1757
        g_object_notify (G_OBJECT (item), "orientation");
 
1758
    }
 
1759
}
 
1760
 
 
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);
 
1766
 
 
1767
    return item->_priv->tab_label;
 
1768
}
 
1769
 
 
1770
void
 
1771
gdl_dock_item_set_tablabel (GdlDockItem *item,
 
1772
                            GtkWidget   *tablabel)
 
1773
{
 
1774
    g_return_if_fail (item != NULL);
 
1775
 
 
1776
    if (item->_priv->tab_label) {
 
1777
        /* disconnect and unref the previous tablabel */
 
1778
        if (GDL_IS_DOCK_TABLABEL (item->_priv->tab_label)) {
 
1779
            g_signal_handlers_disconnect_matched (item->_priv->tab_label,
 
1780
                                                  G_SIGNAL_MATCH_DATA,
 
1781
                                                  0, 0, NULL,
 
1782
                                                  NULL, item);
 
1783
            g_object_set (item->_priv->tab_label, "item", NULL, NULL);
 
1784
        }
 
1785
        gtk_widget_unref (item->_priv->tab_label);
 
1786
        item->_priv->tab_label = NULL;
 
1787
    }
 
1788
    
 
1789
    if (tablabel) {
 
1790
        gtk_widget_ref (tablabel);
 
1791
        gtk_object_sink (GTK_OBJECT (tablabel));
 
1792
        item->_priv->tab_label = tablabel;
 
1793
        if (GDL_IS_DOCK_TABLABEL (tablabel)) {
 
1794
            g_object_set (tablabel, "item", item, NULL);
 
1795
            /* connect to tablabel signal */
 
1796
            g_signal_connect (tablabel, "button_pressed_handle",
 
1797
                              G_CALLBACK (gdl_dock_item_tab_button), item);
 
1798
        }
 
1799
    }
 
1800
}
 
1801
 
 
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
}
 
1812
 
 
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
}
 
1822
 
 
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));
 
1830
    
 
1831
    gdl_dock_object_bind (GDL_DOCK_OBJECT (item),
 
1832
                          G_OBJECT (GDL_DOCK_OBJECT_GET_MASTER (dock)));
 
1833
}
 
1834
 
 
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);
 
1840
 
 
1841
    gdl_dock_object_unbind (GDL_DOCK_OBJECT (item));
 
1842
}
 
1843
 
 
1844
void
 
1845
gdl_dock_item_hide_item (GdlDockItem *item)
 
1846
{
 
1847
    g_return_if_fail (item != NULL);
 
1848
 
 
1849
    if (!GDL_DOCK_OBJECT_ATTACHED (item))
 
1850
        /* already hidden/detached */
 
1851
        return;
 
1852
       
 
1853
    /* if the object is manual, create a new placeholder to be able to
 
1854
       restore the position later */
 
1855
    if (!GDL_DOCK_OBJECT_AUTOMATIC (item)) {
 
1856
        if (item->_priv->ph)
 
1857
            g_object_unref (item->_priv->ph); 
 
1858
        
 
1859
        gboolean isFloating = FALSE;
 
1860
        gint width=0, height=0, x=0, y = 0;
 
1861
        
 
1862
        if (GDL_IS_DOCK (gdl_dock_object_get_parent_object (GDL_DOCK_OBJECT (item))))
 
1863
        {
 
1864
            GdlDock* dock = GDL_DOCK (gdl_dock_object_get_parent_object (GDL_DOCK_OBJECT (item)));
 
1865
            g_object_get (dock,
 
1866
                          "floating", &isFloating, 
 
1867
                          "width", &width,
 
1868
                          "height",&height,
 
1869
                          "floatx",&x,
 
1870
                          "floaty",&y,
 
1871
                          NULL);
 
1872
        } else {
 
1873
            item->_priv->preferred_width=GTK_WIDGET (item)->allocation.width;
 
1874
            item->_priv->preferred_height=GTK_WIDGET (item)->allocation.height;
 
1875
        }
 
1876
        item->_priv->ph = GDL_DOCK_PLACEHOLDER (
 
1877
            g_object_new (GDL_TYPE_DOCK_PLACEHOLDER,
 
1878
                          "sticky", FALSE,
 
1879
                          "host", item,
 
1880
                          "width", width,
 
1881
                          "height", height,
 
1882
                          "floating", isFloating,
 
1883
                          "floatx", x,
 
1884
                          "floaty", y,
 
1885
                          NULL));
 
1886
        g_object_ref (item->_priv->ph);
 
1887
        gtk_object_sink (GTK_OBJECT (item->_priv->ph));
 
1888
    }
 
1889
    
 
1890
    gdl_dock_object_freeze (GDL_DOCK_OBJECT (item));
 
1891
    
 
1892
    /* hide our children first, so they can also set placeholders */
 
1893
    if (gdl_dock_object_is_compound (GDL_DOCK_OBJECT (item))) 
 
1894
        gtk_container_foreach (GTK_CONTAINER (item),
 
1895
                               (GtkCallback) gdl_dock_item_hide_item,
 
1896
                               NULL);
 
1897
    
 
1898
    /* detach the item recursively */
 
1899
    gdl_dock_object_detach (GDL_DOCK_OBJECT (item), TRUE);
 
1900
 
 
1901
    gtk_widget_hide (GTK_WIDGET (item));
 
1902
 
 
1903
    gdl_dock_object_thaw (GDL_DOCK_OBJECT (item));
 
1904
}
 
1905
 
 
1906
void
 
1907
gdl_dock_item_iconify_item (GdlDockItem *item)
 
1908
{
 
1909
    g_return_if_fail (item != NULL);
 
1910
    
 
1911
    GDL_DOCK_OBJECT_SET_FLAGS (item, GDL_DOCK_ICONIFIED);
 
1912
    gdl_dock_item_hide_item (item);
 
1913
}
 
1914
 
 
1915
void
 
1916
gdl_dock_item_show_item (GdlDockItem *item)
 
1917
{
 
1918
    g_return_if_fail (item != NULL);
 
1919
 
 
1920
    GDL_DOCK_OBJECT_UNSET_FLAGS (item, GDL_DOCK_ICONIFIED);
 
1921
    
 
1922
    if (item->_priv->ph) {
 
1923
        gboolean isFloating=FALSE;
 
1924
        gint width = 0, height = 0, x= 0, y = 0;
 
1925
        g_object_get (G_OBJECT(item->_priv->ph),
 
1926
                      "width", &width,
 
1927
                      "height", &height,
 
1928
                      "floating",&isFloating,
 
1929
                      "floatx", &x,
 
1930
                      "floaty", &y,
 
1931
                      NULL);
 
1932
        if (isFloating) {
 
1933
            GdlDockObject *controller =
 
1934
                gdl_dock_master_get_controller (GDL_DOCK_OBJECT_GET_MASTER (item));
 
1935
            gdl_dock_add_floating_item (GDL_DOCK (controller),
 
1936
                                        item, x, y, width, height);
 
1937
        } else {
 
1938
            gtk_container_add (GTK_CONTAINER (item->_priv->ph),
 
1939
                               GTK_WIDGET (item));
 
1940
        }
 
1941
        g_object_unref (item->_priv->ph);
 
1942
        item->_priv->ph = NULL;
 
1943
        
 
1944
    } else if (gdl_dock_object_is_bound (GDL_DOCK_OBJECT (item))) {
 
1945
        GdlDockObject *toplevel;
 
1946
        
 
1947
        toplevel = gdl_dock_master_get_controller
 
1948
                        (GDL_DOCK_OBJECT_GET_MASTER (item));
 
1949
        
 
1950
        if (item->behavior & GDL_DOCK_ITEM_BEH_NEVER_FLOATING) {
 
1951
            g_warning("Object %s has no default position and flag GDL_DOCK_ITEM_BEH_NEVER_FLOATING is set.\n",
 
1952
                      GDL_DOCK_OBJECT(item)->name);
 
1953
        } else if (toplevel) {
 
1954
            gdl_dock_object_dock (toplevel, GDL_DOCK_OBJECT (item),
 
1955
                                  GDL_DOCK_FLOATING, NULL);
 
1956
        } else
 
1957
            g_warning("There is no toplevel window. GdlDockItem %s cannot be shown.\n", GDL_DOCK_OBJECT(item)->name);
 
1958
        
 
1959
    } else
 
1960
        g_warning("GdlDockItem %s is not bound. It cannot be shown.\n",
 
1961
                  GDL_DOCK_OBJECT(item)->name);
 
1962
    
 
1963
    gtk_widget_show (GTK_WIDGET (item));
 
1964
}
 
1965
 
 
1966
void
 
1967
gdl_dock_item_lock (GdlDockItem *item)
 
1968
{
 
1969
    g_object_set (item, "locked", TRUE, NULL);
 
1970
}
 
1971
 
 
1972
void
 
1973
gdl_dock_item_unlock (GdlDockItem *item)
 
1974
{
 
1975
    g_object_set (item, "locked", FALSE, NULL);
 
1976
}
 
1977
 
 
1978
void 
 
1979
gdl_dock_item_set_default_position (GdlDockItem   *item,
 
1980
                                    GdlDockObject *reference)
 
1981
{
 
1982
    g_return_if_fail (item != NULL);
 
1983
 
 
1984
    if (item->_priv->ph) {
 
1985
        g_object_unref (item->_priv->ph);
 
1986
        item->_priv->ph = NULL;
 
1987
    }
 
1988
 
 
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
}
 
2005
 
 
2006
void 
 
2007
gdl_dock_item_preferred_size (GdlDockItem    *item,
 
2008
                              GtkRequisition *req)
 
2009
{
 
2010
    if (!req)
 
2011
        return;
 
2012
 
 
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
}
 
2018
 
 
2019
 
 
2020
gboolean
 
2021
gdl_dock_item_or_child_has_focus (GdlDockItem *item)
 
2022
{
 
2023
    GtkWidget *item_child;
 
2024
    gboolean item_or_child_has_focus;
 
2025
 
 
2026
    g_return_val_if_fail (GDL_IS_DOCK_ITEM (item), FALSE);
 
2027
 
 
2028
    for (item_child = GTK_CONTAINER (item)->focus_child;
 
2029
         item_child && GTK_IS_CONTAINER (item_child) && GTK_CONTAINER (item_child)->focus_child;
 
2030
         item_child = GTK_CONTAINER (item_child)->focus_child) ;
 
2031
    
 
2032
    item_or_child_has_focus =
 
2033
        (GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (item)) || 
 
2034
         (GTK_IS_WIDGET (item_child) && GTK_WIDGET_HAS_FOCUS (item_child)));
 
2035
    
 
2036
    return item_or_child_has_focus;
 
2037
}
 
2038
 
 
2039
 
 
2040
/* ----- gtk orientation type exporter/importer ----- */
 
2041
 
 
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
}
 
2050
 
 
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
}
 
2060