~ubuntu-branches/ubuntu/hoary/gimp/hoary

« back to all changes in this revision

Viewing changes to app/widgets/gimpdock.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2005-04-04 14:51:23 UTC
  • Revision ID: james.westby@ubuntu.com-20050404145123-9py049eeelfymur8
Tags: upstream-2.2.2
ImportĀ upstreamĀ versionĀ 2.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* The GIMP -- an image manipulation program
 
2
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 
3
 *
 
4
 * gimpdock.c
 
5
 * Copyright (C) 2001-2003 Michael Natterer <mitch@gimp.org>
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 2 of the License, or
 
10
 * (at your option) any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
 
 
24
#include <gtk/gtk.h>
 
25
 
 
26
#include "libgimpwidgets/gimpwidgets.h"
 
27
 
 
28
#include "widgets-types.h"
 
29
 
 
30
#include "config/gimpguiconfig.h"
 
31
 
 
32
#include "core/gimp.h"
 
33
#include "core/gimpcontext.h"
 
34
#include "core/gimpmarshal.h"
 
35
 
 
36
#include "gimpdialogfactory.h"
 
37
#include "gimpdnd.h"
 
38
#include "gimpdock.h"
 
39
#include "gimpdockable.h"
 
40
#include "gimpdockbook.h"
 
41
#include "gimphelp-ids.h"
 
42
#include "gimpmessagebox.h"
 
43
#include "gimpmessagedialog.h"
 
44
#include "gimpwidgets-utils.h"
 
45
 
 
46
#include "gimp-intl.h"
 
47
 
 
48
 
 
49
#define DEFAULT_DOCK_HEIGHT       300
 
50
#define DEFAULT_SEPARATOR_HEIGHT  6
 
51
 
 
52
enum
 
53
{
 
54
  PROP_0,
 
55
  PROP_CONTEXT,
 
56
  PROP_DIALOG_FACTORY
 
57
};
 
58
 
 
59
enum
 
60
{
 
61
  BOOK_ADDED,
 
62
  BOOK_REMOVED,
 
63
  LAST_SIGNAL
 
64
};
 
65
 
 
66
 
 
67
static void        gimp_dock_class_init        (GimpDockClass         *klass);
 
68
static void        gimp_dock_init              (GimpDock              *dock);
 
69
 
 
70
static GObject   * gimp_dock_constructor       (GType                  type,
 
71
                                                guint                  n_params,
 
72
                                                GObjectConstructParam *params);
 
73
static void        gimp_dock_set_property      (GObject               *object,
 
74
                                                guint                  property_id,
 
75
                                                const GValue          *value,
 
76
                                                GParamSpec            *pspec);
 
77
static void        gimp_dock_get_property      (GObject               *object,
 
78
                                                guint                  property_id,
 
79
                                                GValue                *value,
 
80
                                                GParamSpec            *pspec);
 
81
 
 
82
static void        gimp_dock_destroy           (GtkObject             *object);
 
83
 
 
84
static gboolean    gimp_dock_delete_event      (GtkWidget             *widget,
 
85
                                                GdkEventAny           *event);
 
86
static gboolean    gimp_dock_key_press_event   (GtkWidget             *widget,
 
87
                                                GdkEventKey           *kevent);
 
88
 
 
89
static void        gimp_dock_style_set         (GtkWidget             *widget,
 
90
                                                GtkStyle              *prev_style);
 
91
 
 
92
static void        gimp_dock_real_book_added   (GimpDock              *dock,
 
93
                                                GimpDockbook          *dockbook);
 
94
static void        gimp_dock_real_book_removed (GimpDock              *dock,
 
95
                                                GimpDockbook          *dockbook);
 
96
 
 
97
static GtkWidget * gimp_dock_separator_new            (GimpDock       *dock);
 
98
static void        gimp_dock_separator_drag_leave     (GtkWidget      *widget,
 
99
                                                       GdkDragContext *context,
 
100
                                                       guint           time,
 
101
                                                       gpointer        data);
 
102
static gboolean    gimp_dock_separator_drag_motion    (GtkWidget      *widget,
 
103
                                                       GdkDragContext *context,
 
104
                                                       gint            x,
 
105
                                                       gint            y,
 
106
                                                       guint           time,
 
107
                                                       gpointer        data);
 
