gimpmenudock.c 22.9 KB
Newer Older
Michael Natterer's avatar
Michael Natterer committed
1
2
3
/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
4
 * gimpmenudock.c
5
 * Copyright (C) 2001-2004 Michael Natterer <mitch@gimp.org>
Michael Natterer's avatar
Michael Natterer committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "config.h"

24
25
#include <string.h>

Michael Natterer's avatar
Michael Natterer committed
26
27
#include <gtk/gtk.h>

28
#include "libgimpbase/gimpbase.h"
Michael Natterer's avatar
Michael Natterer committed
29
30
#include "libgimpwidgets/gimpwidgets.h"

31
#include "widgets-types.h"
Michael Natterer's avatar
Michael Natterer committed
32

33
#include "core/gimp.h"
34
35
#include "core/gimpcontext.h"
#include "core/gimpimage.h"
36
#include "core/gimplist.h"
37
#include "core/gimptoolinfo.h"
38

Michael Natterer's avatar
Michael Natterer committed
39
#include "gimpdialogfactory.h"
40
41
#include "gimpcontainercombobox.h"
#include "gimpcontainerview.h"
42
#include "gimpdockable.h"
Michael Natterer's avatar
Michael Natterer committed
43
#include "gimpdockbook.h"
44
#include "gimphelp-ids.h"
45
#include "gimpmenudock.h"
46
#include "gimpsessioninfo.h"
Michael Natterer's avatar
Michael Natterer committed
47

48
#include "gimp-intl.h"
Michael Natterer's avatar
Michael Natterer committed
49
50


51
52
#define DEFAULT_MINIMAL_WIDTH     250
#define DEFAULT_MENU_PREVIEW_SIZE GTK_ICON_SIZE_SMALL_TOOLBAR
53
54


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
static void   gimp_menu_dock_class_init          (GimpMenuDockClass *klass);
static void   gimp_menu_dock_init                (GimpMenuDock      *dock);

static GObject * gimp_menu_dock_constructor   (GType                  type,
                                               guint                  n_params,
                                               GObjectConstructParam *params);
static void   gimp_menu_dock_destroy                 (GtkObject      *object);

static void   gimp_menu_dock_style_set               (GtkWidget      *widget,
                                                      GtkStyle       *prev_style);

static void   gimp_menu_dock_setup                   (GimpDock       *dock,
                                                      const GimpDock *template);
static void   gimp_menu_dock_set_aux_info            (GimpDock       *dock,
                                                      GList          *aux_info);
static GList *gimp_menu_dock_get_aux_info            (GimpDock       *dock);
static void   gimp_menu_dock_book_added              (GimpDock       *dock,
                                                      GimpDockbook   *dockbook);
static void   gimp_menu_dock_book_removed            (GimpDock       *dock,
                                                      GimpDockbook   *dockbook);

static void   gimp_menu_dock_dockbook_changed        (GimpDockbook   *dockbook,
                                                      GimpDockable   *dockable,
                                                      GimpMenuDock   *dock);
static void   gimp_menu_dock_update_title            (GimpMenuDock   *dock);

static void   gimp_menu_dock_factory_display_changed (GimpContext    *context,
                                                      GimpObject     *display,
                                                      GimpDock       *dock);
static void   gimp_menu_dock_factory_image_changed   (GimpContext    *context,
                                                      GimpImage      *gimage,
                                                      GimpDock       *dock);
static void   gimp_menu_dock_image_changed           (GimpContext    *context,
                                                      GimpImage      *gimage,
                                                      GimpDock       *dock);
static void   gimp_menu_dock_auto_clicked            (GtkWidget      *widget,
                                                      GimpDock       *dock);
Michael Natterer's avatar
Michael Natterer committed
92
93
94
95
96


static GimpDockClass *parent_class = NULL;


