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

« back to all changes in this revision

Viewing changes to inkscape-0.47pre1/src/libgdl/gdl-dock.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
 * This file is part of the GNOME Devtools Libraries.
 
4
 *
 
5
 * Copyright (C) 2002 Gustavo Giráldez <gustavo.giraldez@gmx.net>
 
6
 *               2007 Naba Kumar  <naba@gnome.org>
 
7
 * 
 
8
 * This library is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU Lesser General Public
 
10
 * License as published by the Free Software Foundation; either
 
11
 * version 2.1 of the License, or (at your option) any later version.
 
12
 *
 
13
 * This library is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * Lesser General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU Lesser General Public
 
19
 * License along with this library; if not, write to the Free Software
 
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
21
 */
 
22
 
 
23
#ifdef HAVE_CONFIG_H
 
24
#include <config.h>
 
25
#endif
 
26
 
 
27
#include "gdl-i18n.h"
 
28
#include <stdlib.h>
 
29
#include <string.h>
 
30
 
 
31
#include "gdl-tools.h"
 
32
#include "gdl-dock.h"
 
33
#include "gdl-dock-master.h"
 
34
#include "gdl-dock-paned.h"
 
35
#include "gdl-dock-notebook.h"
 
36
#include "gdl-dock-placeholder.h"
 
37
 
 
38
#include "libgdlmarshal.h"
 
39
 
 
40
 
 
41
/* ----- Private prototypes ----- */
 
42
 
 
43
static void  gdl_dock_class_init      (GdlDockClass *class);
 
44
static void  gdl_dock_instance_init   (GdlDock *dock);
 
45
 
 
46
static GObject *gdl_dock_constructor  (GType                  type,
 
47
                                       guint                  n_construct_properties,
 
48
                                       GObjectConstructParam *construct_param);
 
49
static void  gdl_dock_set_property    (GObject      *object,
 
50
                                       guint         prop_id,
 
51
                                       const GValue *value,
 
52
                                       GParamSpec   *pspec);
 
53
static void  gdl_dock_get_property    (GObject      *object,
 
54
                                       guint         prop_id,
 
55
                                       GValue       *value,
 
56
                                       GParamSpec   *pspec);
 
57
static void  gdl_dock_notify_cb       (GObject      *object,
 
58
                                       GParamSpec   *pspec,
 
59
                                       gpointer      user_data);
 
60
 
 
61
static void  gdl_dock_set_title       (GdlDock      *dock);
 
62
 
 
63
static void  gdl_dock_destroy         (GtkObject    *object);
 
64
 
 
65
static void  gdl_dock_size_request    (GtkWidget      *widget,
 
66
                                       GtkRequisition *requisition);
 
67
static void  gdl_dock_size_allocate   (GtkWidget      *widget,
 
68
                                       GtkAllocation  *allocation);
 
69
static void  gdl_dock_map             (GtkWidget      *widget);
 
70
static void  gdl_dock_unmap           (GtkWidget      *widget);
 
71
static void  gdl_dock_show            (GtkWidget      *widget);
 
72
static void  gdl_dock_hide            (GtkWidget      *widget);
 
73
 
 
74
static void  gdl_dock_add             (GtkContainer *container,
 
75
                                       GtkWidget    *widget);
 
76
static void  gdl_dock_remove          (GtkContainer *container,
 
77
                                       GtkWidget    *widget);
 
78
static void  gdl_dock_forall          (GtkContainer *container,
 
79
                                       gboolean      include_internals,
 
80
                                       GtkCallback   callback,
 
81
                                       gpointer      callback_data);
 
82
static GtkType  gdl_dock_child_type   (GtkContainer *container);
 
83
 
 
84
static void     gdl_dock_detach       (GdlDockObject    *object,
 
85
                                       gboolean          recursive);
 
86
static void     gdl_dock_reduce       (GdlDockObject    *object);
 
87
static gboolean gdl_dock_dock_request (GdlDockObject    *object,
 
88
                                       gint              x,
 
89
                                       gint              y,
 
90
                                       GdlDockRequest   *request);
 
91
static void     gdl_dock_dock         (GdlDockObject    *object,
 
92
                                       GdlDockObject    *requestor,
 
93
                                       GdlDockPlacement  position,
 
94
                                       GValue           *other_data);
 
95
static gboolean gdl_dock_reorder      (GdlDockObject    *object,
 
96
                                       GdlDockObject    *requestor,
 
97
                                       GdlDockPlacement  new_position,
 
98
                                       GValue           *other_data);
 
99
 
 
100
static gboolean gdl_dock_floating_window_delete_event_cb (GtkWidget *widget);
 
101
 
 
102
static gboolean gdl_dock_child_placement  (GdlDockObject    *object,
 
103
                                           GdlDockObject    *child,
 
104
                                           GdlDockPlacement *placement);
 
105
 
 
106
static void     gdl_dock_present          (GdlDockObject    *object,
 
107
                                           GdlDockObject    *child);
 
108
 
 
109
 
 
110
/* ----- Class variables and definitions ----- */
 
111
 
 
112
struct _GdlDockPrivate
 
113
{
 
114
    /* for floating docks */
 
115
    gboolean            floating;
 
116
    GtkWidget          *window;
 
117
    gboolean            auto_title;
 
118
    
 
119
    gint                float_x;
 
120
    gint                float_y;
 
121
    gint                width;
 
122
    gint                height;
 
123
 
 
124
    /* auxiliary fields */
 
125
    GdkGC              *xor_gc;
 
126
};
 
127
 
 
128
enum {
 
129
    LAYOUT_CHANGED,
 
130
    LAST_SIGNAL
 
131
};
 
132
 
 
133
enum {
 
134
    PROP_0,
 
135
    PROP_FLOATING,
 
136
    PROP_DEFAULT_TITLE,
 
137
    PROP_WIDTH,
 
138
    PROP_HEIGHT,
 
139
    PROP_FLOAT_X,
 
140
    PROP_FLOAT_Y
 
141
};
 
142
 
 
143
static guint dock_signals [LAST_SIGNAL] = { 0 };
 
144
 
 
145
#define SPLIT_RATIO  0.3
 
146
 
 
147
 
 
148
/* ----- Private functions ----- */
 
149
 
 
150
GDL_CLASS_BOILERPLATE (GdlDock, gdl_dock, GdlDockObject, GDL_TYPE_DOCK_OBJECT);
 
151
 
 
152
static void
 
153
gdl_dock_class_init (GdlDockClass *klass)
 