108
static gboolean    gimp_dock_separator_drag_drop      (GtkWidget      *widget,
 
109
                                                       GdkDragContext *context,
 
110
                                                       gint            x,
 
111
                                                       gint            y,
 
112
                                                       guint           time,
 
113
                                                       GimpDock       *dock);
 
114
 
 
115
 
 
116
static GtkWindowClass *parent_class              = NULL;
 
117
static guint           dock_signals[LAST_SIGNAL] = { 0 };
 
118
static GtkTargetEntry  dialog_target_table[]     =
 
119
{
 
120
  GIMP_TARGET_DIALOG
 
121
};
 
122
 
 
123
 
 
124
GType
 
125
gimp_dock_get_type (void)
 
126
{
 
127
  static GType dock_type = 0;
 
128
 
 
129
  if (! dock_type)
 
130
    {
 
131
      static const GTypeInfo dock_info =
 
132
      {
 
133
        sizeof (GimpDockClass),
 
134
        NULL,           /* base_init */
 
135
        NULL,           /* base_finalize */
 
136
        (GClassInitFunc) gimp_dock_class_init,
 
137
        NULL,           /* class_finalize */
 
138
        NULL,           /* class_data */
 
139
        sizeof (GimpDock),
 
140
        0,              /* n_preallocs */
 
141
        (GInstanceInitFunc) gimp_dock_init,
 
142
      };
 
143
 
 
144
      dock_type = g_type_register_static (GTK_TYPE_WINDOW,
 
145
                                          "GimpDock",
 
146
                                          &dock_info, 0);
 
147
    }
 
148
 
 
149
  return dock_type;
 
150
}
 
151
 
 
152
static void
 
153
gimp_dock_class_init (GimpDockClass *klass)
 
154
{
 
155
  GObjectClass   *object_class;
 
156
  GtkObjectClass *gtk_object_class;
 
157
  GtkWidgetClass *widget_class;
 
158
 
 
159
  object_class     = G_OBJECT_CLASS (klass);
 
160
  gtk_object_class = GTK_OBJECT_CLASS (klass);
 
161
  widget_class     = GTK_WIDGET_CLASS (klass);
 
162
 
 
163
  parent_class = g_type_class_peek_parent (klass);
 
164
 
 
165
  dock_signals[BOOK_ADDED] =
 
166
    g_signal_new ("book_added",
 
167
                  G_TYPE_FROM_CLASS (klass),
 
168
                  G_SIGNAL_RUN_FIRST,
 
169
                  G_STRUCT_OFFSET (GimpDockClass, book_added),
 
170
                  NULL, NULL,
 
171
                  gimp_marshal_VOID__OBJECT,
 
172
                  G_TYPE_NONE, 1,
 
173
                  GIMP_TYPE_DOCKBOOK);
 
174
 
 
175
  dock_signals[BOOK_REMOVED] =
 
176
    g_signal_new ("book_removed",
 
177
                  G_TYPE_FROM_CLASS (klass),
 
178
                  G_SIGNAL_RUN_FIRST,
 
179
                  G_STRUCT_OFFSET (GimpDockClass, book_removed),
 
180
                  NULL, NULL,
 
181
                  gimp_marshal_VOID__OBJECT,
 
182
                  G_TYPE_NONE, 1,
 
183
                  GIMP_TYPE_DOCKBOOK);
 
184
 
 
185
  object_class->constructor     = gimp_dock_constructor;
 
186
  object_class->set_property    = gimp_dock_set_property;
 
187
  object_class->get_property    = gimp_dock_get_property;
 
188
 
 
189
  gtk_object_class->destroy     = gimp_dock_destroy;
 
190
 
 
191
  widget_class->delete_event    = gimp_dock_delete_event;
 
192
  widget_class->key_press_event = gimp_dock_key_press_event;
 
193
  widget_class->style_set       = gimp_dock_style_set;
 
194
 
 
195
  klass->setup                  = NULL;
 
196
  klass->book_added             = gimp_dock_real_book_added;
 
197
  klass->book_removed           = gimp_dock_real_book_removed;
 
198
 
 
199
  g_object_class_install_property (object_class, PROP_CONTEXT,
 
200
                                   g_param_spec_object ("context", NULL, NULL,
 
201
                                                        GIMP_TYPE_CONTEXT,
 
202
                                                        G_PARAM_READWRITE |
 
203
                                                        G_PARAM_CONSTRUCT_ONLY));
 
204
  g_object_class_install_property (object_class, PROP_DIALOG_FACTORY,
 
205
                                   g_param_spec_object ("dialog-factory", NULL, NULL,
 
206
                                                        GIMP_TYPE_DIALOG_FACTORY,
 
207
                                                        G_PARAM_READWRITE |
 
208
                                                        G_PARAM_CONSTRUCT_ONLY));
 
209
 
 
210
  gtk_widget_class_install_style_property (widget_class,
 
211
                                           g_param_spec_int ("default_height",
 
212
                                                             NULL, NULL,
 
213
                                                             -1,
 
214
                                                             G_MAXINT,
 
215
                                                             DEFAULT_DOCK_HEIGHT,
 
216
                                                             G_PARAM_READABLE));
 
217
  gtk_widget_class_install_style_property (widget_class,
 
218
                                           g_param_spec_int ("separator_height",
 
219
                                                             NULL, NULL,
 
220
                                                             0,
 
221
                                                             G_MAXINT,
 
222
                                                             DEFAULT_SEPARATOR_HEIGHT,
 
223
                                                             G_PARAM_READABLE));
 
224
}
 