97
GType
98
gimp_menu_dock_get_type (void)
Michael Natterer's avatar
Michael Natterer committed
99
{
100
  static GType dock_type = 0;
Michael Natterer's avatar
Michael Natterer committed
101
102
103

  if (! dock_type)
    {
104
      static const GTypeInfo dock_info =
Michael Natterer's avatar
Michael Natterer committed
105
      {
106
        sizeof (GimpMenuDockClass),
107
108
        NULL,           /* base_init */
        NULL,           /* base_finalize */
109
        (GClassInitFunc) gimp_menu_dock_class_init,
110
111
        NULL,           /* class_finalize */
        NULL,           /* class_data */
112
        sizeof (GimpMenuDock),
113
        0,              /* n_preallocs */
114
        (GInstanceInitFunc) gimp_menu_dock_init,
Michael Natterer's avatar
Michael Natterer committed
115
116
      };

117
118
      dock_type = g_type_register_static (GIMP_TYPE_IMAGE_DOCK,
                                          "GimpMenuDock",
119
                                          &dock_info, 0);
Michael Natterer's avatar
Michael Natterer committed
120
121
122
123
124
125
    }

  return dock_type;
}

static void
126
gimp_menu_dock_class_init (GimpMenuDockClass *klass)
Michael Natterer's avatar
Michael Natterer committed
127
{
128
129
130
131
  GObjectClass   *object_class     = G_OBJECT_CLASS (klass);
  GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (klass);
  GtkWidgetClass *widget_class     = GTK_WIDGET_CLASS (klass);
  GimpDockClass  *dock_class       = GIMP_DOCK_CLASS (klass);
Michael Natterer's avatar
Michael Natterer committed
132

133
  parent_class = g_type_class_peek_parent (klass);
Michael Natterer's avatar
Michael Natterer committed
134

135
  object_class->constructor = gimp_menu_dock_constructor;
136

137
  gtk_object_class->destroy = gimp_menu_dock_destroy;
138

139
  widget_class->style_set   = gimp_menu_dock_style_set;
140

141
142
143
144
145
  dock_class->setup         = gimp_menu_dock_setup;
  dock_class->set_aux_info  = gimp_menu_dock_set_aux_info;
  dock_class->get_aux_info  = gimp_menu_dock_get_aux_info;
  dock_class->book_added    = gimp_menu_dock_book_added;
  dock_class->book_removed  = gimp_menu_dock_book_removed;
146
147

  gtk_widget_class_install_style_property (widget_class,
148
                                           g_param_spec_int ("minimal-width",
149
150
151
152
153
                                                             NULL, NULL,
                                                             0,
                                                             G_MAXINT,
                                                             DEFAULT_MINIMAL_WIDTH,
                                                             G_PARAM_READABLE));
154
  gtk_widget_class_install_style_property (widget_class,
155
                                           g_param_spec_enum ("menu-preview-size",
156
157
158
159
                                                              NULL, NULL,
                                                              GTK_TYPE_ICON_SIZE,
                                                              DEFAULT_MENU_PREVIEW_SIZE,
                                                              G_PARAM_READABLE));
Michael Natterer's avatar
Michael Natterer committed
160
161
162
}

static void
163
gimp_menu_dock_init (GimpMenuDock *dock)
Michael Natterer's avatar
Michael Natterer committed
164
{
Michael Natterer's avatar
Michael Natterer committed
165
166
  GtkWidget *hbox;

167
168
169
170
171
  dock->image_container      = NULL;
  dock->display_container    = NULL;
  dock->show_image_menu      = FALSE;
  dock->auto_follow_active   = TRUE;
  dock->update_title_idle_id = 0;
Michael Natterer's avatar
Michael Natterer committed
172
173
174

  hbox = gtk_hbox_new (FALSE, 2);
  gtk_box_pack_start (GTK_BOX (GIMP_DOCK (dock)->main_vbox), hbox,
Michael Natterer's avatar
Michael Natterer committed
175
                      FALSE, FALSE, 0);
Michael Natterer's avatar
Michael Natterer committed
176
  gtk_box_reorder_child (GTK_BOX (GIMP_DOCK (dock)->main_vbox), hbox, 0);
177
178
179

  if (dock->show_image_menu)
    gtk_widget_show (hbox);
Michael Natterer's avatar
Michael Natterer committed
180

181
182
183
  dock->image_combo = gimp_container_combo_box_new (NULL, NULL, 16, 1);
  gtk_box_pack_start (GTK_BOX (hbox), dock->image_combo, TRUE, TRUE, 0);
  gtk_widget_show (dock->image_combo);
Michael Natterer's avatar
Michael Natterer committed
184

185
  g_signal_connect (dock->image_combo, "destroy",
186
		    G_CALLBACK (gtk_widget_destroyed),
187
		    &dock->image_combo);
188

189
  gimp_help_set_help_data (dock->image_combo, NULL, GIMP_HELP_DOCK_IMAGE_MENU);
190

191
192
  dock->auto_button = gtk_toggle_button_new_with_label (_("Auto"));
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dock->auto_button),
193
                                dock->auto_follow_active);
