~centralelyon2010/inkscape/imagelinks2

« back to all changes in this revision

Viewing changes to src/libgdl/gdl-dock-placeholder.c

  • Committer: gustav_b
  • Date: 2007-08-29 21:27:07 UTC
  • Revision ID: gustav_b@users.sourceforge.net-20070829212707-xvg87a2oqejqioxv
Dockable dialogs patch applied 
(https://sourceforge.net/tracker/?func=detail&atid=604308&aid=1688508&group_id=93438)

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-placeholder.c - Placeholders for docking items
 
4
 *
 
5
 * This file is part of the GNOME Devtools Libraries.
 
6
 *
 
7
 * Copyright (C) 2002 Gustavo Gir�ldez <gustavo.giraldez@gmx.net>
 
8
 *
 
9
 * This library is free software; you can redistribute it and/or
 
10
 * modify it under the terms of the GNU Lesser General Public
 
11
 * License as published by the Free Software Foundation; either
 
12
 * version 2.1 of the License, or (at your option) any later version.
 
13
 *
 
14
 * This library is distributed in the hope that it will be useful,
 
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
17
 * Lesser General Public License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU Lesser General Public
 
20
 * License along with this library; if not, write to the Free Software
 
21
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
22
 */
 
23
 
 
24
#ifdef HAVE_CONFIG_H
 
25
#include <config.h>
 
26
#endif
 
27
 
 
28
#include "gdl-i18n.h"
 
29
 
 
30
#include "gdl-tools.h"
 
31
#include "gdl-dock-placeholder.h"
 
32
#include "gdl-dock-item.h"
 
33
#include "gdl-dock-master.h"
 
34
#include "libgdltypebuiltins.h"
 
35
 
 
36
 
 
37
#undef PLACEHOLDER_DEBUG
 
38
 
 
39
/* ----- Private prototypes ----- */
 
40
 
 
41
static void     gdl_dock_placeholder_class_init     (GdlDockPlaceholderClass *klass);
 
42
static void     gdl_dock_placeholder_instance_init  (GdlDockPlaceholder      *ph);
 
43
 
 
44
static void     gdl_dock_placeholder_set_property   (GObject                 *g_object,
 
45
                                                     guint                    prop_id,
 
46
                                                     const GValue            *value,
 
47
                                                     GParamSpec              *pspec);
 
48
static void     gdl_dock_placeholder_get_property   (GObject                 *g_object,
 
49
                                                     guint                    prop_id,
 
50
                                                     GValue                  *value,
 
51
                                                     GParamSpec              *pspec);
 
52
 
 
53
static void     gdl_dock_placeholder_destroy        (GtkObject               *object);
 
54
 
 
55
static void     gdl_dock_placeholder_add            (GtkContainer            *container,
 
56
                                                     GtkWidget               *widget);
 
57
 
 
58
static void     gdl_dock_placeholder_detach         (GdlDockObject           *object,
 
59
                                                     gboolean                 recursive);
 
60
static void     gdl_dock_placeholder_reduce         (GdlDockObject           *object);
 
61
static void     gdl_dock_placeholder_dock           (GdlDockObject           *object,
 
62
                                                     GdlDockObject           *requestor,
 
63
                                                     GdlDockPlacement         position,
 
64
                                                     GValue                  *other_data);
 
65
 
 
66
static void     gdl_dock_placeholder_weak_notify    (gpointer                 data,
 
67
                                                     GObject                 *old_object);
 
68
 
 
69
static void     disconnect_host                     (GdlDockPlaceholder      *ph);
 
70
static void     connect_host                        (GdlDockPlaceholder      *ph,
 
71
                                                     GdlDockObject           *new_host);
 
72
static void     do_excursion                        (GdlDockPlaceholder      *ph);
 
73
 
 
74
static void     gdl_dock_placeholder_present        (GdlDockObject           *object,
 
75
                                                     GdlDockObject           *child);
 
76
 
 
77
static void     detach_cb                           (GdlDockObject           *object,
 
78
                                                     gboolean                 recursive,
 
79
                                                     gpointer                 user_data);
 
80
 
 
81
/* ----- Private variables and data structures ----- */
 
82
 
 
83
enum {
 
84
    PROP_0,
 
85
    PROP_STICKY,
 
86
    PROP_HOST,
 
87
    PROP_NEXT_PLACEMENT,
 
88
    PROP_WIDTH,
 
89
    PROP_HEIGHT,
 
90
        PROP_FLOATING,
 
91
        PROP_FLOAT_X,
 
92
        PROP_FLOAT_Y
 
93
};
 
94
 
 
95
struct _GdlDockPlaceholderPrivate {
 
96
    /* current object this placeholder is pinned to */
 
97
    GdlDockObject    *host;
 
98
    gboolean          sticky;
 
99
    
 
100
    /* when the placeholder is moved up the hierarchy, this stack
 
101
       keeps track of the necessary dock positions needed to get the
 
102
       placeholder to the original position */
 
103
    GSList           *placement_stack;
 
104
 
 
105
    /* Width and height of the attachments */
 
106
    gint              width;
 
107
    gint              height;
 
108
    
 
109
    /* connected signal handlers */
 
110
    guint             host_detach_handler;
 
111
    guint             host_dock_handler;
 
112
        
 
113
        /* Window Coordinates if Dock was floating */
 
114
        gboolean        floating;
 
115
        gint              floatx;
 
116
        gint              floaty;
 
117
};
 
118
 
 
119
 
 
120
/* ----- Private interface ----- */
 
121
 
 
122
GDL_CLASS_BOILERPLATE (GdlDockPlaceholder, gdl_dock_placeholder,
 
123
                       GdlDockObject, GDL_TYPE_DOCK_OBJECT);
 
124
 
 
125
static void 
 
126
gdl_dock_placeholder_class_init (GdlDockPlaceholderClass *klass)
 
127
{
 
128
    GObjectClass       *g_object_class;
 
129
    GtkObjectClass     *gtk_object_class;
 
130
    GtkContainerClass  *container_class;
 
131
    GdlDockObjectClass *object_class;
 
132
    
 
133
    g_object_class = G_OBJECT_CLASS (klass);
 
134
    gtk_object_class = GTK_OBJECT_CLASS (klass);
 
135
    container_class = GTK_CONTAINER_CLASS (klass);
 
136
    object_class = GDL_DOCK_OBJECT_CLASS (klass);
 
137
 
 
138
    g_object_class->get_property = gdl_dock_placeholder_get_property;
 
139
    g_object_class->set_property = gdl_dock_placeholder_set_property;
 
140
    
 
141
    g_object_class_install_property (
 
142
        g_object_class, PROP_STICKY,
 
143
        g_param_spec_boolean ("sticky", _("Sticky"),
 
144
                                                _("Whether the placeholder will stick to its host or "
 
145
                                        "move up the hierarchy when the host is redocked"),
 
146
                                                        FALSE,
 
147
                                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
148
    
 
149
    g_object_class_install_property (
 
150
        g_object_class, PROP_HOST,
 
151
        g_param_spec_object ("host", _("Host"),
 
152
                            _("The dock object this placeholder is attached to"),
 
153
                            GDL_TYPE_DOCK_OBJECT,
 
154
                            G_PARAM_READWRITE));
 
155
    
 
156
    /* this will return the top of the placement stack */
 
157
    g_object_class_install_property (
 
158
        g_object_class, PROP_NEXT_PLACEMENT,
 
159
        g_param_spec_enum ("next-placement", _("Next placement"),
 
160
                                                _("The position an item will be docked to our host if a "
 
161
                                                "request is made to dock to us"),
 
162
                                GDL_TYPE_DOCK_PLACEMENT,
 
163
                                GDL_DOCK_CENTER,
 
164
                                G_PARAM_READWRITE |
 
165
                                GDL_DOCK_PARAM_EXPORT | GDL_DOCK_PARAM_AFTER));
 
166
    
 
167
    g_object_class_install_property (
 
168
        g_object_class, PROP_WIDTH,
 
169
        g_param_spec_int ("width", _("Width"),
 
170
                                _("Width for the widget when it's attached to the placeholder"),
 
171
                                -1, G_MAXINT, -1,
 
172
                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
 
173
                                GDL_DOCK_PARAM_EXPORT));
 
174
    
 
175
    g_object_class_install_property (
 
176
        g_object_class, PROP_HEIGHT,
 
177
        g_param_spec_int ("height", _("Height"),
 
178
                                _("Height for the widget when it's attached to the placeholder"),
 
179
                                -1, G_MAXINT, -1,
 
180
                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
 
181
                                GDL_DOCK_PARAM_EXPORT));
 
182
        g_object_class_install_property (
 
183
        g_object_class, PROP_FLOATING,
 
184
                g_param_spec_boolean ("floating", _("Floating Toplevel"),
 
185
                            _("Whether the placeholder is standing in for a "
 
186
                            "floating toplevel dock"),
 
187
                            FALSE,
 
188
                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
189
        g_object_class_install_property (
 
190
        g_object_class, PROP_FLOAT_X,
 
191
        g_param_spec_int ("floatx", _("X-Coordinate"),
 
192
                                _("X-Coordinate fow dock when floating"),
 
193
                                -1, G_MAXINT, -1,
 
194
                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
 
195
                                GDL_DOCK_PARAM_EXPORT));
 
196
        g_object_class_install_property (
 
197
        g_object_class, PROP_FLOAT_Y,
 
198
        g_param_spec_int ("floaty", _("Y-Coordinate"),
 
199
                                _("Y-Coordinate fow dock when floating"),
 
200
                                -1, G_MAXINT, -1,
 
201
                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
 
202
                                GDL_DOCK_PARAM_EXPORT));
 
203
    
 
204
        
 
205
    gtk_object_class->destroy = gdl_dock_placeholder_destroy;
 
206
    container_class->add = gdl_dock_placeholder_add;
 
207
    
 
208
    object_class->is_compound = FALSE;
 
209
    object_class->detach = gdl_dock_placeholder_detach;
 
210
    object_class->reduce = gdl_dock_placeholder_reduce;
 
211
    object_class->dock = gdl_dock_placeholder_dock;
 
212
    object_class->present = gdl_dock_placeholder_present;
 
213
}
 
214
 
 
215
static void 
 
216
gdl_dock_placeholder_instance_init (GdlDockPlaceholder *ph)
 
217
{
 
218
    GTK_WIDGET_SET_FLAGS (ph, GTK_NO_WINDOW);
 
219
    GTK_WIDGET_UNSET_FLAGS (ph, GTK_CAN_FOCUS);
 
220
    
 
221
    ph->_priv = g_new0 (GdlDockPlaceholderPrivate, 1);
 
222
}
 
223
 
 
224
static void 
 
225
gdl_dock_placeholder_set_property (GObject      *g_object,
 
226
                                   guint         prop_id,
 
227
                                   const GValue *value,
 
228
                                   GParamSpec   *pspec)
 
229
{
 
230
    GdlDockPlaceholder *ph = GDL_DOCK_PLACEHOLDER (g_object);
 
231
 
 
232
    switch (prop_id) {
 
233
        case PROP_STICKY:
 
234
            if (ph->_priv)
 
235
                ph->_priv->sticky = g_value_get_boolean (value);
 
236
            break;
 
237
        case PROP_HOST:
 
238
            gdl_dock_placeholder_attach (ph, g_value_get_object (value));
 
239
            break;
 
240
        case PROP_NEXT_PLACEMENT:
 
241
            if (ph->_priv) {
 
242
                ph->_priv->placement_stack =
 
243
                                g_slist_prepend (ph->_priv->placement_stack,
 
244
                                     GINT_TO_POINTER (g_value_get_enum (value)));
 
245
            }
 
246
            break;
 
247
        case PROP_WIDTH:
 
248
            ph->_priv->width = g_value_get_int (value);
 
249
            break;
 
250
        case PROP_HEIGHT:
 
251
            ph->_priv->height = g_value_get_int (value);
 
252
            break;
 
253
                case PROP_FLOATING:
 
254
                        ph->_priv->floating = g_value_get_boolean (value);
 
255
                        break;
 
256
                case PROP_FLOAT_X:
 
257
                        ph->_priv->floatx = g_value_get_int (value);
 
258
                        break;
 
259
                case PROP_FLOAT_Y:
 
260
                        ph->_priv->floaty = g_value_get_int (value);
 
261
                        break;
 
262
        default:
 
263
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (g_object, prop_id, pspec);
 
264
                        break;
 
265
    }
 
266
}
 
267
 
 
268
static void 
 
269
gdl_dock_placeholder_get_property (GObject    *g_object,
 
270
                                   guint       prop_id,
 
271
                                   GValue     *value,
 
272
                                   GParamSpec *pspec)
 
273
{
 
274
    GdlDockPlaceholder *ph = GDL_DOCK_PLACEHOLDER (g_object);
 
275
 
 
276
    switch (prop_id) {
 
277
        case PROP_STICKY:
 
278
            if (ph->_priv)
 
279
                g_value_set_boolean (value, ph->_priv->sticky);
 
280
            else
 
281
                g_value_set_boolean (value, FALSE);
 
282
            break;
 
283
        case PROP_HOST:
 
284
            if (ph->_priv)
 
285
                g_value_set_object (value, ph->_priv->host);
 
286
            else
 
287
                g_value_set_object (value, NULL);
 
288
            break;
 
289
        case PROP_NEXT_PLACEMENT:
 
290
            if (ph->_priv && ph->_priv->placement_stack)
 
291
                g_value_set_enum (value, (GdlDockPlacement) ph->_priv->placement_stack->data);
 
292
            else
 
293
                g_value_set_enum (value, GDL_DOCK_CENTER);
 
294
            break;
 
295
        case PROP_WIDTH:
 
296
            g_value_set_int (value, ph->_priv->width);
 
297
            break;
 
298
        case PROP_HEIGHT:
 
299
            g_value_set_int (value, ph->_priv->height);
 
300
            break;
 
301
                case PROP_FLOATING:
 
302
                        g_value_set_boolean (value, ph->_priv->floating);
 
303
                        break;
 
304
                case PROP_FLOAT_X:
 
305
            g_value_set_int (value, ph->_priv->floatx);
 
306
            break;
 
307
        case PROP_FLOAT_Y:
 
308
            g_value_set_int (value, ph->_priv->floaty);
 
309
            break;
 
310
        default:
 
311
            G_OBJECT_WARN_INVALID_PROPERTY_ID (g_object, prop_id, pspec);
 
312
            break;
 
313
    }
 
314
}
 
315
 
 
316
static void
 
317
gdl_dock_placeholder_destroy (GtkObject *object)
 
318
{
 
319
    GdlDockPlaceholder *ph = GDL_DOCK_PLACEHOLDER (object);
 
320
 
 
321
    if (ph->_priv) {
 
322
        if (ph->_priv->host)
 
323
            gdl_dock_placeholder_detach (GDL_DOCK_OBJECT (object), FALSE);
 
324
        g_free (ph->_priv);
 
325
        ph->_priv = NULL;
 
326
    }
 
327
 
 
328
    GDL_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
 
329
}
 
330
 
 
331
static void 
 
332
gdl_dock_placeholder_add (GtkContainer *container,
 
333
                          GtkWidget    *widget)
 
334
{
 
335
    GdlDockPlaceholder *ph;
 
336
    GdlDockPlacement    pos = GDL_DOCK_CENTER;   /* default position */
 
337
    
 
338
    g_return_if_fail (GDL_IS_DOCK_PLACEHOLDER (container));
 
339
    g_return_if_fail (GDL_IS_DOCK_ITEM (widget));
 
340
 
 
341
    ph = GDL_DOCK_PLACEHOLDER (container);
 
342
    if (ph->_priv->placement_stack)
 
343
        pos = (GdlDockPlacement) ph->_priv->placement_stack->data;
 
344
    
 
345
    gdl_dock_object_dock (GDL_DOCK_OBJECT (ph), GDL_DOCK_OBJECT (widget),
 
346
                          pos, NULL);
 
347
}
 
348
 
 
349
static void
 
350
gdl_dock_placeholder_detach (GdlDockObject *object,
 
351
                             gboolean       recursive)
 
352
{
 
353
    GdlDockPlaceholder *ph = GDL_DOCK_PLACEHOLDER (object);
 
354
 
 
355
    /* disconnect handlers */
 
356
    disconnect_host (ph);
 
357
    
 
358
    /* free the placement stack */
 
359
    g_slist_free (ph->_priv->placement_stack);
 
360
    ph->_priv->placement_stack = NULL;
 
361
 
 
362
    GDL_DOCK_OBJECT_UNSET_FLAGS (object, GDL_DOCK_ATTACHED);
 
363
}
 
364
 
 
365
static void 
 
366
gdl_dock_placeholder_reduce (GdlDockObject *object)
 
367
{
 
368
    /* placeholders are not reduced */
 
369
    return;
 
370
}
 
371
 
 
372
static void
 
373
find_biggest_dock_item (GtkContainer *container, GtkWidget **biggest_child,
 
374
                        gint *biggest_child_area)
 
375
{
 
376
    GList *children, *child;
 
377
    
 
378
    children = gtk_container_get_children (GTK_CONTAINER (container));
 
379
    child = children;
 
380
    while (child) {
 
381
        gint area;
 
382
        GtkWidget *child_widget;
 
383
        
 
384
        child_widget = GTK_WIDGET (child->data);
 
385
        
 
386
        if (gdl_dock_object_is_compound (GDL_DOCK_OBJECT(child_widget))) {
 
387
            find_biggest_dock_item (GTK_CONTAINER (child_widget),
 
388
                                    biggest_child, biggest_child_area);
 
389
            child = g_list_next (child);
 
390
            continue;
 
391
        }
 
392
        area = child_widget->allocation.width * child_widget->allocation.height;
 
393
        
 
394
        if (area > *biggest_child_area) {
 
395
            *biggest_child_area = area;
 
396
            *biggest_child = child_widget;
 
397
        }
 
398
        child = g_list_next (child);
 
399
    }
 
400
}
 
401
 
 
402
static void
 
403
attempt_to_dock_on_host (GdlDockPlaceholder *ph, GdlDockObject *host,
 
404
                         GdlDockObject *requestor, GdlDockPlacement placement,
 
405
                         gpointer other_data)
 
406
{
 
407
    GdlDockObject *parent;
 
408
    gint host_width = GTK_WIDGET (host)->allocation.width;
 
409
    gint host_height = GTK_WIDGET (host)->allocation.height;
 
410
    
 
411
    if (placement != GDL_DOCK_CENTER || !GDL_IS_DOCK_PANED (host)) {
 
412
        /* we simply act as a proxy for our host */
 
413
        gdl_dock_object_dock (host, requestor,
 
414
                              placement, other_data);
 
415
    } else {
 
416
        /* If the requested pos is center, we have to make sure that it
 
417
         * does not colapses existing paned items. Find the larget item
 
418
         * which is not a paned item to dock to.
 
419
         */
 
420
        GtkWidget *biggest_child = NULL;
 
421
        gint biggest_child_area = 0;
 
422
        
 
423
        find_biggest_dock_item (GTK_CONTAINER (host), &biggest_child,
 
424
                                &biggest_child_area);
 
425
        
 
426
        if (biggest_child) {
 
427
            /* we simply act as a proxy for our host */
 
428
            gdl_dock_object_dock (GDL_DOCK_OBJECT (biggest_child), requestor,
 
429
                                  placement, other_data);
 
430
        } else {
 
431
            g_warning ("No suitable child found! Should not be here!");
 
432
            /* we simply act as a proxy for our host */
 
433
            gdl_dock_object_dock (GDL_DOCK_OBJECT (host), requestor,
 
434
                                  placement, other_data);
 
435
        }
 
436
    }
 
437
    
 
438
    parent = gdl_dock_object_get_parent_object (requestor);
 
439
    
 
440
    /* Restore dock item's dimention */
 
441
    switch (placement) {
 
442
        case GDL_DOCK_LEFT:
 
443
            if (ph->_priv->width > 0) {
 
444
                g_object_set (G_OBJECT (parent), "position",
 
445
                              ph->_priv->width, NULL);
 
446
            }
 
447
            break;
 
448
        case GDL_DOCK_RIGHT:
 
449
            if (ph->_priv->width > 0) {
 
450
                gint complementary_width = host_width - ph->_priv->width;
 
451
                
 
452
                if (complementary_width > 0)
 
453
                    g_object_set (G_OBJECT (parent), "position",
 
454
                                  complementary_width, NULL);
 
455
            }
 
456
            break;
 
457
        case GDL_DOCK_TOP:
 
458
            if (ph->_priv->height > 0) {
 
459
                g_object_set (G_OBJECT (parent), "position",
 
460
                              ph->_priv->height, NULL);
 
461
            }
 
462
            break;
 
463
        case GDL_DOCK_BOTTOM:
 
464
            if (ph->_priv->height > 0) {
 
465
                gint complementary_height = host_height - ph->_priv->height;
 
466
                
 
467
                if (complementary_height > 0)
 
468
                    g_object_set (G_OBJECT (parent), "position",
 
469
                                  complementary_height, NULL);
 
470
            }
 
471
            break;
 
472
        default:
 
473
            /* nothing */
 
474
            break;
 
475
    }
 
476
}
 
477
 
 
478
static void 
 
479
gdl_dock_placeholder_dock (GdlDockObject    *object,
 
480
                           GdlDockObject    *requestor,
 
481
                           GdlDockPlacement  position,
 
482
                           GValue           *other_data)
 
483
{
 
484
    GdlDockPlaceholder *ph = GDL_DOCK_PLACEHOLDER (object);
 
485
    
 
486
    if (ph->_priv->host) {
 
487
        attempt_to_dock_on_host (ph, ph->_priv->host, requestor,
 
488
                                 position, other_data);
 
489
    }
 
490
    else {
 
491
        GdlDockObject *toplevel;
 
492
        
 
493
        if (!gdl_dock_object_is_bound (GDL_DOCK_OBJECT (ph))) {
 
494
            g_warning (_("Attempt to dock a dock object to an unbound placeholder"));
 
495
            return;
 
496
        }
 
497
        
 
498
        /* dock the item as a floating of the controller */
 
499
        toplevel = gdl_dock_master_get_controller (GDL_DOCK_OBJECT_GET_MASTER (ph));
 
500
        gdl_dock_object_dock (toplevel, requestor,
 
501
                              GDL_DOCK_FLOATING, NULL);
 
502
    }
 
503
}
 
504
 
 
505
#ifdef PLACEHOLDER_DEBUG
 
506
static void
 
507
print_placement_stack (GdlDockPlaceholder *ph)
 
508
{
 
509
    GSList *s = ph->_priv->placement_stack;
 
510
    GEnumClass *enum_class = G_ENUM_CLASS (g_type_class_ref (GDL_TYPE_DOCK_PLACEMENT));
 
511
    GEnumValue *enum_value;
 
512
    gchar *name;
 
513
    GString *message;
 
514
 
 
515
    message = g_string_new (NULL);
 
516
    g_string_printf (message, "[%p] host: %p (%s), stack: ",
 
517
                     ph, ph->_priv->host, G_OBJECT_TYPE_NAME (ph->_priv->host));
 
518
    for (; s; s = s->next) {
 
519
        enum_value = g_enum_get_value (enum_class, (GdlDockPlacement) s->data);
 
520
        name = enum_value ? enum_value->value_name : NULL;
 
521
        g_string_append_printf (message, "%s, ", name);
 
522
    }
 
523
    g_message ("%s", message->str);
 
524
    
 
525
    g_string_free (message, TRUE);
 
526
    g_type_class_unref (enum_class);
 
527
}
 
528
#endif
 
529
 
 
530
static void 
 
531
gdl_dock_placeholder_present (GdlDockObject *object,
 
532
                              GdlDockObject *child)
 
533
{
 
534
    /* do nothing */
 
535
    return;
 
536
}
 
537
 
 
538
/* ----- Public interface ----- */ 
 
539
                                                                   
 
540
GtkWidget * 
 
541
gdl_dock_placeholder_new (gchar            *name,
 
542
                          GdlDockObject    *object,
 
543
                          GdlDockPlacement  position,
 
544
                          gboolean          sticky)
 
545
{
 
546
    GdlDockPlaceholder *ph;
 
547
 
 
548
    ph = GDL_DOCK_PLACEHOLDER (g_object_new (GDL_TYPE_DOCK_PLACEHOLDER,
 
549
                                             "name", name,
 
550
                                             "sticky", sticky,
 
551
                                             NULL));
 
552
    GDL_DOCK_OBJECT_UNSET_FLAGS (ph, GDL_DOCK_AUTOMATIC);
 
553
 
 
554
    if (object) {
 
555
        gdl_dock_placeholder_attach (ph, object);
 
556
        if (position == GDL_DOCK_NONE)
 
557
            position = GDL_DOCK_CENTER;
 
558
        g_object_set (G_OBJECT (ph), "next-placement", position, NULL);
 
559
        if (GDL_IS_DOCK (object)) {
 
560
            /* the top placement will be consumed by the toplevel
 
561
               dock, so add a dummy placement */
 
562
            g_object_set (G_OBJECT (ph), "next-placement", GDL_DOCK_CENTER, NULL);
 
563
        }
 
564
        /* try a recursion */
 
565
        do_excursion (ph);
 
566
    }
 
567
    
 
568
    return GTK_WIDGET (ph);
 
569
}
 
570
 
 
571
static void 
 
572
gdl_dock_placeholder_weak_notify (gpointer data,
 
573
                                  GObject *old_object)
 
574
{
 
575
    GdlDockPlaceholder *ph;
 
576
    
 
577
    g_return_if_fail (data != NULL && GDL_IS_DOCK_PLACEHOLDER (data));
 
578
 
 
579
    ph = GDL_DOCK_PLACEHOLDER (data);
 
580
    
 
581
#ifdef PLACEHOLDER_DEBUG
 
582
    g_message ("The placeholder just lost its host, ph = %p", ph);
 
583
#endif
 
584
    
 
585
    /* we shouldn't get here, so perform an emergency detach. instead
 
586
       we should have gotten a detach signal from our host */
 
587
    ph->_priv->host = NULL;
 
588
    
 
589
    /* We didn't get a detach signal from the host. Detach from the 
 
590
    supposedly dead host (consequently attaching to the controller) */
 
591
    
 
592
    detach_cb (NULL, TRUE, data);
 
593
#if 0
 
594
    /* free the placement stack */
 
595
    g_slist_free (ph->_priv->placement_stack);
 
596
    ph->_priv->placement_stack = NULL;
 
597
    GDL_DOCK_OBJECT_UNSET_FLAGS (ph, GDL_DOCK_ATTACHED);
 
598
#endif
 
599
}
 
600
 
 
601
static void
 
602
detach_cb (GdlDockObject *object,
 
603
           gboolean       recursive,
 
604
           gpointer       user_data)
 
605
{
 
606
    GdlDockPlaceholder *ph;
 
607
    GdlDockObject      *new_host, *obj;
 
608
 
 
609
    g_return_if_fail (user_data != NULL && GDL_IS_DOCK_PLACEHOLDER (user_data));
 
610
    
 
611
    /* we go up in the hierarchy and we store the hinted placement in
 
612
     * the placement stack so we can rebuild the docking layout later
 
613
     * when we get the host's dock signal.  */
 
614
 
 
615
    ph = GDL_DOCK_PLACEHOLDER (user_data);
 
616
    obj = ph->_priv->host;
 
617
    if (obj != object) {
 
618
        g_warning (_("Got a detach signal from an object (%p) who is not "
 
619
                     "our host %p"), object, ph->_priv->host);
 
620
        return;
 
621
    }
 
622
    
 
623
    /* skip sticky objects */
 
624
    if (ph->_priv->sticky)
 
625
        return;
 
626
    
 
627
    if (obj)
 
628
        /* go up in the hierarchy */
 
629
        new_host = gdl_dock_object_get_parent_object (obj);
 
630
    else
 
631
        /* Detaching from the dead host */
 
632
        new_host = NULL;
 
633
    
 
634
    while (new_host) {
 
635
        GdlDockPlacement pos = GDL_DOCK_NONE;
 
636
        
 
637
        /* get placement hint from the new host */
 
638
        if (gdl_dock_object_child_placement (new_host, obj, &pos)) {
 
639
            ph->_priv->placement_stack = g_slist_prepend (
 
640
                ph->_priv->placement_stack, (gpointer) pos);
 
641
        }
 
642
        else {
 
643
            g_warning (_("Something weird happened while getting the child "
 
644
                         "placement for %p from parent %p"), obj, new_host);
 
645
        }
 
646
 
 
647
        if (!GDL_DOCK_OBJECT_IN_DETACH (new_host))
 
648
            /* we found a "stable" dock object */
 
649
            break;
 
650
        
 
651
        obj = new_host;
 
652
        new_host = gdl_dock_object_get_parent_object (obj);
 
653
    }
 
654
 
 
655
    /* disconnect host */
 
656
    disconnect_host (ph);
 
657
 
 
658
    if (!new_host) {
 
659
#ifdef PLACEHOLDER_DEBUG
 
660
        g_message ("Detaching from the toplevel. Assignaing to controller");
 
661
#endif
 
662
        /* the toplevel was detached: we attach ourselves to the
 
663
           controller with an initial placement of floating */
 
664
        new_host = gdl_dock_master_get_controller (GDL_DOCK_OBJECT_GET_MASTER (ph));
 
665
        
 
666
        /*
 
667
        ph->_priv->placement_stack = g_slist_prepend (
 
668
        ph->_priv->placement_stack, (gpointer) GDL_DOCK_FLOATING);
 
669
        */
 
670
    }
 
671
    if (new_host)
 
672
        connect_host (ph, new_host);
 
673
 
 
674
#ifdef PLACEHOLDER_DEBUG
 
675
    print_placement_stack (ph);
 
676
#endif
 
677
}
 
678
 
 
679
/**
 
680
 * do_excursion:
 
681
 * @ph: placeholder object
 
682
 *
 
683
 * Tries to shrink the placement stack by examining the host's
 
684
 * children and see if any of them matches the placement which is at
 
685
 * the top of the stack.  If this is the case, it tries again with the
 
686
 * new host.
 
687
 **/
 
688
static void
 
689
do_excursion (GdlDockPlaceholder *ph)
 
690
{
 
691
    if (ph->_priv->host &&
 
692
        !ph->_priv->sticky &&
 
693
        ph->_priv->placement_stack &&
 
694
        gdl_dock_object_is_compound (ph->_priv->host)) {
 
695
 
 
696
        GdlDockPlacement pos, stack_pos =
 
697
            (GdlDockPlacement) ph->_priv->placement_stack->data;
 
698
        GList           *children, *l;
 
699
        GdlDockObject   *host = ph->_priv->host;
 
700
        
 
701
        children = gtk_container_get_children (GTK_CONTAINER (host));
 
702
        for (l = children; l; l = l->next) {
 
703
            pos = stack_pos;
 
704
            gdl_dock_object_child_placement (GDL_DOCK_OBJECT (host),
 
705
                                             GDL_DOCK_OBJECT (l->data),
 
706
                                             &pos);
 
707
            if (pos == stack_pos) {
 
708
                /* remove the stack position */
 
709
                ph->_priv->placement_stack =
 
710
                    g_slist_remove_link (ph->_priv->placement_stack,
 
711
                                         ph->_priv->placement_stack);
 
712
                
 
713
                /* connect to the new host */
 
714
                disconnect_host (ph);
 
715
                connect_host (ph, GDL_DOCK_OBJECT (l->data));
 
716
 
 
717
                /* recurse... */
 
718
                if (!GDL_DOCK_OBJECT_IN_REFLOW (l->data))
 
719
                    do_excursion (ph);
 
720
                
 
721
                break;
 
722
            }
 
723
        }
 
724
        g_list_free (children);
 
725
    }
 
726
}
 
727
 
 
728
static void 
 
729
dock_cb (GdlDockObject    *object,
 
730
         GdlDockObject    *requestor,
 
731
         GdlDockPlacement  position,
 
732
         GValue           *other_data,
 
733
         gpointer          user_data)
 
734
{
 
735
    GdlDockPlacement    pos = GDL_DOCK_NONE;
 
736
    GdlDockPlaceholder *ph;
 
737
    
 
738
    g_return_if_fail (user_data != NULL && GDL_IS_DOCK_PLACEHOLDER (user_data));
 
739
    ph = GDL_DOCK_PLACEHOLDER (user_data);
 
740
    g_return_if_fail (ph->_priv->host == object);
 
741
    
 
742
    /* see if the given position is compatible for the stack's top
 
743
       element */
 
744
    if (!ph->_priv->sticky && ph->_priv->placement_stack) {
 
745
        pos = (GdlDockPlacement) ph->_priv->placement_stack->data;
 
746
        if (gdl_dock_object_child_placement (object, requestor, &pos)) {
 
747
            if (pos == (GdlDockPlacement) ph->_priv->placement_stack->data) {
 
748
                /* the position is compatible: excurse down */
 
749
                do_excursion (ph);
 
750
            }
 
751
        }
 
752
    }
 
753
#ifdef PLACEHOLDER_DEBUG
 
754
    print_placement_stack (ph);
 
755
#endif
 
756
}
 
757
 
 
758
static void
 
759
disconnect_host (GdlDockPlaceholder *ph)
 
760
{
 
761
    if (!ph->_priv->host)
 
762
        return;
 
763
    
 
764
    if (ph->_priv->host_detach_handler)
 
765
        g_signal_handler_disconnect (ph->_priv->host, ph->_priv->host_detach_handler);
 
766
    if (ph->_priv->host_dock_handler)
 
767
        g_signal_handler_disconnect (ph->_priv->host, ph->_priv->host_dock_handler);
 
768
    ph->_priv->host_detach_handler = 0;
 
769
    ph->_priv->host_dock_handler = 0;
 
770
 
 
771
    /* remove weak ref to object */
 
772
    g_object_weak_unref (G_OBJECT (ph->_priv->host),
 
773
                         gdl_dock_placeholder_weak_notify, ph);
 
774
    ph->_priv->host = NULL;
 
775
    
 
776
#ifdef PLACEHOLDER_DEBUG
 
777
    g_message ("Host just disconnected!, ph = %p", ph);
 
778
#endif
 
779
}
 
780
 
 
781
static void
 
782
connect_host (GdlDockPlaceholder *ph,
 
783
              GdlDockObject      *new_host)
 
784
{
 
785
    if (ph->_priv->host)
 
786
        disconnect_host (ph);
 
787
    
 
788
    ph->_priv->host = new_host;
 
789
    g_object_weak_ref (G_OBJECT (ph->_priv->host),
 
790
                       gdl_dock_placeholder_weak_notify, ph);
 
791
 
 
792
    ph->_priv->host_detach_handler =
 
793
        g_signal_connect (ph->_priv->host,
 
794
                          "detach",
 
795
                          (GCallback) detach_cb,
 
796
                          (gpointer) ph);
 
797
    
 
798
    ph->_priv->host_dock_handler =
 
799
        g_signal_connect (ph->_priv->host,
 
800
                          "dock",
 
801
                          (GCallback) dock_cb,
 
802
                          (gpointer) ph);
 
803
    
 
804
#ifdef PLACEHOLDER_DEBUG
 
805
    g_message ("Host just connected!, ph = %p", ph);
 
806
#endif
 
807
}
 
808
 
 
809
void
 
810
gdl_dock_placeholder_attach (GdlDockPlaceholder *ph,
 
811
                             GdlDockObject      *object)
 
812
{
 
813
    g_return_if_fail (ph != NULL && GDL_IS_DOCK_PLACEHOLDER (ph));
 
814
    g_return_if_fail (ph->_priv != NULL);
 
815
    g_return_if_fail (object != NULL);
 
816
    
 
817
    /* object binding */
 
818
    if (!gdl_dock_object_is_bound (GDL_DOCK_OBJECT (ph)))
 
819
        gdl_dock_object_bind (GDL_DOCK_OBJECT (ph), object->master);
 
820
 
 
821
    g_return_if_fail (GDL_DOCK_OBJECT (ph)->master == object->master);
 
822
        
 
823
    gdl_dock_object_freeze (GDL_DOCK_OBJECT (ph));
 
824
    
 
825
    /* detach from previous host first */
 
826
    if (ph->_priv->host)
 
827
        gdl_dock_object_detach (GDL_DOCK_OBJECT (ph), FALSE);
 
828
 
 
829
    connect_host (ph, object);
 
830
    
 
831
    GDL_DOCK_OBJECT_SET_FLAGS (ph, GDL_DOCK_ATTACHED);
 
832
    
 
833
    gdl_dock_object_thaw (GDL_DOCK_OBJECT (ph));
 
834
}