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

« back to all changes in this revision

Viewing changes to app/widgets/gimpdockable.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
 * gimpdockable.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 "core/gimpcontext.h"
 
31
 
 
32
#include "gimpdialogfactory.h"
 
33
#include "gimpdnd.h"
 
34
#include "gimpdock.h"
 
35
#include "gimpdockable.h"
 
36
#include "gimpdockbook.h"
 
37
#include "gimpdocked.h"
 
38
#include "gimphelp-ids.h"
 
39
#include "gimpuimanager.h"
 
40
#include "gimpwidgets-utils.h"
 
41
 
 
42
#include "gimp-intl.h"
 
43
 
 
44
 
 
45
static void       gimp_dockable_class_init        (GimpDockableClass *klass);
 
46
static void       gimp_dockable_init              (GimpDockable      *dockable);
 
47
 
 
48
static void       gimp_dockable_destroy           (GtkObject      *object);
 
49
static void       gimp_dockable_size_request      (GtkWidget      *widget,
 
50
                                                   GtkRequisition *requisition);
 
51
static void       gimp_dockable_size_allocate     (GtkWidget      *widget,
 
52
                                                   GtkAllocation  *allocation);
 
53
static void       gimp_dockable_realize           (GtkWidget      *widget);
 
54
static void       gimp_dockable_unrealize         (GtkWidget      *widget);
 
55
static void       gimp_dockable_map               (GtkWidget      *widget);
 
56
static void       gimp_dockable_unmap             (GtkWidget      *widget);
 
57
 
 
58
static gboolean   gimp_dockable_drag_drop         (GtkWidget      *widget,
 
59
                                                   GdkDragContext *context,
 
60
                                                   gint            x,
 
61
                                                   gint            y,
 
62
                                                   guint           time);
 
63
static void       gimp_dockable_style_set         (GtkWidget      *widget,
 
64
                                                   GtkStyle       *prev_style);
 
65
static gboolean   gimp_dockable_expose_event      (GtkWidget      *widget,
 
66
                                                   GdkEventExpose *event);
 
67
static gboolean   gimp_dockable_drag_event_filter (GtkWidget      *widget,
 
68
                                                   GdkEventAny    *event);
 
69
static gboolean   gimp_dockable_popup_menu        (GtkWidget      *widget);
 
70
 
 
71
static void       gimp_dockable_add               (GtkContainer   *container,
 
72
                                                   GtkWidget      *widget);
 
73
static void       gimp_dockable_remove            (GtkContainer   *container,
 
74
                                                   GtkWidget      *widget);
 
75
static GType      gimp_dockable_child_type        (GtkContainer   *container);
 
76
static void       gimp_dockable_forall            (GtkContainer   *container,
 
77
                                                   gboolean       include_internals,
 
78
                                                   GtkCallback     callback,
 
79
                                                   gpointer        callback_data);
 
80
 
 
81
static void       gimp_dockable_get_title_area    (GimpDockable   *dockable,
 
82
                                                   GdkRectangle   *area);
 
83
 
 
84
static gboolean   gimp_dockable_menu_button_press (GtkWidget      *button,
 
85
                                                   GdkEventButton *bevent,
 
86
                                                   GimpDockable   *dockable);
 
87
static void       gimp_dockable_close_clicked     (GtkWidget      *button,
 
88
                                                   GimpDockable   *dockable);
 
89
static gboolean   gimp_dockable_show_menu         (GimpDockable   *dockable);
 
90
 
 
91
static void       gimp_dockable_title_changed     (GimpDocked     *docked,
 
92
                                                   GimpDockable   *dockable);
 
93
 
 
94
 
 
95
static GtkBinClass *parent_class = NULL;
 
96
 
 
97
static GtkTargetEntry dialog_target_table[] =
 
98
{
 
99
  GIMP_TARGET_DIALOG
 
100
};
 
101
 
 
102
 
 
103
GType
 
104
gimp_dockable_get_type (void)
 
105
{
 
106
  static GType dockable_type = 0;
 
107
 
 
108
  if (! dockable_type)
 
109
    {
 
110
      static const GTypeInfo dockable_info =
 
111
      {
 
112
        sizeof (GimpDockableClass),
 
113
        NULL,           /* base_init */
 
114
        NULL,           /* base_finalize */
 
115
        (GClassInitFunc) gimp_dockable_class_init,
 
116
        NULL,           /* class_finalize */
 
117
        NULL,           /* class_data */
 
118
        sizeof (GimpDockable),
 
119
        0,              /* n_preallocs */
 
120
        (GInstanceInitFunc) gimp_dockable_init,
 
121
      };
 
122
 
 
123
      dockable_type = g_type_register_static (GTK_TYPE_BIN,
 
124
                                              "GimpDockable",
 
125
                                              &dockable_info, 0);
 
126
    }
 
127
 
 
128
  return dockable_type;
 
129
}
 
130
 
 
131
static void
 
132
gimp_dockable_class_init (GimpDockableClass *klass)
 