194
195
  gtk_box_pack_start (GTK_BOX (hbox), dock->auto_button, FALSE, FALSE, 0);
  gtk_widget_show (dock->auto_button);
Michael Natterer's avatar
Michael Natterer committed
196

197
  g_signal_connect (dock->auto_button, "clicked",
198
                    G_CALLBACK (gimp_menu_dock_auto_clicked),
199
                    dock);
200

201
202
203
  gimp_help_set_help_data (dock->auto_button,
                           _("When enabled the dialog automatically "
                             "follows the image you are working on."),
204
                           GIMP_HELP_DOCK_AUTO_BUTTON);
Michael Natterer's avatar
Michael Natterer committed
205
206
}

207
static GObject *
208
209
210
gimp_menu_dock_constructor (GType                  type,
                            guint                  n_params,
                            GObjectConstructParam *params)
Michael Natterer's avatar
Michael Natterer committed
211
{
212
213
  GObject      *object;
  GimpMenuDock *dock;
214
215

  object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params);
Michael Natterer's avatar
Michael Natterer committed
216

217
  dock = GIMP_MENU_DOCK (object);
Michael Natterer's avatar
Michael Natterer committed
218

219
220
221
222
  return object;
}

static void
223
gimp_menu_dock_destroy (GtkObject *object)
224
{
225
  GimpMenuDock *dock = GIMP_MENU_DOCK (object);
226

227
228
229
230
231
232
  if (dock->update_title_idle_id)
    {
      g_source_remove (dock->update_title_idle_id);
      dock->update_title_idle_id = 0;
    }

Michael Natterer's avatar
Michael Natterer committed
233
234
235
  /*  remove the image menu and the auto button manually here because
   *  of weird cross-connections with GimpDock's context
   */
236
  if (GIMP_DOCK (dock)->main_vbox &&
237
238
      dock->image_combo           &&
      dock->image_combo->parent)
239
240
    {
      gtk_container_remove (GTK_CONTAINER (GIMP_DOCK (dock)->main_vbox),
241
                            dock->image_combo->parent);
242
    }
Michael Natterer's avatar
Michael Natterer committed
243

244
  GTK_OBJECT_CLASS (parent_class)->destroy (object);
Michael Natterer's avatar
Michael Natterer committed
245
246
}

247
static void
248
249
gimp_menu_dock_style_set (GtkWidget *widget,
                          GtkStyle  *prev_style)
250
{
251
252
253
254
255
256
257
258
259
260
261
  GimpMenuDock *menu_dock;
  gint          minimal_width;
  GtkIconSize   menu_preview_size;
  GdkScreen    *screen;
  gint          menu_preview_width  = 18;
  gint          menu_preview_height = 18;
  gint          focus_line_width;
  gint          focus_padding;
  gint          ythickness;

  menu_dock = GIMP_MENU_DOCK (widget);
262
263
264
265
266

  if (GTK_WIDGET_CLASS (parent_class)->style_set)
    GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);

  gtk_widget_style_get (widget,
267
268
                        "minimal_width",     &minimal_width,
                        "menu_preview_size", &menu_preview_size,
269
                        NULL);
270

271
  screen = gtk_widget_get_screen (menu_dock->image_combo);
272
273
274
275
  gtk_icon_size_lookup_for_settings (gtk_settings_get_for_screen (screen),
                                     menu_preview_size,
                                     &menu_preview_width,
                                     &menu_preview_height);
276

277
  gtk_widget_style_get (menu_dock->auto_button,
278
279
                        "focus_line_width", &focus_line_width,
                        "focus_padding",    &focus_padding,
280
                        NULL);
281

282
  ythickness = menu_dock->auto_button->style->ythickness;
283

284
  gtk_widget_set_size_request (widget, minimal_width, -1);
285