154
{
 
155
    GObjectClass       *g_object_class;
 
156
    GtkObjectClass     *gtk_object_class;
 
157
    GtkWidgetClass     *widget_class;
 
158
    GtkContainerClass  *container_class;
 
159
    GdlDockObjectClass *object_class;
 
160
    
 
161
    g_object_class = G_OBJECT_CLASS (klass);
 
162
    gtk_object_class = GTK_OBJECT_CLASS (klass);
 
163
    widget_class = GTK_WIDGET_CLASS (klass);
 
164
    container_class = GTK_CONTAINER_CLASS (klass);
 
165
    object_class = GDL_DOCK_OBJECT_CLASS (klass);
 
166
    
 
167
    g_object_class->constructor = gdl_dock_constructor;
 
168
    g_object_class->set_property = gdl_dock_set_property;
 
169
    g_object_class->get_property = gdl_dock_get_property;
 
170
    
 
171
    /* properties */
 
172
 
 
173
    g_object_class_install_property (
 
174
        g_object_class, PROP_FLOATING,
 
175
        g_param_spec_boolean ("floating", _("Floating"),
 
176
                              _("Whether the dock is floating in its own window"),
 
177
                              FALSE,
 
178
                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
 
179
                              GDL_DOCK_PARAM_EXPORT));
 
180
    
 
181
    g_object_class_install_property (
 
182
        g_object_class, PROP_DEFAULT_TITLE,
 
183
        g_param_spec_string ("default-title", _("Default title"),
 
184
                             _("Default title for the newly created floating docks"),
 
185
                             NULL,
 
186
                             G_PARAM_READWRITE));
 
187
    
 
188
    g_object_class_install_property (
 
189
        g_object_class, PROP_WIDTH,
 
190
        g_param_spec_int ("width", _("Width"),
 
191
                          _("Width for the dock when it's of floating type"),
 
192
                          -1, G_MAXINT, -1,
 
193
                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
 
194
                          GDL_DOCK_PARAM_EXPORT));
 
195
    
 
196
    g_object_class_install_property (
 
197
        g_object_class, PROP_HEIGHT,
 
198
        g_param_spec_int ("height", _("Height"),
 
199
                          _("Height for the dock when it's of floating type"),
 
200
                          -1, G_MAXINT, -1,
 
201
                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
 
202
                          GDL_DOCK_PARAM_EXPORT));
 
203
    
 
204
    g_object_class_install_property (
 
205
        g_object_class, PROP_FLOAT_X,
 
206
        g_param_spec_int ("floatx", _("Float X"),
 
207
                          _("X coordinate for a floating dock"),
 
208
                          G_MININT, G_MAXINT, 0,
 
209
                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
 
210
                          GDL_DOCK_PARAM_EXPORT));
 
211
    
 
212
    g_object_class_install_property (
 
213
        g_object_class, PROP_FLOAT_Y,
 
214
        g_param_spec_int ("floaty", _("Float Y"),
 
215
                          _("Y coordinate for a floating dock"),
 
216
                          G_MININT, G_MAXINT, 0,
 
217
                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
 
218
                          GDL_DOCK_PARAM_EXPORT));
 
219
    
 
220
    gtk_object_class->destroy = gdl_dock_destroy;
 
221
 
 
222
    widget_class->size_request = gdl_dock_size_request;
 
223
    widget_class->size_allocate = gdl_dock_size_allocate;
 
224
    widget_class->map = gdl_dock_map;
 
225
    widget_class->unmap = gdl_dock_unmap;
 
226
    widget_class->show = gdl_dock_show;
 
227
    widget_class->hide = gdl_dock_hide;
 
228
    
 
229
    container_class->add = gdl_dock_add;
 
230
    container_class->remove = gdl_dock_remove;
 
231
    container_class->forall = gdl_dock_forall;
 
232
    container_class->child_type = gdl_dock_child_type;
 
233
    
 
234
    object_class->is_compound = TRUE;
 
235
    
 
236
    object_class->detach = gdl_dock_detach;
 
237
    object_class->reduce = gdl_dock_reduce;
 
238
    object_class->dock_request = gdl_dock_dock_request;
 
239
    object_class->dock = gdl_dock_dock;
 
240
    object_class->reorder = gdl_dock_reorder;    
 
241
    object_class->child_placement = gdl_dock_child_placement;
 
242
    object_class->present = gdl_dock_present;
 
243
    
 
244
    /* signals */
 
245
 
 
246
    dock_signals [LAYOUT_CHANGED] = 
 
247
        g_signal_new ("layout-changed", 
 
248
                      G_TYPE_FROM_CLASS (klass),
 
249
                      G_SIGNAL_RUN_LAST,
 
250
                      G_STRUCT_OFFSET (GdlDockClass, layout_changed),
 
251
                      NULL, /* accumulator */
 
252
                      NULL, /* accu_data */
 
253
                      gdl_marshal_VOID__VOID,
 
254
                      G_TYPE_NONE, /* return type */
 
255
                      0);
 
256
 
 
257
    klass->layout_changed = NULL;
 
258
}
 
259
 
 
260
static void
 
261
gdl_dock_instance_init (GdlDock *dock)
 
262
{
 
263
    GTK_WIDGET_SET_FLAGS (GTK_WIDGET (dock), GTK_NO_WINDOW);
 
264
 
 
265
    dock->root = NULL;
 
266
    dock->_priv = g_new0 (GdlDockPrivate, 1);
 
267
    dock->_priv->width = -1;
 
268
    dock->_priv->height = -1;
 
269
}
 
270
 
 
271
static gboolean 
 
272
gdl_dock_floating_configure_event_cb (GtkWidget         *widget,
 
273
                                      GdkEventConfigure *event,
 
274
                                      gpointer           user_data)
 
275
{
 
276
    GdlDock *dock;
 
277
 
 
278
    g_return_val_if_fail (user_data != NULL && GDL_IS_DOCK (user_data), TRUE);
 
279
 
 
280
    dock = GDL_DOCK (user_data);
 
281
    dock->_priv->float_x = event->x;
 
282
    dock->_priv->float_y = event->y;
 
283
    dock->_priv->width = event->width;
 
284
    dock->_priv->height = event->height;
 
285
 
 
286
    return FALSE;
 
287
}
 
288
 
 
289
static GObject *
 
290
gdl_dock_constructor (GType                  type,
 
291
                      guint                  n_construct_properties,
 
292
                      GObjectConstructParam *construct_param)
 
293
{
 
294
    GObject *g_object;
 
295
    
 
296
    g_object = GDL_CALL_PARENT_WITH_DEFAULT (G_OBJECT_CLASS, 
 
297
                                               constructor, 
 
298
                                               (type,
 
299
                                                n_construct_properties,
 
300
                                                construct_param),
 
301
                                               NULL);
 
302
    if (g_object) {
 
303
        GdlDock *dock = GDL_DOCK (g_object);
 
304
        GdlDockMaster *master;
 
305
        
 
306
        /* create a master for the dock if none was provided in the construction */
 
307
        master = GDL_DOCK_OBJECT_GET_MASTER (GDL_DOCK_OBJECT (dock));
 
308
        if (!master) {
 
309
            GDL_DOCK_OBJECT_UNSET_FLAGS (dock, GDL_DOCK_AUTOMATIC);
 
310
            master = g_object_new (GDL_TYPE_DOCK_MASTER, NULL);
 
311
            /* the controller owns the master ref */
 
312
            gdl_dock_object_bind (GDL_DOCK_OBJECT (dock), G_OBJECT (master));
 
313
        }
 
314
 
 
315
        if (dock->_priv->floating) {
 
316
            GdlDockObject *controller;
 
317
            
 
318
            /* create floating window for this dock */
 
319
            dock->_priv->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 
320
            g_object_set_data (G_OBJECT (dock->_priv->window), "dock", dock);
 
321
            
 
322
            /* set position and default size */
 
323
            gtk_window_set_position (GTK_WINDOW (dock->_priv->window),
 
324
                                     GTK_WIN_POS_MOUSE);
 
325
            gtk_window_set_default_size (GTK_WINDOW (dock->_priv->window),
 
326
                                         dock->_priv->width,
 
327
                                         dock->_priv->height);
 
328
            gtk_window_set_type_hint (GTK_WINDOW (dock->_priv->window),
 
329
                                      GDK_WINDOW_TYPE_HINT_NORMAL);
 
330
            
 
331
            gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dock->_priv->window), 
 
332
                                              TRUE);
 
333
 
 
334
            /* metacity ignores this */
 
335
            gtk_window_move (GTK_WINDOW (dock->_priv->window),
 
336
                             dock->_priv->float_x,
 
337
                             dock->_priv->float_y);
 
338
            
 
339
            /* connect to the configure event so we can track down window geometry */
 
340
            g_signal_connect (dock->_priv->window, "configure_event",
 
341
                              (GCallback) gdl_dock_floating_configure_event_cb,
 
342
                              dock);
 
343
            
 
344
            /* set the title and connect to the long_name notify queue
 
345
               so we can reset the title when this prop changes */
 
346
            gdl_dock_set_title (dock);
 
347
            g_signal_connect (dock, "notify::long-name",
 
348
                              (GCallback) gdl_dock_notify_cb, NULL);
 
349
            
 
350
            /* set transient for the first dock if that is a non-floating dock */
 
351
            controller = gdl_dock_master_get_controller (master);
 
352
            if (controller && GDL_IS_DOCK (controller)) {
 
353
                gboolean first_is_floating;
 
354
                g_object_get (controller, "floating", &first_is_floating, NULL);
 
355
                if (!first_is_floating) {
 
356
                    GtkWidget *toplevel =
 
357
                        gtk_widget_get_toplevel (GTK_WIDGET (controller));
 
358
 
 
359
                    if (GTK_IS_WINDOW (toplevel))
 
360
                        gtk_window_set_transient_for (GTK_WINDOW (dock->_priv->window),
 
361
                                                      GTK_WINDOW (toplevel));
 
362
                }
 
363
            }
 
364
 
 
365
            gtk_container_add (GTK_CONTAINER (dock->_priv->window), GTK_WIDGET (dock));
 
366
    
 
367
            g_signal_connect (dock->_priv->window, "delete_event",
 
368
                              G_CALLBACK (gdl_dock_floating_window_delete_event_cb), 
 
369
                              NULL);
 
370
        }
 