225
 
 
226
static void
 
227
gimp_dock_init (GimpDock *dock)
 
228
{
 
229
  GtkWidget *separator;
 
230
 
 
231
  dock->context = NULL;
 
232
 
 
233
  gtk_window_set_role (GTK_WINDOW (dock), "gimp-dock");
 
234
  gtk_window_set_resizable (GTK_WINDOW (dock), TRUE);
 
235
 
 
236
  dock->main_vbox = gtk_vbox_new (FALSE, 0);
 
237
  gtk_container_add (GTK_CONTAINER (dock), dock->main_vbox);
 
238
  gtk_widget_show (dock->main_vbox);
 
239
 
 
240
  dock->vbox = gtk_vbox_new (FALSE, 0);
 
241
  gtk_container_add (GTK_CONTAINER (dock->main_vbox), dock->vbox);
 
242
  gtk_widget_show (dock->vbox);
 
243
 
 
244
  separator = gimp_dock_separator_new (dock);
 
245
  gtk_box_pack_start (GTK_BOX (dock->vbox), separator, FALSE, FALSE, 0);
 
246
  gtk_widget_show (separator);
 
247
}
 
248
 
 
249
static void
 
250
gimp_dock_set_property (GObject      *object,
 
251
                        guint         property_id,
 
252
                        const GValue *value,
 
253
                        GParamSpec   *pspec)
 
254
{
 
255
  GimpDock *dock = GIMP_DOCK (object);
 
256
 
 
257
  switch (property_id)
 
258
    {
 
259
    case PROP_CONTEXT:
 
260
      dock->context = GIMP_CONTEXT (g_value_dup_object (value));
 
261
      break;
 
262
    case PROP_DIALOG_FACTORY:
 
263
      dock->dialog_factory = GIMP_DIALOG_FACTORY (g_value_get_object (value));
 
264
      break;
 
265
    default:
 
266
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
267
      break;
 
268
    }
 
269
}
 
270
 
 
271
static void
 
272
gimp_dock_get_property (GObject    *object,
 
273
                               guint       property_id,
 
274
                               GValue     *value,
 
275
                               GParamSpec *pspec)
 
276
{
 
277
  GimpDock *dock = GIMP_DOCK (object);
 
278
 
 
279
  switch (property_id)
 
280
    {
 
281
    case PROP_CONTEXT:
 
282
      g_value_set_object (value, dock->context);
 
283
      break;
 
284
    case PROP_DIALOG_FACTORY:
 
285
      g_value_set_object (value, dock->dialog_factory);
 
286
      break;
 
287
    default:
 
288
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
289
      break;
 
290
    }
 
291
}
 
292
 
 
293
static GObject *
 
294
gimp_dock_constructor (GType                  type,
 
295
                       guint                  n_params,
 
296
                       GObjectConstructParam *params)
 