286
  gimp_container_view_set_preview_size (GIMP_CONTAINER_VIEW (menu_dock->image_combo),
287
                                        menu_preview_height, 1);
288

289
  gtk_widget_set_size_request (menu_dock->auto_button, -1,
290
291
292
293
294
                               menu_preview_height +
                               2 * (1 /* CHILD_SPACING */ +
                                    ythickness            +
                                    focus_padding         +
                                    focus_line_width));
295
296
}

297
static void
298
299
gimp_menu_dock_setup (GimpDock       *dock,
                      const GimpDock *template)
300
{
301
  if (GIMP_IS_MENU_DOCK (template))
302
303
304
305
    {
      gboolean auto_follow_active;
      gboolean show_image_menu;

306
307
      auto_follow_active = GIMP_MENU_DOCK (template)->auto_follow_active;
      show_image_menu    = GIMP_MENU_DOCK (template)->show_image_menu;
308

309
310
311
312
      gimp_menu_dock_set_auto_follow_active (GIMP_MENU_DOCK (dock),
                                             auto_follow_active);
      gimp_menu_dock_set_show_image_menu (GIMP_MENU_DOCK (dock),
                                          show_image_menu);
313
314
315
    }
}

316
317
318
#define AUX_INFO_SHOW_IMAGE_MENU     "show-image-menu"
#define AUX_INFO_FOLLOW_ACTIVE_IMAGE "follow-active-image"

319
static void
320
321
gimp_menu_dock_set_aux_info (GimpDock *dock,
                             GList    *aux_info)
322
{
323
324
325
326
  GimpMenuDock *menu_dock   = GIMP_MENU_DOCK (dock);
  GList        *list;
  gboolean      menu_shown  = menu_dock->show_image_menu;
  gboolean      auto_follow = menu_dock->auto_follow_active;
327

328
  for (list = aux_info; list; list = g_list_next (list))
329
    {
330
331
      GimpSessionInfoAux *aux = list->data;

332
      if (! strcmp (aux->name, AUX_INFO_SHOW_IMAGE_MENU))
333
334
335
        {
          menu_shown = ! g_ascii_strcasecmp (aux->value, "true");
        }
336
      else if (! strcmp (aux->name, AUX_INFO_FOLLOW_ACTIVE_IMAGE))
337
338
339
        {
          auto_follow = ! g_ascii_strcasecmp (aux->value, "true");
        }
340
341
    }

342
343
  if (menu_shown != menu_dock->show_image_menu)
    gimp_menu_dock_set_show_image_menu (menu_dock, menu_shown);
344

345
346
  if (auto_follow != menu_dock->auto_follow_active)
    gimp_menu_dock_set_auto_follow_active (menu_dock, auto_follow);
347
348
349
}

static GList *
350
gimp_menu_dock_get_aux_info (GimpDock *dock)
351
{
352
353
  GimpMenuDock       *menu_dock = GIMP_MENU_DOCK (dock);
  GList              *aux_info  = NULL;
354
355
  GimpSessionInfoAux *aux;

356
  aux = gimp_session_info_aux_new (AUX_INFO_SHOW_IMAGE_MENU,
357
                                   menu_dock->show_image_menu ?
358
                                   "true" : "false");
359
  aux_info = g_list_append (aux_info, aux);
360

361
  aux = gimp_session_info_aux_new (AUX_INFO_FOLLOW_ACTIVE_IMAGE,
362
                                   menu_dock->auto_follow_active ?
363
                                   "true" : "false");
364
  aux_info = g_list_append (aux_info, aux);
365

366
  return aux_info;
367
368
}

369
static void
370
371
gimp_menu_dock_book_added (GimpDock     *dock,
                           GimpDockbook *dockbook)
372
373
{
  g_signal_connect (dockbook, "dockable_added",
374
                    G_CALLBACK (gimp_menu_dock_dockbook_changed),
375
376
                    dock);
  g_signal_connect (dockbook, "dockable_removed",
377
                    G_CALLBACK (gimp_menu_dock_dockbook_changed),
378
379
                    dock);
  g_signal_connect (dockbook, "dockable_reordered",
380
                    G_CALLBACK (gimp_menu_dock_dockbook_changed),
381
382
                    dock);

383
  gimp_menu_dock_update_title (GIMP_MENU_DOCK (dock));
384
385
386
387
388

  GIMP_DOCK_CLASS (parent_class)->book_added (dock, dockbook);
}