371
        GDL_DOCK_OBJECT_SET_FLAGS (dock, GDL_DOCK_ATTACHED);
 
372
    }
 
373
    
 
374
    return g_object;
 
375
}
 
376
 
 
377
static void
 
378
gdl_dock_set_property  (GObject      *object,
 
379
                        guint         prop_id,
 
380
                        const GValue *value,
 
381
                        GParamSpec   *pspec)
 
382
{
 
383
    GdlDock *dock = GDL_DOCK (object);
 
384
    
 
385
    switch (prop_id) {
 
386
        case PROP_FLOATING:
 
387
            dock->_priv->floating = g_value_get_boolean (value);
 
388
            break;
 
389
        case PROP_DEFAULT_TITLE:
 
390
            if (GDL_DOCK_OBJECT (object)->master)
 
391
                g_object_set (GDL_DOCK_OBJECT (object)->master,
 
392
                              "default-title", g_value_get_string (value),
 
393
                              NULL);
 
394
            break;
 
395
        case PROP_WIDTH:
 
396
            dock->_priv->width = g_value_get_int (value);
 
397
            break;
 
398
        case PROP_HEIGHT:
 
399
            dock->_priv->height = g_value_get_int (value);
 
400
            break;
 
401
        case PROP_FLOAT_X:
 
402
            dock->_priv->float_x = g_value_get_int (value);
 
403
            break;
 
404
        case PROP_FLOAT_Y:
 
405
            dock->_priv->float_y = g_value_get_int (value);
 
406
            break;
 
407
        default:
 
408
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
409
            break;
 
410
    }
 
411
 
 
412
    switch (prop_id) {
 
413
        case PROP_WIDTH:
 
414
        case PROP_HEIGHT:
 
415
        case PROP_FLOAT_X:
 
416
        case PROP_FLOAT_Y:
 
417
            if (dock->_priv->floating && dock->_priv->window) {
 
418
                gtk_window_resize (GTK_WINDOW (dock->_priv->window),
 
419
                                   dock->_priv->width,
 
420
                                   dock->_priv->height);
 
421
            }
 
422
            break;
 
423
    }
 
424
}
 
425
 
 
426
static void
 
427
gdl_dock_get_property  (GObject      *object,
 
428
                        guint         prop_id,
 
429
                        GValue       *value,
 
430
                        GParamSpec   *pspec)
 
431
{
 
432
    GdlDock *dock = GDL_DOCK (object);
 
433
 
 
434
    switch (prop_id) {
 
435
        case PROP_FLOATING:
 
436
            g_value_set_boolean (value, dock->_priv->floating);
 
437
            break;
 
438
        case PROP_DEFAULT_TITLE:
 
439
            if (GDL_DOCK_OBJECT (object)->master) {
 
440
                gchar *default_title;
 
441
                g_object_get (GDL_DOCK_OBJECT (object)->master,
 
442
                              "default-title", &default_title,
 
443
                              NULL);
 
444
#if GLIB_CHECK_VERSION(2,3,0)
 
445
                g_value_take_string (value, default_title);
 
446
#else
 
447
                g_value_set_string_take_ownership (value, default_title);
 
448
#endif
 
449
            }
 
450
            else
 
451
                g_value_set_string (value, NULL);
 
452
            break;
 
453
        case PROP_WIDTH:
 
454
            g_value_set_int (value, dock->_priv->width);
 
455
            break;
 
456
        case PROP_HEIGHT:
 
457
            g_value_set_int (value, dock->_priv->height);
 
458
            break;
 
459
        case PROP_FLOAT_X:
 
460
            g_value_set_int (value, dock->_priv->float_x);
 
461
            break;
 
462
        case PROP_FLOAT_Y:
 
463
            g_value_set_int (value, dock->_priv->float_y);
 
464
            break;
 
465
        default:
 
466
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
467
            break;
 
468
    }
 
469
}
 
470
 
 
471
static void
 
472
gdl_dock_set_title (GdlDock *dock)
 
473
{
 
474
    GdlDockObject *object = GDL_DOCK_OBJECT (dock);
 
475
    gchar         *title = NULL;
 
476
    gboolean       free_title = FALSE;
 
477
    
 
478
    if (!dock->_priv->window)
 
479
        return;
 
480
    
 
481
    if (!dock->_priv->auto_title && object->long_name) {
 
482
        title = object->long_name;
 
483
    }
 
484
    else if (object->master) {
 
485
        g_object_get (object->master, "default-title", &title, NULL);
 
486
        free_title = TRUE;
 
487
    }
 
488
 
 
489
    if (!title && dock->root) {
 
490
        g_object_get (dock->root, "long-name", &title, NULL);
 
491
        free_title = TRUE;
 
492
    }
 
493
    
 
494
    if (!title) {
 
495
        /* set a default title in the long_name */
 
496
        dock->_priv->auto_title = TRUE;
 
497
        free_title = FALSE;
 
498
        title = object->long_name = g_strdup_printf (
 
499
            _("Dock #%d"), GDL_DOCK_MASTER (object->master)->dock_number++);
 
500
    }
 
501
 
 
502
    gtk_window_set_title (GTK_WINDOW (dock->_priv->window), title);
 
503
    if (free_title)
 
504
        g_free (title);
 
505
}
 
506
 
 
507
static void
 
508
gdl_dock_notify_cb (GObject    *object,
 
509
                    GParamSpec *pspec,
 
510
                    gpointer    user_data)
 
511
{
 
512
    GdlDock *dock;
 
513
    
 
514
    g_return_if_fail (object != NULL || GDL_IS_DOCK (object));
 
515
    
 
516
    dock = GDL_DOCK (object);
 
517
    dock->_priv->auto_title = FALSE;
 
518
    gdl_dock_set_title (dock);
 
519
}
 