297
{
 
298
  GObject       *object;
 
299
  GimpDock      *dock;
 
300
  GimpGuiConfig *config;
 
301
 
 
302
  object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params);
 
303
 
 
304
  dock = GIMP_DOCK (object);
 
305
 
 
306
  g_assert (GIMP_IS_CONTEXT (dock->context));
 
307
  g_assert (GIMP_IS_DIALOG_FACTORY (dock->dialog_factory));
 
308
 
 
309
  config = GIMP_GUI_CONFIG (dock->context->gimp->config);
 
310
 
 
311
  gimp_window_set_hint (GTK_WINDOW (dock), config->dock_window_hint);
 
312
 
 
313
  return object;
 
314
}
 
315
 
 
316
static void
 
317
gimp_dock_destroy (GtkObject *object)
 
318
{
 
319
  GimpDock *dock = GIMP_DOCK (object);
 
320
 
 
321
  while (dock->dockbooks)
 
322
    gimp_dock_remove_book (dock, GIMP_DOCKBOOK (dock->dockbooks->data));
 
323
 
 
324
  if (dock->context)
 
325
    {
 
326
      g_object_unref (dock->context);
 
327
      dock->context = NULL;
 
328
    }
 
329
 
 
330
  GTK_OBJECT_CLASS (parent_class)->destroy (object);
 
331
}
 
332
 
 
333
static gboolean
 
334
gimp_dock_delete_event (GtkWidget   *widget,
 
335
                        GdkEventAny *event)
 
336
{
 
337
  GimpDock *dock = GIMP_DOCK (widget);
 
338
  GList    *list;
 
339
  gboolean  retval = FALSE;
 
340
  gint      n;
 
341
 
 
342
  for (list = dock->dockbooks, n = 0; list; list = list->next)
 
343
    n += gtk_notebook_get_n_pages (GTK_NOTEBOOK (list->data));
 
344
 
 
345
  if (n > 1)
 
346
    {
 
347
      GtkWidget *dialog =
 
348
        gimp_message_dialog_new (_("Close all tabs?"),
 
349
                                 GIMP_STOCK_WARNING,
 
350
                                 widget, GTK_DIALOG_MODAL,
 
351
                                 NULL, NULL,
 
352
 
 
353
                                 GTK_STOCK_CANCEL,    GTK_RESPONSE_CANCEL,
 
354
                                 _("Close all Tabs"), GTK_RESPONSE_OK,
 
355
 
 
356
                                 NULL);
 
357
 
 
358
      gimp_message_box_set_primary_text (GIMP_MESSAGE_DIALOG (dialog)->box,
 
359
                                         _("Close all tabs?"));
 
360
      gimp_message_box_set_text (GIMP_MESSAGE_DIALOG (dialog)->box,
 
361
                                 _("This window has %d tabs open. Closing the "
 
362
                                   "window will also close all its tabs."), n);
 
363
 
 
364
      retval = (gimp_dialog_run (GIMP_DIALOG (dialog)) != GTK_RESPONSE_OK);
 
365
 
 
366
      gtk_widget_destroy (dialog);
 
367
    }
 
368
 
 
369
  return retval;
 
370
}
 
371
 
 
372
static gboolean
 
373
gimp_dock_key_press_event (GtkWidget   *widget,
 
374
                           GdkEventKey *event)
 
375
{
 
376
  GtkWindow *window  = GTK_WINDOW (widget);
 
377
  gboolean   handled = FALSE;
 
378
 
 
379
  /* we're overriding the GtkWindow implementation here to give
 
380
   * the focus widget precedence over unmodified accelerators
 
381
   * before the accelerator activation scheme.
 
382
   */
 
383
 
 
384
  /* invoke control/alt accelerators */
 
385
  if (! handled && event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK))
 
386
    handled = gtk_window_activate_key (window, event);
 
387
 
 
388
  /* invoke focus widget handlers */
 
389
  if (! handled)
 
390
    handled = gtk_window_propagate_key_event (window, event);
 
391
 
 
392
  /* invoke non-(control/alt) accelerators */
 
393
  if (! handled && ! (event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)))
 
394
    handled = gtk_window_activate_key (window, event);
 
395
 
 
396
  /* chain up, bypassing gtk_window_key_press(), to invoke binding set */
 
397
  if (! handled)
 