133
{
 
134
  GtkObjectClass    *object_class    = GTK_OBJECT_CLASS (klass);
 
135
  GtkWidgetClass    *widget_class    = GTK_WIDGET_CLASS (klass);
 
136
  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
 
137
 
 
138
  parent_class = g_type_class_peek_parent (klass);
 
139
 
 
140
  object_class->destroy       = gimp_dockable_destroy;
 
141
 
 
142
  widget_class->size_request  = gimp_dockable_size_request;
 
143
  widget_class->size_allocate = gimp_dockable_size_allocate;
 
144
  widget_class->realize       = gimp_dockable_realize;
 
145
  widget_class->unrealize     = gimp_dockable_unrealize;
 
146
  widget_class->map           = gimp_dockable_map;
 
147
  widget_class->unmap         = gimp_dockable_unmap;
 
148
  widget_class->style_set     = gimp_dockable_style_set;
 
149
  widget_class->drag_drop     = gimp_dockable_drag_drop;
 
150
  widget_class->expose_event  = gimp_dockable_expose_event;
 
151
  widget_class->popup_menu    = gimp_dockable_popup_menu;
 
152
 
 
153
  container_class->add        = gimp_dockable_add;
 
154
  container_class->remove     = gimp_dockable_remove;
 
155
  container_class->child_type = gimp_dockable_child_type;
 
156
  container_class->forall     = gimp_dockable_forall;
 
157
 
 
158
  gtk_widget_class_install_style_property (widget_class,
 
159
                                           g_param_spec_int ("content_border",
 
160
                                                             NULL, NULL,
 
161
                                                             0,
 
162
                                                             G_MAXINT,
 
163
                                                             0,
 
164
                                                             G_PARAM_READABLE));
 
165
}
 
166
 
 
167
static void
 
168
gimp_dockable_init (GimpDockable *dockable)
 
