~ubuntu-branches/ubuntu/oneiric/inkscape/oneiric-updates

« back to all changes in this revision

Viewing changes to inkscape-0.47pre1/src/libgdl/gdl-dock-master.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-master.c - Object which manages a dock ring
 
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-master.h"
 
32
#include "gdl-dock.h"
 
33
#include "gdl-dock-item.h"
 
34
#include "libgdlmarshal.h"
 
35
#include "libgdltypebuiltins.h"
 
36
#ifdef WIN32
 
37
#include "gdl-win32.h"
 
38
#endif
 
39
 
 
40
/* ----- Private prototypes ----- */
 
41
 
 
42
static void     gdl_dock_master_class_init    (GdlDockMasterClass *klass);
 
43
static void     gdl_dock_master_instance_init (GdlDockMaster      *master);
 
44
 
 
45
static void     gdl_dock_master_dispose       (GObject            *g_object);
 
46
static void     gdl_dock_master_set_property  (GObject            *object,
 
47
                                               guint               prop_id,
 
48
                                               const GValue       *value,
 
49
                                               GParamSpec         *pspec);
 
50
static void     gdl_dock_master_get_property  (GObject            *object,
 
51
                                               guint               prop_id,
 
52
                                               GValue             *value,
 
53
                                               GParamSpec         *pspec);
 
54
 
 
55
static void     _gdl_dock_master_remove       (GdlDockObject      *object,
 
56
                                               GdlDockMaster      *master);
 
57
 
 
58
static void     gdl_dock_master_drag_begin    (GdlDockItem        *item, 
 
59
                                               gpointer            data);
 
60
static void     gdl_dock_master_drag_end      (GdlDockItem        *item,
 
61
                                               gboolean            cancelled,
 
62
                                               gpointer            data);
 
63
static void     gdl_dock_master_drag_motion   (GdlDockItem        *item, 
 
64
                                               gint                x, 
 
65
                                               gint                y,
 
66
                                               gpointer            data);
 
67
 
 
68
static void     _gdl_dock_master_foreach      (gpointer            key,
 
69
                                               gpointer            value,
 
70
                                               gpointer            user_data);
 
71
 
 
72
static void     gdl_dock_master_xor_rect      (GdlDockMaster      *master);
 
73
 
 
74
static void     gdl_dock_master_layout_changed (GdlDockMaster     *master);
 
75
 
 
76
static void gdl_dock_master_set_switcher_style (GdlDockMaster *master,
 
77
                                                GdlSwitcherStyle switcher_style);
 
78
 
 
79
/* ----- Private data types and variables ----- */
 
80
 
 
81
enum {
 
82
    PROP_0,
 
83
    PROP_DEFAULT_TITLE,
 
84
    PROP_LOCKED,
 
85
    PROP_SWITCHER_STYLE,
 
86
    PROP_EXPANSION_DIRECTION
 
87
};
 
88
 
 
89
enum {
 
90
    LAYOUT_CHANGED,
 
91
    LAST_SIGNAL
 
92
};
 
93
 
 
94
struct _GdlDockMasterPrivate {
 
95
    gint            number;             /* for naming nameless manual objects */
 
96
    gchar          *default_title;
 
97
    
 
98
    GdkGC          *root_xor_gc;
 
99
    gboolean        rect_drawn;
 
100
    GdlDock        *rect_owner;
 
101
    
 
102
    GdlDockRequest *drag_request;
 
103
 
 
104
    /* source id for the idle handler to emit a layout_changed signal */
 
105
    guint           idle_layout_changed_id;
 
106
 
 
107
    /* hashes to quickly calculate the overall locked status: i.e.
 
108
     * if size(unlocked_items) == 0 then locked = 1
 
109
     * else if size(locked_items) == 0 then locked = 0
 
110
     * else locked = -1
 
111
     */
 
112
    GHashTable     *locked_items;
 
113
    GHashTable     *unlocked_items;
 
114
    
 
115
    GdlSwitcherStyle switcher_style;
 
116
 
 
117
    GdlDockExpansionDirection expansion_direction;
 
118
};
 
119
 
 
120
#define COMPUTE_LOCKED(master)                                          \
 
121
    (g_hash_table_size ((master)->_priv->unlocked_items) == 0 ? 1 :     \
 
122
     (g_hash_table_size ((master)->_priv->locked_items) == 0 ? 0 : -1))
 
123
 
 
124
static guint master_signals [LAST_SIGNAL] = { 0 };
 
125
 
 
126
 
 
127
/* ----- Private interface ----- */
 
128
 
 
129
GDL_CLASS_BOILERPLATE (GdlDockMaster, gdl_dock_master, GObject, G_TYPE_OBJECT);
 
130
 
 
131
static void
 
132
gdl_dock_master_class_init (GdlDockMasterClass *klass)
 