398
    handled = GTK_WIDGET_CLASS (g_type_class_peek (g_type_parent (GTK_TYPE_WINDOW)))->key_press_event (widget, event);
 
399
 
 
400
  return handled;
 
401
}
 
402
 
 
403
static void
 
404
gimp_dock_style_set (GtkWidget *widget,
 
405
                     GtkStyle  *prev_style)
 
406
{
 
407
  GimpDock *dock;
 
408
  GList    *children;
 
409
  GList    *list;
 
410
  gint      default_height;
 
411
  gint      separator_height;
 
412
 
 
413
  dock = GIMP_DOCK (widget);
 
414
 
 
415
  if (GTK_WIDGET_CLASS (parent_class)->style_set)
 
416
    GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
 
417
 
 
418
  gtk_widget_style_get (widget,
 
419
                        "default_height",   &default_height,
 
420
                        "separator_height", &separator_height,
 
421
                        NULL);
 
422
 
 
423
  gtk_window_set_default_size (GTK_WINDOW (widget), -1, default_height);
 
424
 
 
425
  children = gtk_container_get_children (GTK_CONTAINER (dock->vbox));
 
426
 
 
427
  for (list = children; list; list = g_list_next (list))
 
428
    {
 
429
      if (GTK_IS_EVENT_BOX (list->data))
 
430
        gtk_widget_set_size_request (GTK_WIDGET (list->data),
 
431
                                     -1, separator_height);
 
432
    }
 
433
 
 
434
  g_list_free (children);
 
435
}
 
436
 
 
437
static void
 
438
gimp_dock_real_book_added (GimpDock     *dock,
 
439
                           GimpDockbook *dockbook)
 
440
{
 
441
}
 
442
 
 
443
static void
 
444
gimp_dock_real_book_removed (GimpDock     *dock,
 
445
                             GimpDockbook *dockbook)
 
446
{
 
447
  if (dock->dockbooks == NULL)
 
448
    gtk_widget_destroy (GTK_WIDGET (dock));
 
449
}
 
450
 
 
451
static GtkWidget *
 
452
gimp_dock_separator_new (GimpDock *dock)
 
453
{
 
454
  GtkWidget  *event_box;
 
455
  GtkWidget  *frame;
 
456
  gint        separator_height;
 
457
 
 
458
  event_box = gtk_event_box_new ();
 
459
 
 
460
  gtk_widget_set_name (event_box, "gimp-dock-separator");
 
461
 
 
462
  gtk_widget_style_get (GTK_WIDGET (dock),
 
463
                        "separator_height", &separator_height,
 
464
                        NULL);
 
465
 
 
466
  gtk_widget_set_size_request (event_box, -1, separator_height);
 
467
 
 
468
  frame = gtk_frame_new (NULL);
 
469
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
 
470
  gtk_container_add (GTK_CONTAINER (event_box), frame);
 
471
  gtk_widget_show (frame);
 
472
 
 
473
  gimp_help_set_help_data (event_box,
 
474
                           _("You can drop dockable dialogs here."),
 
475
                           GIMP_HELP_DOCK_SEPARATOR);
 
476
 
 
477
  gtk_drag_dest_set (GTK_WIDGET (event_box),
 
478
                     GTK_DEST_DEFAULT_ALL,
 
479
                     dialog_target_table, G_N_ELEMENTS (dialog_target_table),
 
480
                     GDK_ACTION_MOVE);
 
481
 
 
482
  g_signal_connect (event_box, "drag_leave",
 
483
                    G_CALLBACK (gimp_dock_separator_drag_leave),
 
484
                    NULL);
 
485
  g_signal_connect (event_box, "drag_motion",
 
486
                    G_CALLBACK (gimp_dock_separator_drag_motion),
 
487
                    NULL);
 
488
  g_signal_connect (event_box, "drag_drop",
 
489
                    G_CALLBACK (gimp_dock_separator_drag_drop),
 
490
                    dock);
 
491
 
 
492
  return event_box;
 
493
}
 
494
 
 
495
void
 
496
gimp_dock_setup (GimpDock       *dock,
 
497
                 const GimpDock *template)
 