520
 
 
521
static void
 
522
gdl_dock_destroy (GtkObject *object)
 
523
{
 
524
    GdlDock *dock = GDL_DOCK (object);
 
525
 
 
526
    if (dock->_priv) {
 
527
        GdlDockPrivate *priv = dock->_priv;
 
528
        dock->_priv = NULL;
 
529
 
 
530
        if (priv->window) {
 
531
            gtk_widget_destroy (priv->window);
 
532
            priv->floating = FALSE;
 
533
            priv->window = NULL;
 
534
        }
 
535
        
 
536
        /* destroy the xor gc */
 
537
        if (priv->xor_gc) {
 
538
            g_object_unref (priv->xor_gc);
 
539
            priv->xor_gc = NULL;
 
540
        }
 
541
 
 
542
        g_free (priv);
 
543
    }
 
544
    
 
545
    GDL_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
 
546
}
 
547
 
 
548
static void
 
549
gdl_dock_size_request (GtkWidget      *widget,
 
550
                       GtkRequisition *requisition)
 
551
{
 
552
    GdlDock       *dock;
 
553
    GtkContainer  *container;
 
554
    guint          border_width;
 
555
 
 
556
    g_return_if_fail (widget != NULL);
 
557
    g_return_if_fail (GDL_IS_DOCK (widget));
 
558
 
 
559
    dock = GDL_DOCK (widget);
 
560
    container = GTK_CONTAINER (widget);
 
561
    border_width = container->border_width;
 
562
 
 
563
    /* make request to root */
 
564
    if (dock->root && GTK_WIDGET_VISIBLE (dock->root))
 
565
        gtk_widget_size_request (GTK_WIDGET (dock->root), requisition);
 
566
    else {
 
567
        requisition->width = 0;
 
568
        requisition->height = 0;
 
569
    };
 
570
 
 
571
    requisition->width += 2 * border_width;
 
572
    requisition->height += 2 * border_width;
 
573
 
 
574
    widget->requisition = *requisition;
 
575
}
 
576
 
 
577
static void
 
578
gdl_dock_size_allocate (GtkWidget     *widget,
 
579
                        GtkAllocation *allocation)
 
580
{
 
581
    GdlDock       *dock;
 
582
    GtkContainer  *container;
 
583
    guint          border_width;
 
584
 
 
585
    g_return_if_fail (widget != NULL);
 
586
    g_return_if_fail (GDL_IS_DOCK (widget));
 
587
    
 
588
    dock = GDL_DOCK (widget);
 
589
    container = GTK_CONTAINER (widget);
 
590
    border_width = container->border_width;
 
591
 
 
592
    widget->allocation = *allocation;
 
593
 
 
594
    /* reduce allocation by border width */
 
595
    allocation->x += border_width;
 
596
    allocation->y += border_width;
 
597
    allocation->width = MAX (1, allocation->width - 2 * border_width);
 
598
    allocation->height = MAX (1, allocation->height - 2 * border_width);
 
599
 
 
600
    if (dock->root && GTK_WIDGET_VISIBLE (dock->root))
 
601
        gtk_widget_size_allocate (GTK_WIDGET (dock->root), allocation);
 
602
}
 
603
 
 
604
static void
 
605
gdl_dock_map (GtkWidget *widget)
 
606
{
 
607
    GtkWidget *child;
 
608
    GdlDock   *dock;
 
609
 
 
610
    g_return_if_fail (widget != NULL);
 
611
    g_return_if_fail (GDL_IS_DOCK (widget));
 
612
 
 
613
    dock = GDL_DOCK (widget);
 
614
 
 
615
    GDL_CALL_PARENT (GTK_WIDGET_CLASS, map, (widget));
 
616
 
 
617
    if (dock->root) {
 
618
        child = GTK_WIDGET (dock->root);
 
619
        if (GTK_WIDGET_VISIBLE (child) && !GTK_WIDGET_MAPPED (child))
 
620
            gtk_widget_map (child);
 
621
    }
 
622
}
 
623
 
 
624
static void
 
625
gdl_dock_unmap (GtkWidget *widget)
 
626
{
 
627
    GtkWidget *child;
 
628
    GdlDock   *dock;
 
629
    
 
630
    g_return_if_fail (widget != NULL);
 
631
    g_return_if_fail (GDL_IS_DOCK (widget));
 
632
 
 
633
    dock = GDL_DOCK (widget);
 
634
 
 
635
    GDL_CALL_PARENT (GTK_WIDGET_CLASS, unmap, (widget));
 
636
 
 
637
    if (dock->root) {
 
638
        child = GTK_WIDGET (dock->root);
 
639
        if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_MAPPED (child))
 
640
            gtk_widget_unmap (child);
 
641
    }
 
642
    
 
643
    if (dock->_priv->window)
 
644
        gtk_widget_unmap (dock->_priv->window);
 
645
}
 
646
 
 
647
static void
 
648
gdl_dock_foreach_automatic (GdlDockObject *object,
 
649
                            gpointer       user_data)
 
650
{
 
651
    void (* function) (GtkWidget *) = user_data;
 
652
 
 
653
    if (GDL_DOCK_OBJECT_AUTOMATIC (object))
 
654
        (* function) (GTK_WIDGET (object));
 
655
}
 
656
 
 
657
static void
 
658
gdl_dock_show (GtkWidget *widget)
 
659
{
 
660
    GdlDock *dock;
 
661
    
 
662
    g_return_if_fail (widget != NULL);
 
663
    g_return_if_fail (GDL_IS_DOCK (widget));
 
664
    
 
665
    GDL_CALL_PARENT (GTK_WIDGET_CLASS, show, (widget));
 
666
    
 
667
    dock = GDL_DOCK (widget);
 
668
    if (dock->_priv->floating && dock->_priv->window)
 
669
        gtk_widget_show (dock->_priv->window);
 
670
 
 
671
    if (GDL_DOCK_IS_CONTROLLER (dock)) {
 
672
        gdl_dock_master_foreach_toplevel (GDL_DOCK_OBJECT_GET_MASTER (dock),
 
673
                                          FALSE, (GFunc) gdl_dock_foreach_automatic,
 
674
                                          gtk_widget_show);
 
675
    }
 
676
}
 
677
 
 
678
static void
 
679
gdl_dock_hide (GtkWidget *widget)
 
680
{
 
681
    GdlDock *dock;
 
682
    
 
683
    g_return_if_fail (widget != NULL);
 
684
    g_return_if_fail (GDL_IS_DOCK (widget));
 
685
    
 
686
    GDL_CALL_PARENT (GTK_WIDGET_CLASS, hide, (widget));
 
687
    
 
688
    dock = GDL_DOCK (widget);
 
689
    if (dock->_priv->floating && dock->_priv->window)
 
690
        gtk_widget_hide (dock->_priv->window);
 
691
 
 
692
    if (GDL_DOCK_IS_CONTROLLER (dock)) {
 
693
        gdl_dock_master_foreach_toplevel (GDL_DOCK_OBJECT_GET_MASTER (dock),
 
694
                                          FALSE, (GFunc) gdl_dock_foreach_automatic,
 
695
                                          gtk_widget_hide);
 
696
    }
 
697
}
 
698
 
 
699
static void
 
700
gdl_dock_add (GtkContainer *container,
 
701
              GtkWidget    *widget)
 
702
{
 
703
    g_return_if_fail (container != NULL);
 
704
    g_return_if_fail (GDL_IS_DOCK (container));
 
705
    g_return_if_fail (GDL_IS_DOCK_ITEM (widget));
 
706
 
 
707
    gdl_dock_add_item (GDL_DOCK (container), 
 
708
                       GDL_DOCK_ITEM (widget), 
 
709
                       GDL_DOCK_TOP);  /* default position */
 
710
}
 