133
{
 
134
    GObjectClass      *g_object_class;
 
135
 
 
136
    g_object_class = G_OBJECT_CLASS (klass);
 
137
 
 
138
    g_object_class->dispose = gdl_dock_master_dispose;
 
139
    g_object_class->set_property = gdl_dock_master_set_property;
 
140
    g_object_class->get_property = gdl_dock_master_get_property;
 
141
 
 
142
    g_object_class_install_property (
 
143
        g_object_class, PROP_DEFAULT_TITLE,
 
144
        g_param_spec_string ("default-title", _("Default title"),
 
145
                             _("Default title for newly created floating docks"),
 
146
                             NULL,
 
147
                             G_PARAM_READWRITE));
 
148
    
 
149
    g_object_class_install_property (
 
150
        g_object_class, PROP_LOCKED,
 
151
        g_param_spec_int ("locked", _("Locked"),
 
152
                          _("If is set to 1, all the dock items bound to the master "
 
153
                            "are locked; if it's 0, all are unlocked; -1 indicates "
 
154
                            "inconsistency among the items"),
 
155
                          -1, 1, 0,
 
156
                          G_PARAM_READWRITE));
 
157
 
 
158
    g_object_class_install_property (
 
159
        g_object_class, PROP_SWITCHER_STYLE,
 
160
        g_param_spec_enum ("switcher-style", _("Switcher Style"),
 
161
                           _("Switcher buttons style"),
 
162
                           GDL_TYPE_SWITCHER_STYLE,
 
163
                           GDL_SWITCHER_STYLE_BOTH,
 
164
                           G_PARAM_READWRITE));
 
165
 
 
166
    g_object_class_install_property (
 
167
        g_object_class, PROP_EXPANSION_DIRECTION,
 
168
        g_param_spec_enum ("expand-direction", _("Expand direction"),
 
169
                           _("Allow the master's dock items to expand their container "
 
170
                             "dock objects in the given direction"),
 
171
                           GDL_TYPE_EXPANSION_DIRECTION,
 
172
                           GDL_DOCK_EXPANSION_DIRECTION_NONE,
 
173
                           G_PARAM_READWRITE));
 
174
 
 
175
    master_signals [LAYOUT_CHANGED] = 
 
176
        g_signal_new ("layout-changed", 
 
177
                      G_TYPE_FROM_CLASS (klass),
 
178
                      G_SIGNAL_RUN_LAST,
 
179
                      G_STRUCT_OFFSET (GdlDockMasterClass, layout_changed),
 
180
                      NULL, /* accumulator */
 
181
                      NULL, /* accu_data */
 
182
                      gdl_marshal_VOID__VOID,
 
183
                      G_TYPE_NONE, /* return type */
 
184
                      0);
 
185
 
 
186
    klass->layout_changed = gdl_dock_master_layout_changed;
 
187
}
 
188
 
 
189
static void
 
190
gdl_dock_master_instance_init (GdlDockMaster *master)
 
191
{
 
192
    master->dock_objects = g_hash_table_new_full (g_str_hash, g_str_equal,
 
193
                                                  g_free, NULL);
 
194
    master->toplevel_docks = NULL;
 
195
    master->controller = NULL;
 
196
    master->dock_number = 1;
 
197
    
 
198
    master->_priv = g_new0 (GdlDockMasterPrivate, 1);
 
199
    master->_priv->number = 1;
 
200
    master->_priv->switcher_style = GDL_SWITCHER_STYLE_BOTH;
 
201
    master->_priv->expansion_direction = GDL_DOCK_EXPANSION_DIRECTION_NONE;
 
202
    master->_priv->locked_items = g_hash_table_new (g_direct_hash, g_direct_equal);
 
203
    master->_priv->unlocked_items = g_hash_table_new (g_direct_hash, g_direct_equal);
 
204
}
 
205
 
 
206
static void
 
207
_gdl_dock_master_remove (GdlDockObject *object,
 
208
                         GdlDockMaster *master)
 
209
{
 
210
    g_return_if_fail (master != NULL && object != NULL);
 
211
 
 
212
    if (GDL_IS_DOCK (object)) {
 
213
        GList *found_link;
 
214
 
 
215
        found_link = g_list_find (master->toplevel_docks, object);
 
216
        if (found_link)
 
217
            master->toplevel_docks = g_list_delete_link (master->toplevel_docks,
 
218
                                                         found_link);
 
219
        if (object == master->controller) {
 
220
            GList *last;
 
221
            GdlDockObject *new_controller = NULL;
 
222
            
 
223
            /* now find some other non-automatic toplevel to use as a
 
224
               new controller.  start from the last dock, since it's
 
225
               probably a non-floating and manual */
 
226
            last = g_list_last (master->toplevel_docks);
 
227
            while (last) {
 
228
                if (!GDL_DOCK_OBJECT_AUTOMATIC (last->data)) {
 
229
                    new_controller = GDL_DOCK_OBJECT (last->data);
 
230
                    break;
 
231
                }
 
232
                last = last->prev;
 
233
            };
 
234
 
 
235
            if (new_controller) {
 
236
                /* the new controller gets the ref (implicitly of course) */
 
237
                master->controller = new_controller;
 
238
            } else {
 
239
                master->controller = NULL;
 
240
                /* no controller, no master */
 
241
                g_object_unref (master);
 
242
            }
 
243
        }
 
244
    }
 
245
    /* disconnect dock object signals */
 
246
    g_signal_handlers_disconnect_matched (object, G_SIGNAL_MATCH_DATA, 
 
247
                                          0, 0, NULL, NULL, master);
 
248
 
 
249
    /* unref the object from the hash if it's there */
 
250
    if (object->name) {
 
251
        GdlDockObject *found_object;
 
252
        found_object = g_hash_table_lookup (master->dock_objects, object->name);
 
253
        if (found_object == object) {
 
254
            g_hash_table_remove (master->dock_objects, object->name);
 
255
            g_object_unref (object);
 
256
        }
 
257
    }
 
258
}
 
259
 
 
260
static void
 
261
ht_foreach_build_slist (gpointer  key,
 
262
                        gpointer  value,
 
263
                        GSList  **slist)
 
264
{
 
265
    *slist = g_slist_prepend (*slist, value);
 
266
}
 
267
 
 
268
static void
 
269
gdl_dock_master_dispose (GObject *g_object)
 