169
{
 
170
  GtkWidget *image;
 
171
 
 
172
  dockable->name         = NULL;
 
173
  dockable->blurb        = NULL;
 
174
  dockable->stock_id     = NULL;
 
175
  dockable->help_id      = NULL;
 
176
  dockable->tab_style    = GIMP_TAB_STYLE_PREVIEW;
 
177
  dockable->dockbook     = NULL;
 
178
  dockable->context      = NULL;
 
179
 
 
180
  dockable->title_layout = NULL;
 
181
  dockable->title_window = NULL;
 
182
 
 
183
  gtk_widget_push_composite_child ();
 
184
  dockable->menu_button = gtk_button_new ();
 
185
  gtk_widget_pop_composite_child ();
 
186
 
 
187
  GTK_WIDGET_UNSET_FLAGS (dockable->menu_button, GTK_CAN_FOCUS);
 
188
  gtk_widget_set_parent (dockable->menu_button, GTK_WIDGET (dockable));
 
189
  gtk_button_set_relief (GTK_BUTTON (dockable->menu_button), GTK_RELIEF_NONE);
 
190
  gtk_widget_show (dockable->menu_button);
 
191
 
 
192
  image = gtk_image_new_from_stock (GIMP_STOCK_MENU_LEFT, GTK_ICON_SIZE_MENU);
 
193
  gtk_container_add (GTK_CONTAINER (dockable->menu_button), image);
 
194
  gtk_widget_show (image);
 
195
 
 
196
  g_signal_connect (dockable->menu_button, "button_press_event",
 
197
                    G_CALLBACK (gimp_dockable_menu_button_press),
 
198
                    dockable);
 
199
 
 
200
  gtk_widget_push_composite_child ();
 
201
  dockable->close_button = gtk_button_new ();
 
202
  gtk_widget_pop_composite_child ();
 
203
 
 
204
  GTK_WIDGET_UNSET_FLAGS (dockable->close_button, GTK_CAN_FOCUS);
 
205
  gtk_widget_set_parent (dockable->close_button, GTK_WIDGET (dockable));
 
206
  gtk_button_set_relief (GTK_BUTTON (dockable->close_button), GTK_RELIEF_NONE);
 
207
  gtk_widget_show (dockable->close_button);
 
208
 
 
209
  gimp_help_set_help_data (dockable->close_button, _("Close this Tab"),
 
210
                           GIMP_HELP_DOCK_TAB_CLOSE);
 
211
 
 
212
  image = gtk_image_new_from_stock (GIMP_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
 
213
  gtk_container_add (GTK_CONTAINER (dockable->close_button), image);
 
214
  gtk_widget_show (image);
 
215
 
 
216
  g_signal_connect (dockable->close_button, "clicked",
 
217
                    G_CALLBACK (gimp_dockable_close_clicked),
 
218
                    dockable);
 
219
 
 
220
  gtk_drag_dest_set (GTK_WIDGET (dockable),
 
221
                     GTK_DEST_DEFAULT_ALL,
 
222
                     dialog_target_table, G_N_ELEMENTS (dialog_target_table),
 
223
                     GDK_ACTION_MOVE);
 
224
 
 
225
  /*  Filter out all button_press events not coming from the event window
 
226
      over the title area.  This keeps events that originate from widgets
 
227
      in the dockable to start a drag.
 
228
   */
 
229
  g_signal_connect (dockable, "button_press_event",
 
230
                    G_CALLBACK (gimp_dockable_drag_event_filter),
 
231
                    NULL);
 
232
}
 
233
 
 
234
static void
 
235
gimp_dockable_destroy (GtkObject *object)
 
236
{
 
237
  GimpDockable *dockable = GIMP_DOCKABLE (object);
 
238
 
 
239
  if (dockable->context)
 
240
    gimp_dockable_set_context (dockable, NULL);
 
241
 
 
242
  if (dockable->blurb && dockable->blurb != dockable->name)
 
243
    {
 
244
      g_free (dockable->blurb);
 
245
      dockable->blurb = NULL;
 
246
    }
 
247
 
 
248
  if (dockable->name)
 
249
    {
 
250
      g_free (dockable->name);
 
251
      dockable->name = NULL;
 
252
    }
 
253
 
 
254
  if (dockable->stock_id)
 
255
    {
 
256
      g_free (dockable->stock_id);
 
257
      dockable->stock_id = NULL;
 
258
    }
 
259
 
 
260
  if (dockable->help_id)
 
261
    {
 
262
      g_free (dockable->help_id);
 
263
      dockable->help_id = NULL;
 
264
    }
 
265
 
 
266
  if (dockable->title_layout)
 
267
    {
 
268
      g_object_unref (dockable->title_layout);
 
269
      dockable->title_layout = NULL;
 
270
    }
 
271
 
 
272
  if (dockable->menu_button)
 
273
    {
 
274
      gtk_widget_unparent (dockable->menu_button);
 
275
      dockable->menu_button = NULL;
 
276
    }
 
277
 
 
278
  if (dockable->close_button)
 
279
    {
 
280
      gtk_widget_unparent (dockable->close_button);
 
281
      dockable->close_button = NULL;
 
282
    }
 
283
 
 
284
  GTK_OBJECT_CLASS (parent_class)->destroy (object);
 
285
}
 
286
 
 
287
static void
 
288
gimp_dockable_size_request (GtkWidget      *widget,
 
289
                            GtkRequisition *requisition)
 
290
{
 
291
  GtkContainer   *container = GTK_CONTAINER (widget);
 
292
  GtkBin         *bin       = GTK_BIN (widget);
 
293
  GimpDockable   *dockable  = GIMP_DOCKABLE (widget);
 
294
 
 
295
  GtkRequisition  child_requisition;
 
296
 
 
297
  requisition->width  = container->border_width * 2;
 
298
  requisition->height = container->border_width * 2;
 
299
 
 
300
  if (dockable->close_button && GTK_WIDGET_VISIBLE (dockable->close_button))
 
301
    {
 
302
      gtk_widget_size_request (dockable->close_button, &child_requisition);
 
303
 
 
304
      if (! bin->child)
 
305
        requisition->width += child_requisition.width;
 
306
 
 
307
      requisition->height += child_requisition.height;
 
308
    }
 
309
 
 
310
  if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
 
311
    {
 
312
      gtk_widget_size_request (bin->child, &child_requisition);
 
313
 
 
314
      requisition->width  += child_requisition.width;
 
315
      requisition->height += child_requisition.height;
 
316
    }
 
317
}
 
318
 
 
319
static void
 
320
gimp_dockable_size_allocate (GtkWidget     *widget,
 
321
                             GtkAllocation *allocation)
 
322
{
 
323
  GtkContainer   *container = GTK_CONTAINER (widget);
 
324
  GtkBin         *bin       = GTK_BIN (widget);
 
325
  GimpDockable   *dockable  = GIMP_DOCKABLE (widget);
 
326
 
 
327
  GtkRequisition  button_requisition = { 0, };
 
328
  GtkAllocation   child_allocation;
 
329
 
 
330
  container = GTK_CONTAINER (widget);
 
331
  bin       = GTK_BIN (widget);
 
332
  dockable  = GIMP_DOCKABLE (widget);
 
333
 
 
334
  widget->allocation = *allocation;
 
335
 
 
336
  if (dockable->close_button)
 
337
    {
 
338
      gtk_widget_size_request (dockable->close_button, &button_requisition);
 
339
 
 
340
      if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
 
341
        child_allocation.x    = (allocation->x +
 
342
                                 allocation->width -
 
343
                                 container->border_width -
 
344
                                 button_requisition.width);
 
345
      else
 
346
        child_allocation.x    = allocation->x + container->border_width;
 
347
 
 
348
      child_allocation.y      = allocation->y + container->border_width;
 
349
      child_allocation.width  = button_requisition.width;
 
350
      child_allocation.height = button_requisition.height;
 
351
 
 
352
      gtk_widget_size_allocate (dockable->close_button, &child_allocation);
 
353
    }
 
354
 
 
355
  if (dockable->menu_button)
 
356
    {
 
357
      if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
 
358
        child_allocation.x    = (allocation->x +
 
359
                                 allocation->width -
 
360
                                 container->border_width -
 
361
                                 2 * button_requisition.width);
 
362
      else
 
363
        child_allocation.x    = (allocation->x + container->border_width +
 
364
                                 button_requisition.width);
 
365
 
 
366
      child_allocation.y      = allocation->y + container->border_width;
 
367
      child_allocation.width  = button_requisition.width;
 
368
      child_allocation.height = button_requisition.height;
 
369
 
 
370
      gtk_widget_size_allocate (dockable->menu_button, &child_allocation);
 
371
    }
 
372
 
 
373
  if (bin->child)
 
374
    {
 
375
      child_allocation.x      = allocation->x + container->border_width;
 
376
      child_allocation.y      = allocation->y + container->border_width;
 
377
      child_allocation.width  = MAX (allocation->width  -
 
378
                                     container->border_width * 2,
 
379
                                     0);
 
380
      child_allocation.height = MAX (allocation->height -
 
381
                                     container->border_width * 2 -
 
382
                                     button_requisition.height,
 
383
                                     0);
 
384
 
 
385
      child_allocation.y += button_requisition.height;
 
386
 
 
387
      gtk_widget_size_allocate (bin->child, &child_allocation);
 
388
    }
 
389
 
 
390
  if (dockable->title_window)
 
391
    {
 
392
      GdkRectangle  area;
 
393
 
 
394
      gimp_dockable_get_title_area (dockable, &area);
 
395
 
 
396
      gdk_window_move_resize (dockable->title_window,
 
397
                              area.x, area.y, area.width, area.height);
 
398
    }
 
399
}
 
400
 
 
401
static void
 
402
gimp_dockable_realize (GtkWidget *widget)
 
403
{
 
404
  GimpDockable *dockable = GIMP_DOCKABLE (widget);
 
405
 
 
406
  GTK_WIDGET_CLASS (parent_class)->realize (widget);
 
407
 
 
408
  if (! dockable->title_window)
 
409
    {
 
410
      GdkWindowAttr  attributes;
 
411
      GdkRectangle   area;
 
412
      GdkCursor     *cursor;
 
413
 
 
414
      gimp_dockable_get_title_area (dockable, &area);
 
415
 
 
416
      attributes.x                 = area.x;
 
417
      attributes.y                 = area.y;
 
418
      attributes.width             = area.width;
 
419
      attributes.height            = area.height;
 
420
      attributes.window_type       = GDK_WINDOW_TEMP;
 
421
      attributes.wclass            = GDK_INPUT_ONLY;
 
422
      attributes.override_redirect = TRUE;
 
423
      attributes.event_mask        = (GDK_BUTTON_PRESS_MASK   |
 
424
                                      GDK_BUTTON_RELEASE_MASK |
 
425
                                      GDK_BUTTON_MOTION_MASK  |
 
426
                                      gtk_widget_get_events (widget));
 
427
 
 
428
      dockable->title_window = gdk_window_new (widget->window,
 
429
                                               &attributes,
 
430
                                               (GDK_WA_X |
 
431
                                                GDK_WA_Y |
 
432
                                                GDK_WA_NOREDIR));
 
433
 
 
434
      gdk_window_set_user_data (dockable->title_window, widget);
 
435
 
 
436
      cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
 
437
                                           GDK_HAND2);
 
438
      gdk_window_set_cursor (dockable->title_window, cursor);
 
439
      gdk_cursor_unref (cursor);
 
440
    }
 
441
}
 