711
 
 
712
static void
 
713
gdl_dock_remove (GtkContainer *container,
 
714
                 GtkWidget    *widget)
 
715
{
 
716
    GdlDock  *dock;
 
717
    gboolean  was_visible;
 
718
 
 
719
    g_return_if_fail (container != NULL);
 
720
    g_return_if_fail (widget != NULL);
 
721
 
 
722
    dock = GDL_DOCK (container);
 
723
    was_visible = GTK_WIDGET_VISIBLE (widget);
 
724
 
 
725
    if (GTK_WIDGET (dock->root) == widget) {
 
726
        dock->root = NULL;
 
727
        GDL_DOCK_OBJECT_UNSET_FLAGS (widget, GDL_DOCK_ATTACHED);
 
728
        gtk_widget_unparent (widget);
 
729
 
 
730
        if (was_visible && GTK_WIDGET_VISIBLE (GTK_WIDGET (container)))
 
731
            gtk_widget_queue_resize (GTK_WIDGET (dock));
 
732
    }
 
733
}
 
734
 
 
735
static void
 
736
gdl_dock_forall (GtkContainer *container,
 
737
                 gboolean      include_internals,
 
738
                 GtkCallback   callback,
 
739
                 gpointer      callback_data)
 
740
{
 
741
    GdlDock *dock;
 
742
 
 
743
    g_return_if_fail (container != NULL);
 
744
    g_return_if_fail (GDL_IS_DOCK (container));
 
745
    g_return_if_fail (callback != NULL);
 
746
 
 
747
    dock = GDL_DOCK (container);
 
748
 
 
749
    if (dock->root)
 
750
        (*callback) (GTK_WIDGET (dock->root), callback_data);
 
751
}
 
752
 
 
753
static GtkType
 
754
gdl_dock_child_type (GtkContainer *container)
 
755
{
 
756
    return GDL_TYPE_DOCK_ITEM;
 
757
}
 
758
 
 
759
static void
 
760
gdl_dock_detach (GdlDockObject *object,
 
761
                 gboolean       recursive)
 
762
{
 
763
    GdlDock *dock = GDL_DOCK (object);
 
764
    
 
765
    /* detach children */
 
766
    if (recursive && dock->root) {
 
767
        gdl_dock_object_detach (dock->root, recursive);
 
768
    }
 
769
    GDL_DOCK_OBJECT_UNSET_FLAGS (object, GDL_DOCK_ATTACHED);
 
770
}
 
771
 
 
772
static void
 
773
gdl_dock_reduce (GdlDockObject *object)
 
774
{
 
775
    GdlDock *dock = GDL_DOCK (object);
 
776
    
 
777
    if (dock->root)
 
778
        return;
 
779
    
 
780
    if (GDL_DOCK_OBJECT_AUTOMATIC (dock)) {
 
781
        gtk_widget_destroy (GTK_WIDGET (dock));
 
782
 
 
783
    } else if (!GDL_DOCK_OBJECT_ATTACHED (dock)) {
 
784
        /* if the user explicitly detached the object */
 
785
        if (dock->_priv->floating)
 
786
            gtk_widget_hide (GTK_WIDGET (dock));
 
787
        else {
 
788
            GtkWidget *widget = GTK_WIDGET (object);
 
789
            if (widget->parent) 
 
790
                gtk_container_remove (GTK_CONTAINER (widget->parent), widget);
 
791
        }
 
792
    }
 
793
}
 
794
 
 
795
static gboolean
 
796
gdl_dock_dock_request (GdlDockObject  *object,
 
797
                       gint            x,
 
798
                       gint            y,
 
799
                       GdlDockRequest *request)
 
800
{
 
801
    GdlDock            *dock;
 
802
    guint               bw;
 
803
    gint                rel_x, rel_y;
 
804
    GtkAllocation      *alloc;
 
805
    gboolean            may_dock = FALSE;
 
806
    GdlDockRequest      my_request;
 
807
 
 
808
    g_return_val_if_fail (GDL_IS_DOCK (object), FALSE);
 
809
 
 
810
    /* we get (x,y) in our allocation coordinates system */
 
811
    
 
812
    dock = GDL_DOCK (object);
 
813
    
 
814
    /* Get dock size. */
 
815
    alloc = &(GTK_WIDGET (dock)->allocation);
 
816
    bw = GTK_CONTAINER (dock)->border_width;
 
817
 
 
818
    /* Get coordinates relative to our allocation area. */
 
819
    rel_x = x - alloc->x;
 
820
    rel_y = y - alloc->y;
 
821
 
 
822
    if (request)
 
823
        my_request = *request;
 
824
        
 
825
    /* Check if coordinates are in GdlDock widget. */
 
826
    if (rel_x > 0 && rel_x < alloc->width &&
 
827
        rel_y > 0 && rel_y < alloc->height) {
 
828
 
 
829
        /* It's inside our area. */
 
830
        may_dock = TRUE;
 
831
 
 
832
        /* Set docking indicator rectangle to the GdlDock size. */
 
833
        my_request.rect.x = alloc->x + bw;
 
834
        my_request.rect.y = alloc->y + bw;
 
835
        my_request.rect.width = alloc->width - 2*bw;
 
836
        my_request.rect.height = alloc->height - 2*bw;
 
837
 
 
838
        /* If GdlDock has no root item yet, set the dock itself as 
 
839
           possible target. */
 
840
        if (!dock->root) {
 
841
            my_request.position = GDL_DOCK_TOP;
 
842
            my_request.target = object;
 
843
        } else {
 
844
            my_request.target = dock->root;
 
845
 
 
846
            /* See if it's in the border_width band. */
 
847
            if (rel_x < bw) {
 
848
                my_request.position = GDL_DOCK_LEFT;
 
849
                my_request.rect.width *= SPLIT_RATIO;
 
850
            } else if (rel_x > alloc->width - bw) {
 
851
                my_request.position = GDL_DOCK_RIGHT;
 
852
                my_request.rect.x += my_request.rect.width * (1 - SPLIT_RATIO);
 
853
                my_request.rect.width *= SPLIT_RATIO;
 
854
            } else if (rel_y < bw) {
 
855
                my_request.position = GDL_DOCK_TOP;
 
856
                my_request.rect.height *= SPLIT_RATIO;
 
857
            } else if (rel_y > alloc->height - bw) {
 
858
                my_request.position = GDL_DOCK_BOTTOM;
 
859
                my_request.rect.y += my_request.rect.height * (1 - SPLIT_RATIO);
 
860
                my_request.rect.height *= SPLIT_RATIO;
 
861
            } else {
 
862
                /* Otherwise try our children. */
 
863
                /* give them allocation coordinates (we are a
 
864
                   GTK_NO_WINDOW) widget */
 
865
                may_dock = gdl_dock_object_dock_request (GDL_DOCK_OBJECT (dock->root), 
 
866
                                                         x, y, &my_request);
 
867
            }
 
868
        }
 
869
    }
 
870
 
 
871
    if (may_dock && request)
 
872
        *request = my_request;
 
873
    
 
874
    return may_dock;
 
875
}
 
876
 
 
877
static void
 
878
gdl_dock_dock (GdlDockObject    *object,
 
879
               GdlDockObject    *requestor,
 
880
               GdlDockPlacement  position,
 
881
               GValue           *user_data)
 