498
{
 
499
  g_return_if_fail (GIMP_IS_DOCK (dock));
 
500
  g_return_if_fail (GIMP_IS_DOCK (template));
 
501
 
 
502
  if (GIMP_DOCK_GET_CLASS (dock)->setup)
 
503
    GIMP_DOCK_GET_CLASS (dock)->setup (dock, template);
 
504
}
 
505
 
 
506
void
 
507
gimp_dock_set_aux_info (GimpDock *dock,
 
508
                        GList    *aux_info)
 
509
{
 
510
  g_return_if_fail (GIMP_IS_DOCK (dock));
 
511
 
 
512
  if (GIMP_DOCK_GET_CLASS (dock)->set_aux_info)
 
513
    GIMP_DOCK_GET_CLASS (dock)->set_aux_info (dock, aux_info);
 
514
}
 
515
 
 
516
GList *
 
517
gimp_dock_get_aux_info (GimpDock *dock)
 
518
{
 
519
  g_return_val_if_fail (GIMP_IS_DOCK (dock), NULL);
 
520
 
 
521
  if (GIMP_DOCK_GET_CLASS (dock)->get_aux_info)
 
522
    return GIMP_DOCK_GET_CLASS (dock)->get_aux_info (dock);
 
523
 
 
524
  return NULL;
 
525
}
 
526
 
 
527
void
 
528
gimp_dock_add (GimpDock     *dock,
 
529
               GimpDockable *dockable,
 
530
               gint          section,
 
531
               gint          position)
 
532
{
 
533
  GimpDockbook *dockbook;
 
534
 
 
535
  g_return_if_fail (GIMP_IS_DOCK (dock));
 
536
  g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
 
537
  g_return_if_fail (dockable->dockbook == NULL);
 
538
 
 
539
  dockbook = GIMP_DOCKBOOK (dock->dockbooks->data);
 
540
 
 
541
  gimp_dockbook_add (dockbook, dockable, position);
 
542
}
 
543
 
 
544
void
 
545
gimp_dock_remove (GimpDock     *dock,
 
546
                  GimpDockable *dockable)
 
547
{
 
548
  g_return_if_fail (GIMP_IS_DOCK (dock));
 
549
  g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
 
550
  g_return_if_fail (dockable->dockbook != NULL);
 
551
  g_return_if_fail (dockable->dockbook->dock == dock);
 
552
 
 
553
  gimp_dockbook_remove (dockable->dockbook, dockable);
 
554
}
 
555
 
 
556
void
 
557
gimp_dock_add_book (GimpDock     *dock,
 
558
                    GimpDockbook *dockbook,
 
559
                    gint          index)
 