442
 
 
443
static void
 
444
gimp_dockable_unrealize (GtkWidget *widget)
 
445
{
 
446
  GimpDockable *dockable = GIMP_DOCKABLE (widget);
 
447
 
 
448
  if (dockable->title_window)
 
449
    {
 
450
      gdk_window_set_user_data (dockable->title_window, NULL);
 
451
      gdk_window_destroy (dockable->title_window);
 
452
      dockable->title_window = NULL;
 
453
    }
 
454
 
 
455
  GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
 
456
}
 
457
 
 
458
static void
 
459
gimp_dockable_map (GtkWidget *widget)
 
460
{
 
461
  GimpDockable *dockable = GIMP_DOCKABLE (widget);
 
462
 
 
463
  GTK_WIDGET_CLASS (parent_class)->map (widget);
 
464
 
 
465
  if (dockable->title_window)
 
466
    gdk_window_show (dockable->title_window);
 
467
}
 
468
 
 
469
static void
 
470
gimp_dockable_unmap (GtkWidget *widget)
 
471
{
 
472
  GimpDockable *dockable = GIMP_DOCKABLE (widget);
 
473
 
 
474
  if (dockable->title_window)
 
475
    gdk_window_hide (dockable->title_window);
 
476
 
 
477
  GTK_WIDGET_CLASS (parent_class)->unmap (widget);
 
478
}
 
479
 
 
480
static gboolean
 
481
gimp_dockable_drag_drop (GtkWidget      *widget,
 
482
                         GdkDragContext *context,
 
483
                         gint            x,
 
484
                         gint            y,
 
485
                         guint           time)
 
486
{
 
487
  return gimp_dockbook_drop_dockable (GIMP_DOCKABLE (widget)->dockbook,
 
488
                                      gtk_drag_get_source_widget (context));
 
489
}
 
490
 
 
491
static void
 
492
gimp_dockable_style_set (GtkWidget *widget,
 
493
                         GtkStyle  *prev_style)
 
494
{
 
495
  GimpDockable *dockable;
 
496
  gint          content_border;
 
497
 
 
498
  gtk_widget_style_get (widget,
 
499
                        "content_border", &content_border,
 
500
                        NULL);
 
501
 
 
502
  gtk_container_set_border_width (GTK_CONTAINER (widget), content_border);
 
503
 
 
504
  dockable = GIMP_DOCKABLE (widget);
 
505
 
 
506
  if (dockable->title_layout)
 
507
    {
 
508
      g_object_unref (dockable->title_layout);
 
509
      dockable->title_layout = NULL;
 
510
    }
 
511
 
 
512
  if (GTK_WIDGET_CLASS (parent_class)->style_set)
 
513
    GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
 
514
}
 
515
 
 
516
static gboolean
 
517
gimp_dockable_expose_event (GtkWidget      *widget,
 
518
                            GdkEventExpose *event)
 