882
{
 
883
    GdlDock *dock;
 
884
    
 
885
    g_return_if_fail (GDL_IS_DOCK (object));
 
886
    /* only dock items allowed at this time */
 
887
    g_return_if_fail (GDL_IS_DOCK_ITEM (requestor));
 
888
 
 
889
    dock = GDL_DOCK (object);
 
890
    
 
891
    if (position == GDL_DOCK_FLOATING) {
 
892
        GdlDockItem *item = GDL_DOCK_ITEM (requestor);
 
893
        gint x, y, width, height;
 
894
 
 
895
        if (user_data && G_VALUE_HOLDS (user_data, GDK_TYPE_RECTANGLE)) {
 
896
            GdkRectangle *rect;
 
897
 
 
898
            rect = g_value_get_boxed (user_data);
 
899
            x = rect->x;
 
900
            y = rect->y;
 
901
            width = rect->width;
 
902
            height = rect->height;
 
903
        }
 
904
        else {
 
905
            x = y = 0;
 
906
            width = height = -1;
 
907
        }
 
908
        
 
909
        gdl_dock_add_floating_item (dock, item,
 
910
                                    x, y, width, height);
 
911
    }
 
912
    else if (dock->root) {
 
913
        /* This is somewhat a special case since we know which item to
 
914
           pass the request on because we only have on child */
 
915
        gdl_dock_object_dock (dock->root, requestor, position, NULL);
 
916
        gdl_dock_set_title (dock);
 
917
        
 
918
    }
 
919
    else { /* Item about to be added is root item. */
 
920
        GtkWidget *widget = GTK_WIDGET (requestor);
 
921
        
 
922
        dock->root = requestor;
 
923
        GDL_DOCK_OBJECT_SET_FLAGS (requestor, GDL_DOCK_ATTACHED);
 
924
        gtk_widget_set_parent (widget, GTK_WIDGET (dock));
 
925
        
 
926
        gdl_dock_item_show_grip (GDL_DOCK_ITEM (requestor));
 
927
 
 
928
        /* Realize the item (create its corresponding GdkWindow) when 
 
929
           GdlDock has been realized. */
 
930
        if (GTK_WIDGET_REALIZED (dock))
 
931
            gtk_widget_realize (widget);
 
932
        
 
933
        /* Map the widget if it's visible and the parent is visible and has 
 
934
           been mapped. This is done to make sure that the GdkWindow is 
 
935
           visible. */
 
936
        if (GTK_WIDGET_VISIBLE (dock) && 
 
937
            GTK_WIDGET_VISIBLE (widget)) {
 
938
            if (GTK_WIDGET_MAPPED (dock))
 
939
                gtk_widget_map (widget);
 
940
            
 
941
            /* Make the widget resize. */
 
942
            gtk_widget_queue_resize (widget);
 
943
        }
 
944
        gdl_dock_set_title (dock);
 
945
    }
 
946
}
 
947
    
 
948
static gboolean
 
949
gdl_dock_floating_window_delete_event_cb (GtkWidget *widget)
 
950
{
 
951
    GdlDock *dock;
 
952
    
 
953
    g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
 
954
    
 
955
    dock = GDL_DOCK (g_object_get_data (G_OBJECT (widget), "dock"));
 
956
    if (dock->root) {
 
957
        /* this will call reduce on ourselves, hiding the window if appropiate */
 
958
        gdl_dock_item_hide_item (GDL_DOCK_ITEM (dock->root));
 
959
    }
 
960
 
 
961
    return TRUE;
 
962
}
 
963
 
 
964
static void
 
965
_gdl_dock_foreach_build_list (GdlDockObject *object,
 
966
                              gpointer       user_data)
 
967
{
 
968
    GList **l = (GList **) user_data;
 
969
 
 
970
    if (GDL_IS_DOCK_ITEM (object))
 
971
        *l = g_list_prepend (*l, object);
 
972
}
 
973
 
 
974
static gboolean
 
975
gdl_dock_reorder (GdlDockObject    *object,
 
976
                  GdlDockObject    *requestor,
 
977
                  GdlDockPlacement  new_position,
 
978
                  GValue           *other_data)
 
979
{
 
980
    GdlDock *dock = GDL_DOCK (object);
 
981
    gboolean handled = FALSE;
 
982
    
 
983
    if (dock->_priv->floating &&
 
984
        new_position == GDL_DOCK_FLOATING &&
 
985
        dock->root == requestor) {
 
986
        
 
987
        if (other_data && G_VALUE_HOLDS (other_data, GDK_TYPE_RECTANGLE)) {
 
988
            GdkRectangle *rect;
 
989
 
 
990
            rect = g_value_get_boxed (other_data);
 
991
            gtk_window_move (GTK_WINDOW (dock->_priv->window),
 
992
                             rect->x,
 
993
                             rect->y);
 
994
            handled = TRUE;
 
995
        }
 
996
    }
 
997
    
 
998
    return handled;
 
999
}
 
1000
 
 
1001
static gboolean 
 
1002
gdl_dock_child_placement (GdlDockObject    *object,
 
1003
                          GdlDockObject    *child,
 
1004
                          GdlDockPlacement *placement)
 
1005
{
 
1006
    GdlDock *dock = GDL_DOCK (object);
 
1007
    gboolean retval = TRUE;
 
1008
    
 
1009
    if (dock->root == child) {
 
1010
        if (placement) {
 
1011
            if (*placement == GDL_DOCK_NONE || *placement == GDL_DOCK_FLOATING)
 
1012
                *placement = GDL_DOCK_TOP;
 
1013
        }
 
1014
    } else 
 
1015
        retval = FALSE;
 
1016
 
 
1017
    return retval;
 
1018
}
 
1019
 
 
1020
static void 
 
1021
gdl_dock_present (GdlDockObject *object,
 
1022
                  GdlDockObject *child)
 
1023
{
 
1024
    GdlDock *dock = GDL_DOCK (object);
 
1025
 
 
1026
    if (dock->_priv->floating)
 
1027
        gtk_window_present (GTK_WINDOW (dock->_priv->window));
 
1028
}
 
1029
 
 
1030
 
 
1031
/* ----- Public interface ----- */
 
1032
 
 
1033
GtkWidget *
 
1034
gdl_dock_new (void)
 
1035
{
 
1036
    GObject *dock;
 
1037
 
 
1038
    dock = g_object_new (GDL_TYPE_DOCK, NULL);
 
1039
    GDL_DOCK_OBJECT_UNSET_FLAGS (dock, GDL_DOCK_AUTOMATIC);
 
1040
    
 
1041
    return GTK_WIDGET (dock);
 
1042
}
 
1043
 
 
1044
GtkWidget *
 
1045
gdl_dock_new_from (GdlDock  *original,
 
1046
                   gboolean  floating)
 
1047
{
 
1048
    GObject *new_dock;
 
1049
    
 
1050
    g_return_val_if_fail (original != NULL, NULL);
 
1051
    
 
1052
    new_dock = g_object_new (GDL_TYPE_DOCK, 
 
1053
                             "master", GDL_DOCK_OBJECT_GET_MASTER (original), 
 
1054
                             "floating", floating,
 
1055
                             NULL);
 
1056
    GDL_DOCK_OBJECT_UNSET_FLAGS (new_dock, GDL_DOCK_AUTOMATIC);
 
1057
    
 
1058
    return GTK_WIDGET (new_dock);
 
1059
}
 
1060
 
 
1061
/* Depending on where the dock item (where new item will be docked) locates
 
1062
 * in the dock, we might need to change the docking placement. If the
 
1063
 * item is does not touches the center of dock, the new-item-to-dock would
 
1064
 * require a center dock on this item.
 
1065
 */
 