560
{
 
561
  gint old_length;
 
562
 
 
563
  g_return_if_fail (GIMP_IS_DOCK (dock));
 
564
  g_return_if_fail (GIMP_IS_DOCKBOOK (dockbook));
 
565
  g_return_if_fail (dockbook->dock == NULL);
 
566
 
 
567
  old_length = g_list_length (dock->dockbooks);
 
568
 
 
569
  if (index >= old_length || index < 0)
 
570
    index = old_length;
 
571
 
 
572
  dockbook->dock  = dock;
 
573
  dock->dockbooks = g_list_insert (dock->dockbooks, dockbook, index);
 
574
 
 
575
  if (old_length == 0)
 
576
    {
 
577
      GtkWidget *separator;
 
578
 
 
579
      gtk_box_pack_start (GTK_BOX (dock->vbox), GTK_WIDGET (dockbook),
 
580
                          TRUE, TRUE, 0);
 
581
 
 
582
      separator = gimp_dock_separator_new (dock);
 
583
      gtk_box_pack_end (GTK_BOX (dock->vbox), separator, FALSE, FALSE, 0);
 
584
      gtk_widget_show (separator);
 
585
    }
 
586
  else
 
587
    {
 
588
      GtkWidget *old_book;
 
589
      GtkWidget *parent;
 
590
      GtkWidget *paned;
 
591
 
 
592
      if (index == 0)
 
593
        old_book = g_list_nth_data (dock->dockbooks, index + 1);
 
594
      else
 
595
        old_book = g_list_nth_data (dock->dockbooks, index - 1);
 
596
 
 
597
      parent = old_book->parent;
 
598
 
 
599
      if ((old_length > 1) && (index > 0))
 
600
        {
 
601
          GtkWidget *grandparent;
 
602
 
 
603
          grandparent = parent->parent;
 
604
 
 
605
          old_book = parent;
 
606
          parent   = grandparent;
 
607
        }
 
608
 
 
609
      g_object_ref (old_book);
 
610
 
 
611
      gtk_container_remove (GTK_CONTAINER (parent), old_book);
 
612
 
 
613
      paned = gtk_vpaned_new ();
 
614
 
 
615
      if (GTK_IS_VPANED (parent))
 
616
        gtk_paned_pack1 (GTK_PANED (parent), paned, TRUE, FALSE);
 
617
      else
 
618
        gtk_box_pack_start (GTK_BOX (parent), paned, TRUE, TRUE, 0);
 
619
 
 
620
      gtk_widget_show (paned);
 
621
 
 
622
      if (index == 0)
 
623
        {
 
624
          gtk_paned_pack1 (GTK_PANED (paned), GTK_WIDGET (dockbook),
 
625
                           TRUE, FALSE);
 
626
          gtk_paned_pack2 (GTK_PANED (paned), old_book,
 
627
                           TRUE, FALSE);
 
628
        }
 
629
      else
 
630
        {
 
631
          gtk_paned_pack1 (GTK_PANED (paned), old_book,
 
632
                           TRUE, FALSE);
 
633
          gtk_paned_pack2 (GTK_PANED (paned), GTK_WIDGET (dockbook),
 
634
                           TRUE, FALSE);
 
635
        }
 
636
 
 
637
      g_object_unref (old_book);
 
638
    }
 
639
 
 
640
  gtk_widget_show (GTK_WIDGET (dockbook));
 
641
 
 
642
  g_signal_emit (dock, dock_signals[BOOK_ADDED], 0, dockbook);
 
643
}
 
644
 
 
645
void
 
646
gimp_dock_remove_book (GimpDock     *dock,
 
647
                       GimpDockbook *dockbook)
 
648
{
 
649
  gint old_length;
 
650
  gint index;
 
651
 
 
652
  g_return_if_fail (GIMP_IS_DOCK (dock));
 
653
  g_return_if_fail (GIMP_IS_DOCKBOOK (dockbook));
 
654
 
 
655
  g_return_if_fail (dockbook->dock == dock);
 
656
 
 
657
  old_length = g_list_length (dock->dockbooks);
 
658
  index      = g_list_index (dock->dockbooks, dockbook);
 
659
 
 
660
  dockbook->dock  = NULL;
 
661
  dock->dockbooks = g_list_remove (dock->dockbooks, dockbook);
 
662
 
 
663
  g_object_ref (dockbook);
 
664
 
 
665
  if (old_length == 1)
 
666
    {
 
667
      GtkWidget *separator;
 
668
      GList     *children;
 
669
 
 
670
      children = gtk_container_get_children (GTK_CONTAINER (dock->vbox));
 
671
 
 
672
      separator = g_list_nth_data (children, 2);
 
673
 
 
674
      gtk_container_remove (GTK_CONTAINER (dock->vbox), separator);
 
675
      gtk_container_remove (GTK_CONTAINER (dock->vbox), GTK_WIDGET (dockbook));
 
676
 
 
677
      g_list_free (children);
 
678
    }
 
679
  else
 
680
    {
 
681
      GtkWidget *other_book;
 
682
      GtkWidget *parent;
 
683
      GtkWidget *grandparent;
 
684
 
 
685
      parent      = GTK_WIDGET (dockbook)->parent;
 
686
      grandparent = parent->parent;
 
687
 
 
688
      if (index == 0)
 
689
        other_book = GTK_PANED (parent)->child2;
 
690
      else
 
691
        other_book = GTK_PANED (parent)->child1;
 
692
 
 
693
      g_object_ref (other_book);
 
694
 
 
695
      gtk_container_remove (GTK_CONTAINER (parent), other_book);
 
696
      gtk_container_remove (GTK_CONTAINER (parent), GTK_WIDGET (dockbook));
 
697
 
 
698
      gtk_container_remove (GTK_CONTAINER (grandparent), parent);
 
699
 
 
700
      if (GTK_IS_VPANED (grandparent))
 
701
        gtk_paned_pack1 (GTK_PANED (grandparent), other_book, TRUE, FALSE);
 
702
      else
 
703
        gtk_box_pack_start (GTK_BOX (dock->vbox), other_book, TRUE, TRUE, 0);
 
704
 
 
705
      g_object_unref (other_book);
 
706
    }
 
707
 
 
708
  g_signal_emit (dock, dock_signals[BOOK_REMOVED], 0, dockbook);
 
709
 
 
710
  g_object_unref (dockbook);
 
711
}
 