270
{
 
271
    GdlDockMaster *master;
 
272
    
 
273
    g_return_if_fail (GDL_IS_DOCK_MASTER (g_object));
 
274
 
 
275
    master = GDL_DOCK_MASTER (g_object);
 
276
 
 
277
    if (master->toplevel_docks) {
 
278
        g_list_foreach (master->toplevel_docks,
 
279
                        (GFunc) gdl_dock_object_unbind, NULL);
 
280
        g_list_free (master->toplevel_docks);
 
281
        master->toplevel_docks = NULL;
 
282
    }
 
283
    
 
284
    if (master->dock_objects) {
 
285
        GSList *alive_docks = NULL;
 
286
        g_hash_table_foreach (master->dock_objects,
 
287
                              (GHFunc) ht_foreach_build_slist, &alive_docks);
 
288
        while (alive_docks) {
 
289
            gdl_dock_object_unbind (GDL_DOCK_OBJECT (alive_docks->data));
 
290
            alive_docks = g_slist_delete_link (alive_docks, alive_docks);
 
291
        }
 
292
        
 
293
        g_hash_table_destroy (master->dock_objects);
 
294
        master->dock_objects = NULL;
 
295
    }
 
296
    
 
297
    if (master->_priv) {
 
298
        if (master->_priv->idle_layout_changed_id)
 
299
            g_source_remove (master->_priv->idle_layout_changed_id);
 
300
        
 
301
        if (master->_priv->root_xor_gc) {
 
302
            g_object_unref (master->_priv->root_xor_gc);
 
303
            master->_priv->root_xor_gc = NULL;
 
304
        }
 
305
        if (master->_priv->drag_request) {
 
306
            if (G_IS_VALUE (&master->_priv->drag_request->extra))
 
307
                g_value_unset (&master->_priv->drag_request->extra);
 
308
            g_free (master->_priv->drag_request);
 
309
            master->_priv->drag_request = NULL;
 
310
        }
 
311
        g_free (master->_priv->default_title);
 
312
        master->_priv->default_title = NULL;
 
313
 
 
314
        g_hash_table_destroy (master->_priv->locked_items);
 
315
        master->_priv->locked_items = NULL;
 
316
        g_hash_table_destroy (master->_priv->unlocked_items);
 
317
        master->_priv->unlocked_items = NULL;
 
318
        
 
319
        g_free (master->_priv);
 
320
        master->_priv = NULL;
 
321
    }
 
322
 
 
323
    GDL_CALL_PARENT (G_OBJECT_CLASS, dispose, (g_object));
 
324
}
 
325
 
 
326
static void 
 
327
foreach_lock_unlock (GdlDockItem *item,
 
328
                     gboolean     locked)
 
329
{
 
330
    if (!GDL_IS_DOCK_ITEM (item))
 
331
        return;
 
332
    
 
333
    g_object_set (item, "locked", locked, NULL);
 
334
    if (gdl_dock_object_is_compound (GDL_DOCK_OBJECT (item)))
 
335
        gtk_container_foreach (GTK_CONTAINER (item),
 
336
                               (GtkCallback) foreach_lock_unlock,
 
337
                               GINT_TO_POINTER (locked));
 
338
}
 
339
 
 
340
static void
 
341
gdl_dock_master_lock_unlock (GdlDockMaster *master,
 
342
                             gboolean       locked)
 
343
{
 
344
    GList *l;
 
345
    
 
346
    for (l = master->toplevel_docks; l; l = l->next) {
 
347
        GdlDock *dock = GDL_DOCK (l->data);
 
348
        if (dock->root)
 
349
            foreach_lock_unlock (GDL_DOCK_ITEM (dock->root), locked);
 
350
    }
 
351
 
 
352
    /* just to be sure hidden items are set too */
 
353
    gdl_dock_master_foreach (master,
 
354
                             (GFunc) foreach_lock_unlock,
 
355
                             GINT_TO_POINTER (locked));
 
356
}
 
357
 
 
358
static void
 
359
gdl_dock_master_set_property  (GObject      *object,
 
360
                               guint         prop_id,
 
361
                               const GValue *value,
 
362
                               GParamSpec   *pspec)
 
363
{
 
364
    GdlDockMaster *master = GDL_DOCK_MASTER (object);
 
365
 
 
366
    switch (prop_id) {
 
367
        case PROP_DEFAULT_TITLE:
 
368
            g_free (master->_priv->default_title);
 
369
            master->_priv->default_title = g_value_dup_string (value);
 
370
            break;
 
371
        case PROP_LOCKED:
 
372
            if (g_value_get_int (value) >= 0)
 
373
                gdl_dock_master_lock_unlock (master, (g_value_get_int (value) > 0));
 
374
            break;
 
375
        case PROP_SWITCHER_STYLE:
 
376
            gdl_dock_master_set_switcher_style (master, g_value_get_enum (value));
 
377
            break;
 
378
        case PROP_EXPANSION_DIRECTION:
 
379
            master->_priv->expansion_direction = g_value_get_enum (value);
 
380
            break;
 
381
        default:
 
382
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
383
            break;
 
384
    }
 
385
}
 
386
 
 
387
static void
 
388
gdl_dock_master_get_property  (GObject      *object,
 
389
                               guint         prop_id,
 
390
                               GValue       *value,
 
391
                               GParamSpec   *pspec)
 