1066
static GdlDockPlacement
 
1067
gdl_dock_refine_placement (GdlDock *dock, GdlDockItem *dock_item,
 
1068
                           GdlDockPlacement placement)
 
1069
{
 
1070
    GtkRequisition object_size;
 
1071
    
 
1072
    gdl_dock_item_preferred_size (dock_item, &object_size);
 
1073
    g_return_val_if_fail (GTK_WIDGET (dock)->allocation.width > 0, placement);
 
1074
    g_return_val_if_fail (GTK_WIDGET (dock)->allocation.height > 0, placement);
 
1075
    g_return_val_if_fail (object_size.width > 0, placement);
 
1076
    g_return_val_if_fail (object_size.height > 0, placement);
 
1077
 
 
1078
    if (placement == GDL_DOCK_LEFT || placement == GDL_DOCK_RIGHT) {
 
1079
        /* Check if dock_object touches center in terms of width */
 
1080
        if (GTK_WIDGET (dock)->allocation.width/2 > object_size.width) {
 
1081
            return GDL_DOCK_TOP;
 
1082
        }
 
1083
    } 
 
1084
 
 
1085
    return placement;
 
1086
}
 
1087
 
 
1088
/* Determines the larger item of the two based on the placement:
 
1089
 * for left/right placement, height determines it.
 
1090
 * for top/bottom placement, width determines it.
 
1091
 * for center placement, area determines it.
 
1092
 */
 
1093
static GdlDockItem*
 
1094
gdl_dock_select_larger_item (GdlDockItem *dock_item_1,
 
1095
                             GdlDockItem *dock_item_2,
 
1096
                             GdlDockPlacement placement,
 
1097
                             gint level /* for debugging */)
 
1098
{
 
1099
    GtkRequisition size_1, size_2;
 
1100
    
 
1101
    g_return_val_if_fail (dock_item_1 != NULL, dock_item_2);
 
1102
    g_return_val_if_fail (dock_item_2 != NULL, dock_item_1);
 
1103
    
 
1104
    gdl_dock_item_preferred_size (dock_item_1, &size_1);
 
1105
    gdl_dock_item_preferred_size (dock_item_2, &size_2);
 
1106
    
 
1107
    g_return_val_if_fail (size_1.width > 0, dock_item_2);
 
1108
    g_return_val_if_fail (size_1.height > 0, dock_item_2);
 
1109
    g_return_val_if_fail (size_2.width > 0, dock_item_1);
 
1110
    g_return_val_if_fail (size_2.height > 0, dock_item_1);
 
1111
    
 
1112
    if (placement == GDL_DOCK_LEFT || placement == GDL_DOCK_RIGHT)
 
1113
    {
 
1114
        /* For left/right placement, height is what matters */
 
1115
        return (size_1.height >= size_2.height?
 
1116
                    dock_item_1 : dock_item_2);
 
1117
    } else if (placement == GDL_DOCK_TOP || placement == GDL_DOCK_BOTTOM)
 
1118
    {
 
1119
        /* For top/bottom placement, width is what matters */
 
1120
        return (size_1.width >= size_2.width?
 
1121
                    dock_item_1 : dock_item_2);
 
1122
    } else if (placement == GDL_DOCK_CENTER) {
 
1123
        /* For center place, area is what matters */
 
1124
        return ((size_1.width * size_1.height)
 
1125
                    >= (size_2.width * size_2.height)?
 
1126
                    dock_item_1 : dock_item_2);
 
1127
    } else {
 
1128
        g_warning ("Should not reach here: %s:%d", __FUNCTION__, __LINE__);
 
1129
    }
 
1130
    return dock_item_1;
 
1131
}
 
1132
 
 
1133
/* Determines the best dock item to dock a new item with the given placement.
 
1134
 * It traverses the dock tree and (based on the placement) tries to find
 
1135
 * the best located item wrt to the placement. The approach is to find the
 
1136
 * largest item on/around the placement side (for side placements) and to
 
1137
 * find the largest item for center placement. In most situations, this is
 
1138
 * what user wants and the heuristic should be therefore sufficient.
 
1139
 */
 
1140
static GdlDockItem*
 
1141
gdl_dock_find_best_placement_item (GdlDockItem *dock_item,
 
1142
                                   GdlDockPlacement placement,
 
1143
                                   gint level /* for debugging */)
 
1144
{
 
1145
    GdlDockItem *ret_item = NULL;
 
1146
    
 
1147
    if (GDL_IS_DOCK_PANED (dock_item))
 
1148
    {
 
1149
        GtkOrientation orientation;
 
1150
        GdlDockItem *dock_item_1, *dock_item_2;
 
1151
        GList* children;
 
1152
        
 
1153
        children = gtk_container_get_children (GTK_CONTAINER (dock_item));
 
1154
        
 
1155
        g_assert (g_list_length (children) == 2);
 
1156
        
 
1157
        g_object_get (dock_item, "orientation", &orientation, NULL);
 
1158
        if ((orientation == GTK_ORIENTATION_HORIZONTAL &&
 
1159
             placement == GDL_DOCK_LEFT) ||
 
1160
            (orientation == GTK_ORIENTATION_VERTICAL &&
 
1161
             placement == GDL_DOCK_TOP)) {
 
1162
            /* Return left or top pane widget */
 
1163
            ret_item =
 
1164
                gdl_dock_find_best_placement_item (GDL_DOCK_ITEM
 
1165
                                                   (children->data),
 
1166
                                                   placement, level + 1);
 
1167
        } else if ((orientation == GTK_ORIENTATION_HORIZONTAL &&
 
1168
                    placement == GDL_DOCK_RIGHT) ||
 
1169
                   (orientation == GTK_ORIENTATION_VERTICAL &&
 
1170
                    placement == GDL_DOCK_BOTTOM)) {
 
1171
                        /* Return right or top pane widget */
 
1172
            ret_item =
 
1173
                gdl_dock_find_best_placement_item (GDL_DOCK_ITEM
 
1174
                                                   (children->next->data),
 
1175
                                                   placement, level + 1);
 
1176
        } else {
 
1177
            /* Evaluate which of the two sides is bigger */
 
1178
            dock_item_1 =
 
1179
                gdl_dock_find_best_placement_item (GDL_DOCK_ITEM
 
1180
                                                   (children->data),
 
1181
                                                   placement, level + 1);
 
1182
            dock_item_2 =
 
1183
                gdl_dock_find_best_placement_item (GDL_DOCK_ITEM
 
1184
                                                   (children->next->data),
 
1185
                                                   placement, level + 1);
 
1186
            ret_item = gdl_dock_select_larger_item (dock_item_1,
 
1187
                                                    dock_item_2,
 
1188
                                                    placement, level);
 
1189
        }
 
1190
        g_list_free (children);
 
1191
    }
 
1192
    else if (GDL_IS_DOCK_ITEM (dock_item))
 
1193
    {
 
1194
        ret_item = dock_item;
 
1195
    }
 
1196
    else
 
1197
    {
 
1198
        /* should not be here */
 
1199
        g_warning ("Should not reach here: %s:%d", __FUNCTION__, __LINE__);
 
1200
    }
 
1201
    return ret_item;
 
1202
}
 
1203
 
 
1204
void
 
1205
gdl_dock_add_item (GdlDock          *dock,
 
1206
                   GdlDockItem      *item,
 
1207
                   GdlDockPlacement  placement)
 