static void
389
390
gimp_menu_dock_book_removed (GimpDock     *dock,
                             GimpDockbook *dockbook)
391
392
{
  g_signal_handlers_disconnect_by_func (dockbook,
393
                                        gimp_menu_dock_dockbook_changed,
394
395
                                        dock);

396
  gimp_menu_dock_update_title (GIMP_MENU_DOCK (dock));
397

398
  GIMP_DOCK_CLASS (parent_class)->book_removed (dock, dockbook);
399
400
}

Michael Natterer's avatar
Michael Natterer committed
401
GtkWidget *
402
403
404
gimp_menu_dock_new (GimpDialogFactory *dialog_factory,
                    GimpContainer     *image_container,
                    GimpContainer     *display_container)
Michael Natterer's avatar
Michael Natterer committed
405
{
406
407
408
409
410
  GimpMenuDock *menu_dock;
  GimpContext  *context;
  GdkScreen    *screen;
  gint          menu_preview_width;
  gint          menu_preview_height;
411

412
  g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (dialog_factory), NULL);
Michael Natterer's avatar
Michael Natterer committed
413
  g_return_val_if_fail (GIMP_IS_CONTAINER (image_container), NULL);
414
  g_return_val_if_fail (GIMP_IS_CONTAINER (display_container), NULL);
Michael Natterer's avatar
Michael Natterer committed
415

416
417
418
  context = gimp_context_new (dialog_factory->context->gimp,
                              "Dock Context", NULL);

419
420
421
422
  menu_dock = g_object_new (GIMP_TYPE_MENU_DOCK,
                            "context",        context,
                            "dialog-factory", dialog_factory,
                            NULL);
Sven Neumann's avatar
Sven Neumann committed
423

424
425
  menu_dock->image_container   = image_container;
  menu_dock->display_container = display_container;
Michael Natterer's avatar
Michael Natterer committed
426

427
  gimp_help_connect (GTK_WIDGET (menu_dock), gimp_standard_help_func,
428
429
                     GIMP_HELP_DOCK, NULL);

430
  gimp_context_define_properties (context,
431
432
433
434
				  GIMP_CONTEXT_ALL_PROPS_MASK &
				  ~(GIMP_CONTEXT_IMAGE_MASK |
				    GIMP_CONTEXT_DISPLAY_MASK),
				  FALSE);
435
  gimp_context_set_parent (context, dialog_factory->context);
Michael Natterer's avatar
Michael Natterer committed
436

437
  if (menu_dock->auto_follow_active)
438
439
440
441
442
443
444
445
    {
      if (gimp_context_get_display (dialog_factory->context))
        gimp_context_copy_property (dialog_factory->context, context,
                                    GIMP_CONTEXT_PROP_DISPLAY);
      else
        gimp_context_copy_property (dialog_factory->context, context,
                                    GIMP_CONTEXT_PROP_IMAGE);
    }
446

447
  g_signal_connect_object (dialog_factory->context, "display_changed",
448
449
			   G_CALLBACK (gimp_menu_dock_factory_display_changed),
			   menu_dock,
Michael Natterer's avatar
Michael Natterer committed
450
			   0);
451
  g_signal_connect_object (dialog_factory->context, "image_changed",
452
453
			   G_CALLBACK (gimp_menu_dock_factory_image_changed),
			   menu_dock,
454
			   0);
Michael Natterer's avatar
Michael Natterer committed
455

456
  g_signal_connect_object (context, "image_changed",
457
458
			   G_CALLBACK (gimp_menu_dock_image_changed),
			   menu_dock,
459
			   0);
Michael Natterer's avatar
Michael Natterer committed
460

461
  screen = gtk_widget_get_screen (GTK_WIDGET (menu_dock));
462
463
464
465
  gtk_icon_size_lookup_for_settings (gtk_settings_get_for_screen (screen),
                                     DEFAULT_MENU_PREVIEW_SIZE,
                                     &menu_preview_width,
                                     &menu_preview_height);
466

467
  g_object_set (menu_dock->image_combo,
468
469
470
                "container", image_container,
                "context",   context,
                NULL);
471