392
{
 
393
    GdlDockMaster *master = GDL_DOCK_MASTER (object);
 
394
 
 
395
    switch (prop_id) {
 
396
        case PROP_DEFAULT_TITLE:
 
397
            g_value_set_string (value, master->_priv->default_title);
 
398
            break;
 
399
        case PROP_LOCKED:
 
400
            g_value_set_int (value, COMPUTE_LOCKED (master));
 
401
            break;
 
402
        case PROP_SWITCHER_STYLE:
 
403
            g_value_set_enum (value, master->_priv->switcher_style);
 
404
            break;
 
405
        case PROP_EXPANSION_DIRECTION:
 
406
            g_value_set_enum (value, master->_priv->expansion_direction);
 
407
            break;
 
408
        default:
 
409
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
410
            break;
 
411
    }
 
412
}
 
413
 
 
414
static void
 
415
gdl_dock_master_drag_begin (GdlDockItem *item,
 
416
                            gpointer     data)
 
417
{
 
418
    GdlDockMaster  *master;
 
419
    GdlDockRequest *request;
 
420
    
 
421
    g_return_if_fail (data != NULL);
 
422
    g_return_if_fail (item != NULL);
 
423
 
 
424
    master = GDL_DOCK_MASTER (data);
 
425
 
 
426
    if (!master->_priv->drag_request)
 
427
        master->_priv->drag_request = g_new0 (GdlDockRequest, 1);
 
428
 
 
429
    request = master->_priv->drag_request;
 
430
    
 
431
    /* Set the target to itself so it won't go floating with just a click. */
 
432
    request->applicant = GDL_DOCK_OBJECT (item);
 
433
    request->target = GDL_DOCK_OBJECT (item);
 
434
    request->position = GDL_DOCK_FLOATING;
 
435
    if (G_IS_VALUE (&request->extra))
 
436
        g_value_unset (&request->extra);
 
437
 
 
438
    master->_priv->rect_drawn = FALSE;
 
439
    master->_priv->rect_owner = NULL;
 
440
}
 
441
 
 
442
static void
 
443
gdl_dock_master_drag_end (GdlDockItem *item, 
 
444
                          gboolean     cancelled,
 
445
                          gpointer     data)
 
446
{
 
447
    GdlDockMaster  *master;
 
448
    GdlDockRequest *request;
 
449
    
 
450
    g_return_if_fail (data != NULL);
 
451
    g_return_if_fail (item != NULL);
 
452
 
 
453
    master = GDL_DOCK_MASTER (data);
 
454
    request = master->_priv->drag_request;
 
455
    
 
456
    g_return_if_fail (GDL_DOCK_OBJECT (item) == request->applicant);
 
457
    
 
458
    /* Erase previously drawn rectangle */
 
459
    if (master->_priv->rect_drawn)
 
460
        gdl_dock_master_xor_rect (master);
 
461
    
 
462
    /* cancel conditions */
 
463
    if (cancelled || request->applicant == request->target)
 
464
        return;
 
465
    
 
466
    /* dock object to the requested position */
 
467
    gdl_dock_object_dock (request->target,
 
468
                          request->applicant,
 
469
                          request->position,
 
470
                          &request->extra);
 
471
    
 
472
    g_signal_emit (master, master_signals [LAYOUT_CHANGED], 0);
 
473
}
 
474
 
 
475
static void
 
476
gdl_dock_master_drag_motion (GdlDockItem *item, 
 
477
                             gint         root_x, 
 
478
                             gint         root_y,
 
479
                             gpointer     data)
 