519
{
 
520
  if (GTK_WIDGET_DRAWABLE (widget))
 
521
    {
 
522
      GimpDockable *dockable  = GIMP_DOCKABLE (widget);
 
523
      GdkRectangle  title_area;
 
524
      GdkRectangle  expose_area;
 
525
 
 
526
      gimp_dockable_get_title_area (dockable, &title_area);
 
527
 
 
528
      if (gdk_rectangle_intersect (&title_area, &event->area, &expose_area))
 
529
        {
 
530
          gint layout_width;
 
531
          gint layout_height;
 
532
          gint text_x;
 
533
          gint text_y;
 
534
 
 
535
          if (! dockable->title_layout)
 
536
            {
 
537
              GtkBin *bin   = GTK_BIN (dockable);
 
538
              gchar  *title = NULL;
 
539
 
 
540
              if (bin->child)
 
541
                title = gimp_docked_get_title (GIMP_DOCKED (bin->child));
 
542
 
 
543
              if (! title)
 
544
                title = g_strdup (dockable->blurb);
 
545
 
 
546
              dockable->title_layout = gtk_widget_create_pango_layout (widget,
 
547
                                                                       title);
 
548
 
 
549
              g_free (title);
 
550
            }
 
551
 
 
552
          pango_layout_get_pixel_size (dockable->title_layout,
 
553
                                       &layout_width, &layout_height);
 
554
 
 
555
          if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
 
556
            {
 
557
              text_x = title_area.x;
 
558
            }
 
559
          else
 
560
            {
 
561
              text_x = title_area.x + title_area.width - layout_width;
 
562
            }
 
563
 
 
564
          text_y = title_area.y + (title_area.height - layout_height) / 2;
 
565
 
 
566
          gtk_paint_layout (widget->style, widget->window,
 
567
                            widget->state, TRUE,
 
568
                            &expose_area, widget, NULL,
 
569
                            text_x, text_y, dockable->title_layout);
 
570
        }
 
571
    }
 
572
 
 
573
  return GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
 
574
}
 
575
 
 
576
static gboolean
 
577
gimp_dockable_drag_event_filter (GtkWidget   *widget,
 
578
                                 GdkEventAny *event)
 
579
{
 
580
  /*  stop processing of events not coming from the title event window  */
 
581
  return (event->window != GIMP_DOCKABLE (widget)->title_window);
 
582
}
 
583
 
 
584
static gboolean
 
585
gimp_dockable_popup_menu (GtkWidget *widget)
 
586
{
 
587
  return gimp_dockable_show_menu (GIMP_DOCKABLE (widget));
 
588
}
 
589
 
 
590
static void
 
591
gimp_dockable_add (GtkContainer *container,
 
592
                   GtkWidget    *widget)
 
593
{
 
594
  g_return_if_fail (GTK_BIN (container)->child == NULL);
 
595
 
 
596
  GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
 
597
 
 
598
  g_signal_connect (widget, "title_changed",
 
599
                    G_CALLBACK (gimp_dockable_title_changed),
 
600
                    container);
 
601
}
 
602
 
 
603
static void
 
604
gimp_dockable_remove (GtkContainer *container,
 
605
                      GtkWidget    *widget)
 
606
{
 
607
  g_return_if_fail (GTK_BIN (container)->child == widget);
 
608
 
 
609
  g_signal_handlers_disconnect_by_func (widget,
 
610
                                        gimp_dockable_title_changed,
 
611
                                        container);
 
612
 
 
613
  GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
 
614
}
 
615
 
 
616
static GType
 
617
gimp_dockable_child_type (GtkContainer *container)
 
618
{
 
619
  if (GTK_BIN (container)->child)
 
620
    return G_TYPE_NONE;
 
621
 
 
622
  return GIMP_TYPE_DOCKED;
 
623
}
 
624
 
 
625
static void
 
626
gimp_dockable_forall (GtkContainer *container,
 
627
                      gboolean      include_internals,
 
628
                      GtkCallback   callback,
 
629
                      gpointer      callback_data)
 
630
{
 
631
  GimpDockable *dockable = GIMP_DOCKABLE (container);
 
632
 
 
633
  if (include_internals)
 
634
    {
 
635
      if (dockable->menu_button)
 
636
        (* callback) (dockable->menu_button, callback_data);
 
637
 
 
638
      if (dockable->close_button)
 
639
        (* callback) (dockable->close_button, callback_data);
 
640
    }
 
641
 
 
642
  GTK_CONTAINER_CLASS (parent_class)->forall (container, include_internals,
 
643
                                              callback, callback_data);
 
644
}
 
645
 
 
646
GtkWidget *
 
647
gimp_dockable_new (const gchar *name,
 
648
                   const gchar *blurb,
 
649
                   const gchar *stock_id,
 
650
                   const gchar *help_id)
 
651
{
 
652
  GimpDockable *dockable;
 
653
 
 
654
  g_return_val_if_fail (name != NULL, NULL);
 
655
  g_return_val_if_fail (stock_id != NULL, NULL);
 
656
  g_return_val_if_fail (help_id != NULL, NULL);
 
657
 
 
658
  dockable = g_object_new (GIMP_TYPE_DOCKABLE, NULL);
 
659
 
 
660
  dockable->name     = g_strdup (name);
 
661
  dockable->stock_id = g_strdup (stock_id);
 
662
  dockable->help_id  = g_strdup (help_id);
 
663
 
 
664
  if (blurb)
 
665
    dockable->blurb  = g_strdup (blurb);
 
666
  else
 
667
    dockable->blurb  = dockable->name;
 
668
 
 
669
  gimp_help_set_help_data (GTK_WIDGET (dockable), NULL, help_id);
 
670
 
 
671
  return GTK_WIDGET (dockable);
 
672
}
 
673
 
 
674
void
 
675
gimp_dockable_set_aux_info (GimpDockable *dockable,
 
676
                            GList        *aux_info)
 
677
{
 
678
  g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
 
679
 
 
680
  if (GTK_BIN (dockable)->child)
 
681
    gimp_docked_set_aux_info (GIMP_DOCKED (GTK_BIN (dockable)->child),
 
682
                              aux_info);
 
683
}
 