472
  return GTK_WIDGET (menu_dock);
Michael Natterer's avatar
Michael Natterer committed
473
}
Michael Natterer's avatar
Michael Natterer committed
474

475
void
476
477
gimp_menu_dock_set_auto_follow_active (GimpMenuDock *menu_dock,
                                       gboolean      auto_follow_active)
478
{
479
  g_return_if_fail (GIMP_IS_MENU_DOCK (menu_dock));
480

481
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (menu_dock->auto_button),
482
483
484
				auto_follow_active ? TRUE : FALSE);
}

Michael Natterer's avatar
Michael Natterer committed
485
void
486
487
gimp_menu_dock_set_show_image_menu (GimpMenuDock *menu_dock,
                                    gboolean      show)
Michael Natterer's avatar
Michael Natterer committed
488
{
489
  g_return_if_fail (GIMP_IS_MENU_DOCK (menu_dock));
Michael Natterer's avatar
Michael Natterer committed
490
491

  if (show)
492
    gtk_widget_show (menu_dock->image_combo->parent);
Michael Natterer's avatar
Michael Natterer committed
493
  else
494
    gtk_widget_hide (menu_dock->image_combo->parent);
495

496
  menu_dock->show_image_menu = show ? TRUE : FALSE;
Michael Natterer's avatar
Michael Natterer committed
497
498
}

499
static void
500
501
502
gimp_menu_dock_dockbook_changed (GimpDockbook *dockbook,
                                 GimpDockable *dockable,
                                 GimpMenuDock *dock)
503
{
504
  gimp_menu_dock_update_title (dock);
505
506
507
}

static gboolean
508
gimp_menu_dock_update_title_idle (GimpMenuDock *menu_dock)
509
510
511
512
513
514
{
  GString *title;
  GList   *list;

  title = g_string_new (NULL);

515
  for (list = GIMP_DOCK (menu_dock)->dockbooks;
516
517
518
519
520
521
522
523
524
525
526
527
528
       list;
       list = g_list_next (list))
    {
      GimpDockbook *dockbook = list->data;
      GList        *children;
      GList        *child;

      children = gtk_container_get_children (GTK_CONTAINER (dockbook));

      for (child = children; child; child = g_list_next (child))
        {
          GimpDockable *dockable = child->data;

529
          g_string_append (title, dockable->name);
530
531
532
533
534
535
536
537
538
539
540

          if (g_list_next (child))
            g_string_append (title, ", ");
        }

      g_list_free (children);

      if (g_list_next (list))
        g_string_append (title, " | ");
    }

541
  gtk_window_set_title (GTK_WINDOW (menu_dock), title->str);
542
543
544

  g_string_free (title, TRUE);

545
  menu_dock->update_title_idle_id = 0;
546
547
548
549
550

  return FALSE;
}

static void
551
gimp_menu_dock_update_title (GimpMenuDock *menu_dock)
552
{
553
554
  if (menu_dock->update_title_idle_id)
    g_source_remove (menu_dock->update_title_idle_id);
555

556
557
558
  menu_dock->update_title_idle_id =
    g_idle_add ((GSourceFunc) gimp_menu_dock_update_title_idle,
                menu_dock);
559
560
}

Michael Natterer's avatar
Michael Natterer committed
561
static void
562
563
564
gimp_menu_dock_factory_display_changed (GimpContext *context,
                                        GimpObject  *display,
                                        GimpDock    *dock)
Michael Natterer's avatar
Michael Natterer committed
565
{
566
  GimpMenuDock *menu_dock = GIMP_MENU_DOCK (dock);
Michael Natterer's avatar
Michael Natterer committed
567

568
  if (display && menu_dock->auto_follow_active)
569
    gimp_context_set_display (dock->context, display);
Michael Natterer's avatar
Michael Natterer committed
570
571
}

Michael Natterer's avatar
Michael Natterer committed
572
static void
573
574
575
gimp_menu_dock_factory_image_changed (GimpContext *context,
                                      GimpImage   *gimage,
                                      GimpDock    *dock)