480
{
 
481
    GdlDockMaster  *master;
 
482
    GdlDockRequest  my_request, *request;
 
483
    GdkWindow      *window;
 
484
    gint            win_x, win_y;
 
485
    gint            x, y;
 
486
    GdlDock        *dock = NULL;
 
487
    gboolean        may_dock = FALSE;
 
488
    
 
489
    g_return_if_fail (item != NULL && data != NULL);
 
490
 
 
491
    master = GDL_DOCK_MASTER (data);
 
492
    request = master->_priv->drag_request;
 
493
 
 
494
    g_return_if_fail (GDL_DOCK_OBJECT (item) == request->applicant);
 
495
    
 
496
    my_request = *request;
 
497
 
 
498
    /* first look under the pointer */
 
499
    window = gdk_window_at_pointer (&win_x, &win_y);
 
500
    if (window) {
 
501
        GtkWidget *widget;
 
502
        /* ok, now get the widget who owns that window and see if we can
 
503
           get to a GdlDock by walking up the hierarchy */
 
504
        gdk_window_get_user_data (window, (gpointer) &widget);
 
505
        if (GTK_IS_WIDGET (widget)) {
 
506
            while (widget && (!GDL_IS_DOCK (widget) || 
 
507
                   GDL_DOCK_OBJECT_GET_MASTER (widget) != master))
 
508
                widget = widget->parent;
 
509
            if (widget) {
 
510
                gint win_w, win_h;
 
511
                
 
512
                /* verify that the pointer is still in that dock
 
513
                   (the user could have moved it) */
 
514
                gdk_window_get_geometry (widget->window,
 
515
                                         NULL, NULL, &win_w, &win_h, NULL);
 
516
                gdk_window_get_origin (widget->window, &win_x, &win_y);
 
517
                if (root_x >= win_x && root_x < win_x + win_w &&
 
518
                    root_y >= win_y && root_y < win_y + win_h)
 
519
                    dock = GDL_DOCK (widget);
 
520
            }
 
521
        }
 
522
    }
 
523
 
 
524
    if (dock) {
 
525
        /* translate root coordinates into dock object coordinates
 
526
           (i.e. widget coordinates) */
 
527
        gdk_window_get_origin (GTK_WIDGET (dock)->window, &win_x, &win_y);
 
528
        x = root_x - win_x;
 
529
        y = root_y - win_y;
 
530
        may_dock = gdl_dock_object_dock_request (GDL_DOCK_OBJECT (dock),
 
531
                                                 x, y, &my_request);
 
532
    }
 
533
    else {
 
534
        GList *l;
 
535
 
 
536
        /* try to dock the item in all the docks in the ring in turn */
 
537
        for (l = master->toplevel_docks; l; l = l->next) {
 
538
            dock = GDL_DOCK (l->data);
 
539
            /* translate root coordinates into dock object coordinates
 
540
               (i.e. widget coordinates) */
 
541
            gdk_window_get_origin (GTK_WIDGET (dock)->window, &win_x, &win_y);
 
542
            x = root_x - win_x;
 
543
            y = root_y - win_y;
 
544
            may_dock = gdl_dock_object_dock_request (GDL_DOCK_OBJECT (dock),
 
545
                                                     x, y, &my_request);
 
546
            if (may_dock)
 
547
                break;
 
548
        }
 
549
    }
 
550
 
 
551
  
 
552
    if (!may_dock) {
 
553
        GtkRequisition req;
 
554
        /* Special case for GdlDockItems : they must respect the flags */
 
555
        if(GDL_IS_DOCK_ITEM(item)
 
556
        && GDL_DOCK_ITEM(item)->behavior & GDL_DOCK_ITEM_BEH_NEVER_FLOATING)
 
557
            return;
 
558
 
 
559
        dock = NULL;
 
560
        my_request.target = GDL_DOCK_OBJECT (
 
561
            gdl_dock_object_get_toplevel (request->applicant));
 
562
        my_request.position = GDL_DOCK_FLOATING;
 
563
 
 
564
        gdl_dock_item_preferred_size (GDL_DOCK_ITEM (request->applicant), &req);
 
565
        my_request.rect.width = req.width;
 
566
        my_request.rect.height = req.height;
 
567
 
 
568
        my_request.rect.x = root_x - GDL_DOCK_ITEM (request->applicant)->dragoff_x;
 
569
        my_request.rect.y = root_y - GDL_DOCK_ITEM (request->applicant)->dragoff_y;
 
570
 
 
571
        /* setup extra docking information */
 
572
        if (G_IS_VALUE (&my_request.extra))
 
573
            g_value_unset (&my_request.extra);
 
574
 
 
575
        g_value_init (&my_request.extra, GDK_TYPE_RECTANGLE);
 
576
        g_value_set_boxed (&my_request.extra, &my_request.rect);
 
577
    }
 
578
    /* if we want to enforce GDL_DOCK_ITEM_BEH_NEVER_FLOATING           */
 
579
    /* the item must remain attached to the controller, otherwise       */
 
580
    /* it could be inserted in another floating dock                    */
 
581
    /* so check for the flag at this moment                             */
 
582
    else if(GDL_IS_DOCK_ITEM(item)
 
583
        && GDL_DOCK_ITEM(item)->behavior & GDL_DOCK_ITEM_BEH_NEVER_FLOATING
 
584
        && dock != GDL_DOCK(master->controller))
 
585
            return;
 
586
 
 
587
    if (!(my_request.rect.x == request->rect.x &&
 
588
          my_request.rect.y == request->rect.y &&
 
589
          my_request.rect.width == request->rect.width &&
 
590
          my_request.rect.height == request->rect.height &&
 
591
          dock == master->_priv->rect_owner)) {
 
592
        
 
593
        /* erase the previous rectangle */
 
594
        if (master->_priv->rect_drawn)
 
595
            gdl_dock_master_xor_rect (master);
 
596
    }
 
597
 
 
598
    /* set the new values */
 
599
    *request = my_request;
 
600
    master->_priv->rect_owner = dock;
 
601
    
 
602
    /* draw the previous rectangle */
 
603
    if (~master->_priv->rect_drawn)
 
604
        gdl_dock_master_xor_rect (master);
 
605
}
 
606
 
 
607
static void
 
608
_gdl_dock_master_foreach (gpointer key,
 
609
                          gpointer value,
 
610
                          gpointer user_data)
 
611
{
 
612
    (void)key;
 
613
    struct {
 
614
        GFunc    function;
 
615
        gpointer user_data;
 
616
    } *data = user_data;
 
617
 
 
618
    (* data->function) (GTK_WIDGET (value), data->user_data);
 
619
}
 
620
 
 
621
static void
 
622
gdl_dock_master_xor_rect (GdlDockMaster *master)
 