1208
{
 
1209
    g_return_if_fail (dock != NULL);
 
1210
    g_return_if_fail (item != NULL);
 
1211
 
 
1212
    if (placement == GDL_DOCK_FLOATING)
 
1213
        /* Add the item to a new floating dock */
 
1214
        gdl_dock_add_floating_item (dock, item, 0, 0, -1, -1);
 
1215
 
 
1216
    else {
 
1217
        GdlDockItem *best_dock_item;
 
1218
        /* Non-floating item. */
 
1219
        if (dock->root) {
 
1220
            GdlDockPlacement local_placement;
 
1221
            GtkRequisition preferred_size;
 
1222
            
 
1223
            best_dock_item =
 
1224
                gdl_dock_find_best_placement_item (GDL_DOCK_ITEM (dock->root),
 
1225
                                                   placement, 0);
 
1226
            local_placement = gdl_dock_refine_placement (dock, best_dock_item,
 
1227
                                                         placement);
 
1228
            gdl_dock_object_dock (GDL_DOCK_OBJECT (best_dock_item),
 
1229
                                  GDL_DOCK_OBJECT (item),
 
1230
                                  local_placement, NULL);
 
1231
        } else {
 
1232
            gdl_dock_object_dock (GDL_DOCK_OBJECT (dock),
 
1233
                                  GDL_DOCK_OBJECT (item),
 
1234
                                  placement, NULL);
 
1235
        }
 
1236
    }
 
1237
}
 
1238
 
 
1239
void
 
1240
gdl_dock_add_floating_item (GdlDock        *dock,
 
1241
                            GdlDockItem    *item,
 
1242
                            gint            x,
 
1243
                            gint            y,
 
1244
                            gint            width,
 
1245
                            gint            height)
 
1246
{
 
1247
    GdlDock *new_dock;
 
1248
    
 
1249
    g_return_if_fail (dock != NULL);
 
1250
    g_return_if_fail (item != NULL);
 
1251
    
 
1252
    new_dock = GDL_DOCK (g_object_new (GDL_TYPE_DOCK, 
 
1253
                                       "master", GDL_DOCK_OBJECT_GET_MASTER (dock), 
 
1254
                                       "floating", TRUE,
 
1255
                                       "width", width,
 
1256
                                       "height", height,
 
1257
                                       "floatx", x,
 
1258
                                       "floaty", y,
 
1259
                                       NULL));
 
1260
    
 
1261
    if (GTK_WIDGET_VISIBLE (dock)) {
 
1262
        gtk_widget_show (GTK_WIDGET (new_dock));
 
1263
        if (GTK_WIDGET_MAPPED (dock))
 
1264
            gtk_widget_map (GTK_WIDGET (new_dock));
 
1265
        
 
1266
        /* Make the widget resize. */
 
1267
        gtk_widget_queue_resize (GTK_WIDGET (new_dock));
 
1268
    }
 
1269
 
 
1270
    gdl_dock_add_item (GDL_DOCK (new_dock), item, GDL_DOCK_TOP);
 
1271
}
 
1272
 
 
1273
GdlDockItem *
 
1274
gdl_dock_get_item_by_name (GdlDock     *dock,
 
1275
                           const gchar *name)
 
1276
{
 
1277
    GdlDockObject *found;
 
1278
    
 
1279
    g_return_val_if_fail (dock != NULL && name != NULL, NULL);
 
1280
    
 
1281
    /* proxy the call to our master */
 
1282
    found = gdl_dock_master_get_object (GDL_DOCK_OBJECT_GET_MASTER (dock), name);
 
1283
 
 
1284
    return (found && GDL_IS_DOCK_ITEM (found)) ? GDL_DOCK_ITEM (found) : NULL;
 
1285
}
 
1286
 
 
1287
GdlDockPlaceholder *
 
1288
gdl_dock_get_placeholder_by_name (GdlDock     *dock,
 
1289
                                  const gchar *name)
 
1290
{
 
1291
    GdlDockObject *found;
 
1292
    
 
1293
    g_return_val_if_fail (dock != NULL && name != NULL, NULL);
 
1294
    
 
1295
    /* proxy the call to our master */
 
1296
    found = gdl_dock_master_get_object (GDL_DOCK_OBJECT_GET_MASTER (dock), name);
 
1297
 
 
1298
    return (found && GDL_IS_DOCK_PLACEHOLDER (found)) ?
 
1299
        GDL_DOCK_PLACEHOLDER (found) : NULL;
 
1300
}
 
1301
 
 
1302
GList *
 
1303
gdl_dock_get_named_items (GdlDock *dock)
 
1304
{
 
1305
    GList *list = NULL;
 
1306
    
 
1307
    g_return_val_if_fail (dock != NULL, NULL);
 
1308
 
 
1309
    gdl_dock_master_foreach (GDL_DOCK_OBJECT_GET_MASTER (dock),
 
1310
                             (GFunc) _gdl_dock_foreach_build_list, &list);
 
1311
 
 
1312
    return list;
 
1313
}
 
1314
 
 
1315
GdlDock *
 
1316
gdl_dock_object_get_toplevel (GdlDockObject *object)
 
1317
{
 
1318
    GdlDockObject *parent = object;
 
1319
    
 
1320
    g_return_val_if_fail (object != NULL, NULL);
 
1321
 
 
1322
    while (parent && !GDL_IS_DOCK (parent))
 
1323
        parent = gdl_dock_object_get_parent_object (parent);
 
1324
 
 
1325
    return parent ? GDL_DOCK (parent) : NULL;
 
1326
}
 
1327
 
 
1328
void
 
1329
gdl_dock_xor_rect (GdlDock      *dock,
 
1330
                   GdkRectangle *rect)
 
1331
{
 
1332
    GtkWidget *widget;
 
1333
    gint8      dash_list [2];
 
1334
 
 
1335
    widget = GTK_WIDGET (dock);
 
1336
 
 
1337
    if (!dock->_priv->xor_gc) {
 
1338
        if (GTK_WIDGET_REALIZED (widget)) {
 
1339
            GdkGCValues values;
 
1340
 
 
1341
            values.function = GDK_INVERT;
 
1342
            values.subwindow_mode = GDK_INCLUDE_INFERIORS;
 
1343
            dock->_priv->xor_gc = gdk_gc_new_with_values 
 
1344
                (widget->window, &values, GDK_GC_FUNCTION | GDK_GC_SUBWINDOW);
 
1345
        } else 
 
1346
            return;
 
1347
    };
 
1348
 
 
1349
    gdk_gc_set_line_attributes (dock->_priv->xor_gc, 1,
 
1350
                                GDK_LINE_ON_OFF_DASH,
 
1351
                                GDK_CAP_NOT_LAST,
 
1352
                                GDK_JOIN_BEVEL);
 
1353
    
 
1354
    dash_list [0] = 1;
 
1355
    dash_list [1] = 1;
 
1356
    
 
1357
    gdk_gc_set_dashes (dock->_priv->xor_gc, 1, dash_list, 2);
 
1358
 
 
1359
    gdk_draw_rectangle (widget->window, dock->_priv->xor_gc, 0, 
 
1360
                        rect->x, rect->y,
 
1361
                        rect->width, rect->height);
 
1362
 
 
1363
    gdk_gc_set_dashes (dock->_priv->xor_gc, 0, dash_list, 2);
 
1364
 
 
1365
    gdk_draw_rectangle (widget->window, dock->_priv->xor_gc, 0, 
 
1366
                        rect->x + 1, rect->y + 1,
 
1367
                        rect->width - 2, rect->height - 2);
 
1368
}