712
 
 
713
static void
 
714
gimp_dock_separator_drag_leave (GtkWidget      *widget,
 
715
                                GdkDragContext *context,
 
716
                                guint           time,
 
717
                                gpointer        data)
 
718
{
 
719
  gtk_widget_modify_bg (widget, GTK_STATE_NORMAL, NULL);
 
720
}
 
721
 
 
722
static gboolean
 
723
gimp_dock_separator_drag_motion (GtkWidget      *widget,
 
724
                                 GdkDragContext *context,
 
725
                                 gint            x,
 
726
                                 gint            y,
 
727
                                 guint           time,
 
728
                                 gpointer        data)
 
729
{
 
730
  GdkColor *color = gtk_widget_get_style (widget)->bg + GTK_STATE_SELECTED;
 
731
 
 
732
  gtk_widget_modify_bg (widget, GTK_STATE_NORMAL, color);
 
733
 
 
734
  return FALSE;
 
735
}
 
736
 
 
737
static gboolean
 
738
gimp_dock_separator_drag_drop (GtkWidget      *widget,
 
739
                               GdkDragContext *context,
 
740
                               gint            x,
 
741
                               gint            y,
 
742
                               guint           time,
 
743
                               GimpDock       *dock)
 
744
{
 
745
  GtkWidget *source = gtk_drag_get_source_widget (context);
 
746
 
 
747
  if (source)
 
748
    {
 
749
      GimpDockable *dockable;
 
750
 
 
751
      if (GIMP_IS_DOCKABLE (source))
 
752
        dockable = GIMP_DOCKABLE (source);
 
753
      else
 
754
        dockable = (GimpDockable *) g_object_get_data (G_OBJECT (source),
 
755
                                                       "gimp-dockable");
 
756
 
 
757
      if (dockable)
 
758
        {
 
759
          GtkWidget *dockbook;
 
760
          GList     *children;
 
761
          gint       index;
 
762
 
 
763
          g_object_set_data (G_OBJECT (dockable),
 
764
                             "gimp-dock-drag-widget", NULL);
 
765
 
 
766
          children = gtk_container_get_children (GTK_CONTAINER (widget->parent));
 
767
          index = g_list_index (children, widget);
 
768
          g_list_free (children);
 
769
 
 
770
          if (index == 0)
 
771
            index = 0;
 
772
          else if (index == 2)
 
773
            index = -1;
 
774
 
 
775
          /*  if dropping to the same dock, take care that we don't try
 
776
           *  to reorder the *only* dockable in the dock
 
777
           */
 
778
          if (dockable->dockbook->dock == dock)
 
779
            {
 
780
              gint n_books;
 
781
              gint n_dockables;
 
782
 
 
783
              n_books = g_list_length (dock->dockbooks);
 
784
 
 
785
              children =
 
786
                gtk_container_get_children (GTK_CONTAINER (dockable->dockbook));
 
787
              n_dockables = g_list_length (children);
 
788
              g_list_free (children);
 
789
 
 
790
              if (n_books == 1 && n_dockables == 1)
 
791
                return TRUE; /* successfully do nothing */
 
792
            }
 
793
 
 
794
          g_object_ref (dockable);
 
795
 
 
796
          gimp_dockbook_remove (dockable->dockbook, dockable);
 
797
 
 
798
          dockbook = gimp_dockbook_new (dock->dialog_factory->menu_factory);
 
799
          gimp_dock_add_book (dock, GIMP_DOCKBOOK (dockbook), index);
 
800
 
 
801
          gimp_dockbook_add (GIMP_DOCKBOOK (dockbook), dockable, -1);
 
802
 
 
803
          g_object_unref (dockable);
 
804
 
 
805
          return TRUE;
 
806
        }
 
807
    }
 
808
 
 
809
  return FALSE;
 
810
}