623
{
 
624
    gint8         dash_list [2];
 
625
    GdkWindow    *window;
 
626
    GdkRectangle *rect;
 
627
    
 
628
    if (!master->_priv || !master->_priv->drag_request)
 
629
        return;
 
630
    
 
631
    master->_priv->rect_drawn = ~master->_priv->rect_drawn;
 
632
    
 
633
    if (master->_priv->rect_owner) {
 
634
        gdl_dock_xor_rect (master->_priv->rect_owner,
 
635
                           &master->_priv->drag_request->rect);
 
636
        return;
 
637
    }
 
638
    
 
639
    rect = &master->_priv->drag_request->rect;
 
640
    window = gdk_get_default_root_window ();
 
641
 
 
642
    if (!master->_priv->root_xor_gc) {
 
643
        GdkGCValues values;
 
644
 
 
645
        values.function = GDK_INVERT;
 
646
        values.subwindow_mode = GDK_INCLUDE_INFERIORS;
 
647
        master->_priv->root_xor_gc = gdk_gc_new_with_values (
 
648
            window, &values, GDK_GC_FUNCTION | GDK_GC_SUBWINDOW);
 
649
    };
 
650
 
 
651
#ifdef WIN32    
 
652
    GdkLineStyle lineStyle = GDK_LINE_ON_OFF_DASH;
 
653
    if (is_os_vista())
 
654
    {
 
655
        // On Vista the dash-line is increadibly slow to draw, it takes several minutes to draw the tracking lines
 
656
        // With GDK_LINE_SOLID it is parts of a second
 
657
        // No performance issue on WinXP
 
658
        lineStyle = GDK_LINE_SOLID;
 
659
    }
 
660
#else
 
661
    GdkLineStyle lineStyle = GDK_LINE_ON_OFF_DASH;
 
662
#endif
 
663
    gdk_gc_set_line_attributes (master->_priv->root_xor_gc, 1,
 
664
                                lineStyle,
 
665
                                GDK_CAP_NOT_LAST,
 
666
                                GDK_JOIN_BEVEL);
 
667
    
 
668
    dash_list[0] = 1;
 
669
    dash_list[1] = 1;
 
670
    gdk_gc_set_dashes (master->_priv->root_xor_gc, 1, dash_list, 2);
 
671
 
 
672
    gdk_draw_rectangle (window, master->_priv->root_xor_gc, 0, 
 
673
                        rect->x, rect->y,
 
674
                        rect->width, rect->height);
 
675
 
 
676
    gdk_gc_set_dashes (master->_priv->root_xor_gc, 0, dash_list, 2);
 
677
 
 
678
    gdk_draw_rectangle (window, master->_priv->root_xor_gc, 0, 
 
679
                        rect->x + 1, rect->y + 1,
 
680
                        rect->width - 2, rect->height - 2);
 
681
}
 
682
 
 
683
static void
 
684
gdl_dock_master_layout_changed (GdlDockMaster *master)
 
685
{
 
686
    g_return_if_fail (GDL_IS_DOCK_MASTER (master));
 
687
 
 
688
    /* emit "layout-changed" on the controller to notify the user who
 
689
     * normally shouldn't have access to us */
 
690
    if (master->controller)
 
691
        g_signal_emit_by_name (master->controller, "layout-changed");
 
692
 
 
693
    /* remove the idle handler if there is one */
 
694
    if (master->_priv->idle_layout_changed_id) {
 
695
        g_source_remove (master->_priv->idle_layout_changed_id);
 
696
        master->_priv->idle_layout_changed_id = 0;
 
697
    }
 
698
}
 
699
 
 
700
static gboolean
 
701
idle_emit_layout_changed (gpointer user_data)
 
702
{
 
703
    GdlDockMaster *master = user_data;
 
704
 
 
705
    g_return_val_if_fail (master && GDL_IS_DOCK_MASTER (master), FALSE);
 
706
 
 
707
    master->_priv->idle_layout_changed_id = 0;
 
708
    g_signal_emit (master, master_signals [LAYOUT_CHANGED], 0);
 
709
    
 
710
    return FALSE;
 
711
}
 
712
 
 
713
static void 
 
714
item_dock_cb (GdlDockObject    *object,
 
715
              GdlDockObject    *requestor,
 
716
              GdlDockPlacement  position,
 
717
              GValue           *other_data,
 
718
              gpointer          user_data)
 
719
{
 
720
    GdlDockMaster *master = user_data;
 
721
    
 
722
    g_return_if_fail (requestor && GDL_IS_DOCK_OBJECT (requestor));
 
723
    g_return_if_fail (master && GDL_IS_DOCK_MASTER (master));
 
724
 
 
725
    /* here we are in fact interested in the requestor, since it's
 
726
     * assumed that object will not change its visibility... for the
 
727
     * requestor, however, could mean that it's being shown */
 
728
    if (!GDL_DOCK_OBJECT_IN_REFLOW (requestor) &&
 
729
        !GDL_DOCK_OBJECT_AUTOMATIC (requestor)) {
 
730
        if (!master->_priv->idle_layout_changed_id)
 
731
            master->_priv->idle_layout_changed_id =
 
732
                g_idle_add (idle_emit_layout_changed, master);
 
733
    }
 
734
}
 
735
 
 
736
static void 
 
737
item_detach_cb (GdlDockObject *object,
 
738
                gboolean       recursive,
 
739
                gpointer       user_data)
 
740
{
 
741
    GdlDockMaster *master = user_data;
 
742
    
 
743
    g_return_if_fail (object && GDL_IS_DOCK_OBJECT (object));
 
744
    g_return_if_fail (master && GDL_IS_DOCK_MASTER (master));
 
745
 
 
746
    if (!GDL_DOCK_OBJECT_IN_REFLOW (object) &&
 
747
        !GDL_DOCK_OBJECT_AUTOMATIC (object)) {
 
748
        if (!master->_priv->idle_layout_changed_id)
 
749
            master->_priv->idle_layout_changed_id =
 
750
                g_idle_add (idle_emit_layout_changed, master);
 
751
    }
 
752
}
 
753
 
 
754
static void
 
755
item_notify_cb (GdlDockObject *object,
 
756
                GParamSpec    *pspec,
 
757
                gpointer       user_data)
 
758
{
 
759
    GdlDockMaster *master = user_data;
 
760
    gint locked = COMPUTE_LOCKED (master);
 
761
    gboolean item_locked;
 
762
    
 
763
    g_object_get (object, "locked", &item_locked, NULL);
 
764
 
 
765
    if (item_locked) {
 
766
        g_hash_table_remove (master->_priv->unlocked_items, object);
 
767
        g_hash_table_insert (master->_priv->locked_items, object, NULL);
 
768
    } else {
 
769
        g_hash_table_remove (master->_priv->locked_items, object);
 
770
        g_hash_table_insert (master->_priv->unlocked_items, object, NULL);
 
771
    }
 
772
    
 
773
    if (COMPUTE_LOCKED (master) != locked)
 
774
        g_object_notify (G_OBJECT (master), "locked");
 
775
}
 