684
 
 
685
GList *
 
686
gimp_dockable_get_aux_info (GimpDockable *dockable)
 
687
{
 
688
  g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), NULL);
 
689
 
 
690
 
 
691
  if (GTK_BIN (dockable)->child)
 
692
    return gimp_docked_get_aux_info (GIMP_DOCKED (GTK_BIN (dockable)->child));
 
693
 
 
694
  return NULL;
 
695
}
 
696
 
 
697
void
 
698
gimp_dockable_set_tab_style (GimpDockable *dockable,
 
699
                             GimpTabStyle  tab_style)
 
700
{
 
701
  g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
 
702
 
 
703
  if (GTK_BIN (dockable)->child &&
 
704
      ! GIMP_DOCKED_GET_INTERFACE (GTK_BIN (dockable)->child)->get_preview)
 
705
    {
 
706
      switch (tab_style)
 
707
        {
 
708
        case GIMP_TAB_STYLE_PREVIEW:
 
709
          tab_style = GIMP_TAB_STYLE_ICON;
 
710
          break;
 
711
 
 
712
        case GIMP_TAB_STYLE_PREVIEW_NAME:
 
713
          tab_style = GIMP_TAB_STYLE_ICON_BLURB;
 
714
          break;
 
715
 
 
716
        case GIMP_TAB_STYLE_PREVIEW_BLURB:
 
717
          tab_style = GIMP_TAB_STYLE_ICON_BLURB;
 
718
          break;
 
719
 
 
720
        default:
 
721
          break;
 
722
        }
 
723
    }
 
724
 
 
725
  dockable->tab_style = tab_style;
 
726
}
 
727
 
 
728
GtkWidget *
 
729
gimp_dockable_get_tab_widget (GimpDockable *dockable,
 
730
                              GimpContext  *context,
 
731
                              GimpTabStyle  tab_style,
 
732
                              GtkIconSize   size)
 
733
{
 
734
  GtkWidget *tab_widget = NULL;
 
735
  GtkWidget *label      = NULL;
 
736
  GtkWidget *icon       = NULL;
 
737
 
 
738
  g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), NULL);
 
739
  g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
 
740
 
 
741
  switch (tab_style)
 
742
    {
 
743
    case GIMP_TAB_STYLE_NAME:
 
744
    case GIMP_TAB_STYLE_ICON_NAME:
 
745
    case GIMP_TAB_STYLE_PREVIEW_NAME:
 
746
      label = gtk_label_new (dockable->name);
 
747
      break;
 
748
 
 
749
    case GIMP_TAB_STYLE_BLURB:
 
750
    case GIMP_TAB_STYLE_ICON_BLURB:
 
751
    case GIMP_TAB_STYLE_PREVIEW_BLURB:
 
752
      label = gtk_label_new (dockable->blurb);
 
753
      break;
 
754
 
 
755
    default:
 
756
      break;
 
757
    }
 
758
 
 
759
  switch (tab_style)
 
760
    {
 
761
    case GIMP_TAB_STYLE_ICON:
 
762
    case GIMP_TAB_STYLE_ICON_NAME:
 
763
    case GIMP_TAB_STYLE_ICON_BLURB:
 
764
      icon = gtk_image_new_from_stock (dockable->stock_id, size);
 
765
      break;
 
766
 
 
767
    case GIMP_TAB_STYLE_PREVIEW:
 
768
    case GIMP_TAB_STYLE_PREVIEW_NAME:
 
769
    case GIMP_TAB_STYLE_PREVIEW_BLURB:
 
770
      if (GTK_BIN (dockable)->child)
 
771
        icon = gimp_docked_get_preview (GIMP_DOCKED (GTK_BIN (dockable)->child),
 
772
                                        context, size);
 
773
 
 
774
      if (! icon)
 
775
        icon = gtk_image_new_from_stock (dockable->stock_id, size);
 
776
      break;
 
777
 
 
778
    default:
 
779
      break;
 
780
    }
 
781
 
 
782
  switch (tab_style)
 
783
    {
 
784
    case GIMP_TAB_STYLE_ICON:
 
785
    case GIMP_TAB_STYLE_PREVIEW:
 
786
      tab_widget = icon;
 
787
      break;
 
788
 
 
789
    case GIMP_TAB_STYLE_NAME:
 
790
    case GIMP_TAB_STYLE_BLURB:
 
791
      tab_widget = label;
 
792
      break;
 
793
 
 
794
    case GIMP_TAB_STYLE_ICON_NAME:
 
795
    case GIMP_TAB_STYLE_ICON_BLURB:
 
796
    case GIMP_TAB_STYLE_PREVIEW_NAME:
 
797
    case GIMP_TAB_STYLE_PREVIEW_BLURB:
 
798
      tab_widget = gtk_hbox_new (FALSE, 2);
 
799
 
 
800
      gtk_box_pack_start (GTK_BOX (tab_widget), icon, FALSE, FALSE, 0);
 
801
      gtk_widget_show (icon);
 
802
 
 
803
      gtk_box_pack_start (GTK_BOX (tab_widget), label, FALSE, FALSE, 0);
 
804
      gtk_widget_show (label);
 
805
      break;
 
806
    }
 
807
 
 
808
  return tab_widget;
 
809
}
 
810
 
 
811
void
 
812
gimp_dockable_set_context (GimpDockable *dockable,
 
813
                           GimpContext  *context)
 