Michael Natterer's avatar
Michael Natterer committed
576
{
577
  GimpMenuDock *menu_dock = GIMP_MENU_DOCK (dock);
Michael Natterer's avatar
Michael Natterer committed
578

579
  /*  won't do anything if we already set the display above  */
580
  if (gimage && menu_dock->auto_follow_active)
581
    gimp_context_set_image (dock->context, gimage);
Michael Natterer's avatar
Michael Natterer committed
582
583
584
}

static void
585
586
587
gimp_menu_dock_image_changed (GimpContext *context,
                              GimpImage   *gimage,
                              GimpDock    *dock)
Michael Natterer's avatar
Michael Natterer committed
588
{
589
590
591
  GimpMenuDock  *menu_dock         = GIMP_MENU_DOCK (dock);
  GimpContainer *image_container   = menu_dock->image_container;
  GimpContainer *display_container = menu_dock->display_container;
Michael Natterer's avatar
Michael Natterer committed
592

593
  if (gimage == NULL && ! gimp_container_is_empty (image_container))
Michael Natterer's avatar
Michael Natterer committed
594
    {
595
596
      gimage = GIMP_IMAGE (gimp_container_get_child_by_index (image_container,
                                                              0));
Michael Natterer's avatar
Michael Natterer committed
597

598
599
600
601
602
      if (gimage)
	{
	  /*  this invokes this function recursively but we don't enter
	   *  the if() branch the second time
	   */
603
	  gimp_context_set_image (context, gimage);
604
605
606
607

	  /*  stop the emission of the original signal (the emission of
	   *  the recursive signal is finished)
	   */
608
	  g_signal_stop_emission_by_name (context, "image_changed");
609
	}
Michael Natterer's avatar
Michael Natterer committed
610
    }
611
  else if (gimage != NULL && ! gimp_container_is_empty (display_container))
612
613
    {
      GimpObject *gdisp;
614
      GimpImage  *gdisp_gimage;
615
616
617
618
619
620
621
622
      gboolean    find_display = TRUE;

      gdisp = gimp_context_get_display (context);

      if (gdisp)
        {
          g_object_get (gdisp, "image", &gdisp_gimage, NULL);

623
624
625
626
627
628
629
          if (gdisp_gimage)
            {
              g_object_unref (gdisp_gimage);

              if (gdisp_gimage == gimage)
                find_display = FALSE;
            }
630
631
632
633
634
635
        }

      if (find_display)
        {
          GList *list;

636
          for (list = GIMP_LIST (display_container)->list;
637
638
639
640
641
642
643
               list;
               list = g_list_next (list))
            {
              gdisp = GIMP_OBJECT (list->data);

              g_object_get (gdisp, "image", &gdisp_gimage, NULL);

644
              if (gdisp_gimage)
645
                {
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
                  g_object_unref (gdisp_gimage);

                  if (gdisp_gimage == gimage)
                    {
                      /*  this invokes this function recursively but we
                       *  don't enter the if(find_display) branch the
                       *  second time
                       */
                      gimp_context_set_display (context, gdisp);

                      /*  don't stop signal emission here because the
                       *  context's image was not changed by the
                       *  recursive call
                       */
                      break;
                    }
662
663
664
665
                }
            }
        }
    }
Michael Natterer's avatar
Michael Natterer committed
666
667
668
}

static void
669
670
gimp_menu_dock_auto_clicked (GtkWidget *widget,
                             GimpDock  *dock)
Michael Natterer's avatar
Michael Natterer committed
671
{
672
  GimpMenuDock *menu_dock = GIMP_MENU_DOCK (dock);
Michael Natterer's avatar
Michael Natterer committed
673

674
  gimp_toggle_button_update (widget, &menu_dock->auto_follow_active);
Michael Natterer's avatar
Michael Natterer committed
675

676
  if (menu_dock->auto_follow_active)
Michael Natterer's avatar
Michael Natterer committed
677
    {
678
      if (gimp_context_get_display (dock->dialog_factory->context))
679
680
        gimp_context_copy_property (dock->dialog_factory->context,
                                    dock->context,
681
                                    GIMP_CONTEXT_PROP_DISPLAY);
Michael Natterer's avatar
Michael Natterer committed
682
      else
683
684
        gimp_context_copy_property (dock->dialog_factory->context,
                                    dock->context,
685
                                    GIMP_CONTEXT_PROP_IMAGE);
Michael Natterer's avatar
Michael Natterer committed
686
687
    }
}