776
 
 
777
/* ----- Public interface ----- */
 
778
 
 
779
void
 
780
gdl_dock_master_add (GdlDockMaster *master,
 
781
                     GdlDockObject *object)
 
782
{
 
783
    g_return_if_fail (master != NULL && object != NULL);
 
784
 
 
785
    if (!GDL_DOCK_OBJECT_AUTOMATIC (object)) {
 
786
        GdlDockObject *found_object;
 
787
        
 
788
        /* create a name for the object if it doesn't have one */
 
789
        if (!object->name)
 
790
            /* directly set the name, since it's a construction only
 
791
               property */
 
792
            object->name = g_strdup_printf ("__dock_%u", master->_priv->number++);
 
793
        
 
794
        /* add the object to our hash list */
 
795
        if ((found_object = g_hash_table_lookup (master->dock_objects, object->name))) {
 
796
            g_warning (_("master %p: unable to add object %p[%s] to the hash.  "
 
797
                         "There already is an item with that name (%p)."),
 
798
                       master, object, object->name, found_object);
 
799
        }
 
800
        else {
 
801
            g_object_ref (object);
 
802
            gtk_object_sink (GTK_OBJECT (object));
 
803
            g_hash_table_insert (master->dock_objects, g_strdup (object->name), object);
 
804
        }
 
805
    }
 
806
    
 
807
    if (GDL_IS_DOCK (object)) {
 
808
        gboolean floating;
 
809
        
 
810
        /* if this is the first toplevel we are adding, name it controller */
 
811
        if (!master->toplevel_docks)
 
812
            /* the dock should already have the ref */
 
813
            master->controller = object;
 
814
        
 
815
        /* add dock to the toplevel list */
 
816
        g_object_get (object, "floating", &floating, NULL);
 
817
        if (floating)
 
818
            master->toplevel_docks = g_list_prepend (master->toplevel_docks, object);
 
819
        else
 
820
            master->toplevel_docks = g_list_append (master->toplevel_docks, object);
 
821
 
 
822
        /* we are interested in the dock request this toplevel
 
823
         * receives to update the layout */
 
824
        g_signal_connect (object, "dock",
 
825
                          G_CALLBACK (item_dock_cb), master);
 
826
 
 
827
    }
 
828
    else if (GDL_IS_DOCK_ITEM (object)) {
 
829
        /* we need to connect the item's signals */
 
830
        g_signal_connect (object, "dock_drag_begin",
 
831
                          G_CALLBACK (gdl_dock_master_drag_begin), master);
 
832
        g_signal_connect (object, "dock_drag_motion",
 
833
                          G_CALLBACK (gdl_dock_master_drag_motion), master);
 
834
        g_signal_connect (object, "dock_drag_end",
 
835
                          G_CALLBACK (gdl_dock_master_drag_end), master);
 
836
        g_signal_connect (object, "dock",
 
837
                          G_CALLBACK (item_dock_cb), master);
 
838
        g_signal_connect (object, "detach",
 
839
                          G_CALLBACK (item_detach_cb), master);
 
840
 
 
841
        /* register to "locked" notification if the item has a grip,
 
842
         * and add the item to the corresponding hash */
 
843
        if (GDL_DOCK_ITEM_HAS_GRIP (GDL_DOCK_ITEM (object))) {
 
844
            g_signal_connect (object, "notify::locked",
 
845
                              G_CALLBACK (item_notify_cb), master);
 
846
            item_notify_cb (object, NULL, master);
 
847
        }
 
848
        
 
849
        /* If the item is notebook, set the switcher style */
 
850
        if (GDL_IS_DOCK_NOTEBOOK (object) &&
 
851
            GDL_IS_SWITCHER (GDL_DOCK_ITEM (object)->child))
 
852
        {
 
853
            g_object_set (GDL_DOCK_ITEM (object)->child, "switcher-style",
 
854
                          master->_priv->switcher_style, NULL);
 
855
        }
 
856
        
 
857
        /* post a layout_changed emission if the item is not automatic
 
858
         * (since it should be added to the items model) */
 
859
        if (!GDL_DOCK_OBJECT_AUTOMATIC (object)) {
 
860
            if (!master->_priv->idle_layout_changed_id)
 
861
                master->_priv->idle_layout_changed_id =
 
862
                    g_idle_add (idle_emit_layout_changed, master);
 
863
        }
 
864
    }
 
865
}
 
866
 
 
867
void
 
868
gdl_dock_master_remove (GdlDockMaster *master,
 
869
                        GdlDockObject *object)
 
870
{
 
871
    g_return_if_fail (master != NULL && object != NULL);
 
872
 
 
873
    /* remove from locked/unlocked hashes and property change if
 
874
     * that's the case */
 
875
    if (GDL_IS_DOCK_ITEM (object) && GDL_DOCK_ITEM_HAS_GRIP (GDL_DOCK_ITEM (object))) {
 
876
        gint locked = COMPUTE_LOCKED (master);
 
877
        if (g_hash_table_remove (master->_priv->locked_items, object) ||
 
878
            g_hash_table_remove (master->_priv->unlocked_items, object)) {
 
879
            if (COMPUTE_LOCKED (master) != locked)
 
880
                g_object_notify (G_OBJECT (master), "locked");
 
881
        }
 
882
    }
 
883
        
 
884
    /* ref the master, since removing the controller could cause master disposal */
 
885
    g_object_ref (master);
 
886
    
 
887
    /* all the interesting stuff happens in _gdl_dock_master_remove */
 
888
    _gdl_dock_master_remove (object, master);
 
889
 
 
890
    /* post a layout_changed emission if the item is not automatic
 
891
     * (since it should be removed from the items model) */
 
892
    if (!GDL_DOCK_OBJECT_AUTOMATIC (object)) {
 
893
        if (!master->_priv->idle_layout_changed_id)
 
894
            master->_priv->idle_layout_changed_id =
 
895
                g_idle_add (idle_emit_layout_changed, master);
 
896
    }
 
897
    
 
898
    /* balance ref count */
 
899
    g_object_unref (master);
 
900
}
 