814
{
 
815
  g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
 
816
  g_return_if_fail (context == NULL || GIMP_IS_CONTEXT (context));
 
817
 
 
818
  if (context != dockable->context)
 
819
    {
 
820
      if (GTK_BIN (dockable)->child)
 
821
        gimp_docked_set_context (GIMP_DOCKED (GTK_BIN (dockable)->child),
 
822
                                 context);
 
823
 
 
824
      dockable->context = context;
 
825
    }
 
826
}
 
827
 
 
828
GimpUIManager *
 
829
gimp_dockable_get_menu (GimpDockable  *dockable,
 
830
                        const gchar  **ui_path,
 
831
                        gpointer      *popup_data)
 
832
{
 
833
  g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), NULL);
 
834
  g_return_val_if_fail (ui_path != NULL, NULL);
 
835
  g_return_val_if_fail (popup_data != NULL, NULL);
 
836
 
 
837
  if (GTK_BIN (dockable)->child)
 
838
    return gimp_docked_get_menu (GIMP_DOCKED (GTK_BIN (dockable)->child),
 
839
                                 ui_path, popup_data);
 
840
 
 
841
  return NULL;
 
842
}
 
843
 
 
844
void
 
845
gimp_dockable_detach (GimpDockable *dockable)
 
846
{
 
847
  GimpDock  *src_dock;
 
848
  GtkWidget *dock;
 
849
  GtkWidget *dockbook;
 
850
 
 
851
  g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
 
852
  g_return_if_fail (GIMP_IS_DOCKBOOK (dockable->dockbook));
 
853
 
 
854
  src_dock = dockable->dockbook->dock;
 
855
 
 
856
  dock = gimp_dialog_factory_dock_new (src_dock->dialog_factory,
 
857
                                       gtk_widget_get_screen (GTK_WIDGET (dockable)));
 
858
  gimp_dock_setup (GIMP_DOCK (dock), src_dock);
 
859
 
 
860
  dockbook = gimp_dockbook_new (GIMP_DOCK (dock)->dialog_factory->menu_factory);
 
861
 
 
862
  gimp_dock_add_book (GIMP_DOCK (dock), GIMP_DOCKBOOK (dockbook), 0);
 
863
 
 
864
  g_object_ref (dockable);
 
865
 
 
866
  gimp_dockbook_remove (dockable->dockbook, dockable);
 
867
  gimp_dockbook_add (GIMP_DOCKBOOK (dockbook), dockable, 0);
 
868
 
 
869
  g_object_unref (dockable);
 
870
 
 
871
  gtk_widget_show (dock);
 
872
}
 
873
 
 
874
static void
 
875
gimp_dockable_get_title_area (GimpDockable *dockable,
 
876
                              GdkRectangle *area)
 
877
{
 
878
  GtkWidget *widget = GTK_WIDGET (dockable);
 
879
  gint       border = GTK_CONTAINER (dockable)->border_width;
 
880
 
 
881
  area->x      = widget->allocation.x + border;
 
882
  area->y      = widget->allocation.y + border;
 
883
  area->width  = (widget->allocation.width -
 
884
                  2 * border -
 
885
                  2 * dockable->close_button->allocation.width);
 
886
  area->height = dockable->close_button->allocation.height;
 
887
 
 
888
  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
 
889
    area->x += 2 * dockable->close_button->allocation.width;
 
890
}
 
891
 
 
892
static gboolean
 
893
gimp_dockable_menu_button_press (GtkWidget      *button,
 
894
                                 GdkEventButton *bevent,
 
895
                                 GimpDockable   *dockable)
 
896
{
 
897
  if (bevent->button == 1 && bevent->type == GDK_BUTTON_PRESS)
 
898
    {
 
899
      return gimp_dockable_show_menu (dockable);
 
900
    }
 
901
 
 
902
  return FALSE;
 
903
}
 
904
 
 
905
static void
 
906
gimp_dockable_close_clicked (GtkWidget    *button,
 
907
                             GimpDockable *dockable)
 
908
{
 
909
  gimp_dockbook_remove (dockable->dockbook, dockable);
 
910
}
 
911
 
 
912
static void
 
913
gimp_dockable_menu_position (GtkMenu  *menu,
 
914
                             gint     *x,
 
915
                             gint     *y,
 
916
                             gpointer  data)
 
917
{
 
918
  GimpDockable *dockable = GIMP_DOCKABLE (data);
 
919
 
 
920
  gimp_button_menu_position (dockable->menu_button, menu, GTK_POS_LEFT, x, y);
 
921
}
 
922
 
 
923
#define GIMP_DOCKABLE_DETACH_REF_KEY "gimp-dockable-detach-ref"
 
924
 
 
925
static void
 
926
gimp_dockable_menu_end (GimpDockable *dockable)
 
927
{
 
928
  GimpUIManager   *dialog_ui_manager;
 
929
  const gchar     *dialog_ui_path;
 
930
  gpointer         dialog_popup_data;
 
931
 
 
932
  dialog_ui_manager = gimp_dockable_get_menu (dockable,
 
933
                                              &dialog_ui_path,
 
934
                                              &dialog_popup_data);
 
935
 
 
936
  if (dialog_ui_manager && dialog_ui_path)
 
937
    {
 
938
      GtkWidget *child_menu_widget;
 
939
 
 
940
      child_menu_widget = gimp_ui_manager_ui_get (dialog_ui_manager,
 
941
                                                  dialog_ui_path);
 
942
 
 
943
      if (child_menu_widget)
 
944
        gtk_menu_detach (GTK_MENU (child_menu_widget));
 
945
    }
 
946
 
 
947
  /*  release gimp_dockable_show_menu()'s references  */
 
948
  g_object_set_data (G_OBJECT (dockable), GIMP_DOCKABLE_DETACH_REF_KEY, NULL);
 
949
  g_object_unref (dockable);
 
950
}
 