901
 
 
902
void
 
903
gdl_dock_master_foreach (GdlDockMaster *master,
 
904
                         GFunc          function,
 
905
                         gpointer       user_data)
 
906
{
 
907
    struct {
 
908
        GFunc    function;
 
909
        gpointer user_data;
 
910
    } data;
 
911
 
 
912
    g_return_if_fail (master != NULL && function != NULL);
 
913
 
 
914
    data.function = function;
 
915
    data.user_data = user_data;
 
916
    g_hash_table_foreach (master->dock_objects, _gdl_dock_master_foreach, &data);
 
917
}
 
918
 
 
919
void
 
920
gdl_dock_master_foreach_toplevel (GdlDockMaster *master,
 
921
                                  gboolean       include_controller,
 
922
                                  GFunc          function,
 
923
                                  gpointer       user_data)
 
924
{
 
925
    GList *l;
 
926
    
 
927
    g_return_if_fail (master != NULL && function != NULL);
 
928
 
 
929
    for (l = master->toplevel_docks; l; ) {
 
930
        GdlDockObject *object = GDL_DOCK_OBJECT (l->data);
 
931
        l = l->next;
 
932
        if (object != master->controller || include_controller)
 
933
            (* function) (GTK_WIDGET (object), user_data);
 
934
    }
 
935
}
 
936
 
 
937
GdlDockObject *
 
938
gdl_dock_master_get_object (GdlDockMaster *master,
 
939
                            const gchar   *nick_name)
 
940
{
 
941
    gpointer *found;
 
942
    
 
943
    g_return_val_if_fail (master != NULL, NULL);
 
944
 
 
945
    if (!nick_name)
 
946
        return NULL;
 
947
 
 
948
    found = g_hash_table_lookup (master->dock_objects, nick_name);
 
949
 
 
950
    return found ? GDL_DOCK_OBJECT (found) : NULL;
 
951
}
 
952
 
 
953
GdlDockObject *
 
954
gdl_dock_master_get_controller (GdlDockMaster *master)
 
955
{
 
956
    g_return_val_if_fail (master != NULL, NULL);
 
957
 
 
958
    return master->controller;
 
959
}
 
960
 
 
961
void
 
962
gdl_dock_master_set_controller (GdlDockMaster *master,
 
963
                                GdlDockObject *new_controller)
 
964
{
 
965
    g_return_if_fail (master != NULL);
 
966
 
 
967
    if (new_controller) {
 
968
        if (GDL_DOCK_OBJECT_AUTOMATIC (new_controller))
 
969
            g_warning (_("The new dock controller %p is automatic.  Only manual "
 
970
                         "dock objects should be named controller."), new_controller);
 
971
        
 
972
        /* check that the controller is in the toplevel list */
 
973
        if (!g_list_find (master->toplevel_docks, new_controller))
 
974
            gdl_dock_master_add (master, new_controller);
 
975
        master->controller = new_controller;
 
976
 
 
977
    } else {
 
978
        master->controller = NULL;
 
979
        /* no controller, no master */
 
980
        g_object_unref (master);
 
981
    }
 
982
}
 
983
 
 
984
static void
 
985
set_switcher_style_foreach (GtkWidget *obj, gpointer user_data)
 
986
{
 
987
    GdlSwitcherStyle style = GPOINTER_TO_INT (user_data);
 
988
    
 
989
    if (!GDL_IS_DOCK_ITEM (obj))
 
990
        return;
 
991
    
 
992
    if (GDL_IS_DOCK_NOTEBOOK (obj)) {
 
993
        
 
994
        GtkWidget *child = GDL_DOCK_ITEM (obj)->child;
 
995
        if (GDL_IS_SWITCHER (child)) {
 
996
            
 
997
            g_object_set (child, "switcher-style", style, NULL);
 
998
        }
 
999
    } else if (gdl_dock_object_is_compound (GDL_DOCK_OBJECT (obj))) {
 
1000
        
 
1001
        gtk_container_foreach (GTK_CONTAINER (obj),
 
1002
                               set_switcher_style_foreach,
 
1003
                               user_data);
 
1004
    }
 
1005
}
 
1006
 
 
1007
static void
 
1008
gdl_dock_master_set_switcher_style (GdlDockMaster *master,
 
1009
                                    GdlSwitcherStyle switcher_style)
 
1010
{
 
1011
    GList *l;
 
1012
    g_return_if_fail (GDL_IS_DOCK_MASTER (master));
 
1013
    
 
1014
    master->_priv->switcher_style = switcher_style;
 
1015
    for (l = master->toplevel_docks; l; l = l->next) {
 
1016
        GdlDock *dock = GDL_DOCK (l->data);
 
1017
        if (dock->root)
 
1018
            set_switcher_style_foreach (GTK_WIDGET (dock->root),
 
1019
                                        GINT_TO_POINTER (switcher_style));
 
1020
    }
 
1021
 
 
1022
    /* just to be sure hidden items are set too */
 
1023
    gdl_dock_master_foreach (master, (GFunc) set_switcher_style_foreach,
 
1024
                             GINT_TO_POINTER (switcher_style));
 
1025
}