951
 
 
952
static gboolean
 
953
gimp_dockable_show_menu (GimpDockable *dockable)
 
954
{
 
955
  GimpUIManager *dockbook_ui_manager = dockable->dockbook->ui_manager;
 
956
  GimpUIManager *dialog_ui_manager;
 
957
  const gchar   *dialog_ui_path;
 
958
  gpointer       dialog_popup_data;
 
959
  GtkWidget     *parent_menu_widget;
 
960
  GtkAction     *parent_menu_action;
 
961
 
 
962
  if (! dockbook_ui_manager)
 
963
    return FALSE;
 
964
 
 
965
  parent_menu_widget =
 
966
    gimp_ui_manager_ui_get (dockbook_ui_manager,
 
967
                            "/dockable-popup/dockable-menu");
 
968
 
 
969
  parent_menu_action =
 
970
    gtk_ui_manager_get_action (GTK_UI_MANAGER (dockbook_ui_manager),
 
971
                               "/dockable-popup/dockable-menu");
 
972
 
 
973
  if (! parent_menu_widget || ! parent_menu_action)
 
974
    return FALSE;
 
975
 
 
976
  dialog_ui_manager = gimp_dockable_get_menu (dockable,
 
977
                                              &dialog_ui_path,
 
978
                                              &dialog_popup_data);
 
979
 
 
980
  if (dialog_ui_manager && dialog_ui_path)
 
981
    {
 
982
      GtkWidget   *child_menu_widget;
 
983
      GtkAction   *child_menu_action;
 
984
      const gchar *label;
 
985
 
 
986
      child_menu_widget =
 
987
        gimp_ui_manager_ui_get (dialog_ui_manager, dialog_ui_path);
 
988
 
 
989
      child_menu_action =
 
990
        gtk_ui_manager_get_action (GTK_UI_MANAGER (dialog_ui_manager),
 
991
                                   dialog_ui_path);
 
992
 
 
993
      if (! child_menu_widget || ! child_menu_action)
 
994
        return FALSE;
 
995
 
 
996
      g_object_get (child_menu_action,
 
997
                    "label", &label,
 
998
                    NULL);
 
999
 
 
1000
      g_object_set (parent_menu_action,
 
1001
                    "label",    label,
 
1002
                    "stock-id", dockable->stock_id,
 
1003
                    "visible",  TRUE,
 
1004
                    NULL);
 
1005
 
 
1006
      if (! GTK_IS_MENU (child_menu_widget))
 
1007
        {
 
1008
          g_warning ("%s: child_menu_widget (%p) is not a GtkMenu",
 
1009
                     G_STRFUNC, child_menu_widget);
 
1010
          return FALSE;
 
1011
        }
 
1012
 
 
1013
      /* FIXME */
 
1014
      {
 
1015
        GtkWidget *image = gtk_image_new_from_stock (dockable->stock_id,
 
1016
                                                     GTK_ICON_SIZE_MENU);
 
1017
 
 
1018
        gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (parent_menu_widget),
 
1019
                                       image);
 
1020
        gtk_widget_show (image);
 
1021
      }
 
1022
 
 
1023
      gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent_menu_widget),
 
1024
                                 child_menu_widget);
 
1025
 
 
1026
      gimp_ui_manager_update (dialog_ui_manager, dialog_popup_data);
 
1027
    }
 
1028
  else
 
1029
    {
 
1030
      g_object_set (parent_menu_action, "visible", FALSE, NULL);
 
1031
    }
 
1032
 
 
1033
  /*  an action callback may destroy both dockable and dockbook, so
 
1034
   *  reference them for gimp_dockable_menu_end()
 
1035
   */
 
1036
  g_object_ref (dockable);
 
1037
  g_object_set_data_full (G_OBJECT (dockable), GIMP_DOCKABLE_DETACH_REF_KEY,
 
1038
                          g_object_ref (dockable->dockbook),
 
1039
                          g_object_unref);
 
1040
 
 
1041
  gimp_ui_manager_update (dockbook_ui_manager, dockable);
 
1042
  gimp_ui_manager_ui_popup (dockbook_ui_manager, "/dockable-popup",
 
1043
                            GTK_WIDGET (dockable),
 
1044
                            gimp_dockable_menu_position, dockable,
 
1045
                            (GtkDestroyNotify) gimp_dockable_menu_end, dockable);
 
1046
 
 
1047
  return TRUE;
 
1048
}
 
1049
 
 
1050
static void
 
1051
gimp_dockable_title_changed (GimpDocked   *docked,
 
1052
                             GimpDockable *dockable)
 
1053
{
 
1054
  if (dockable->title_layout)
 
1055
    {
 
1056
      g_object_unref (dockable->title_layout);
 
1057
      dockable->title_layout = NULL;
 
1058
    }
 
1059
 
 
1060
  if (GTK_WIDGET (dockable)->window)
 
1061
    {
 
1062
      GdkRectangle title_area;
 
1063
 
 
1064
      gimp_dockable_get_title_area (dockable, &title_area);
 
1065
 
 
1066
      gdk_window_invalidate_rect (GTK_WIDGET (dockable)->window,
 
1067
                                  &title_area, FALSE);
 
1068
    }
 
1069
}