1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimpdock.c
5  * Copyright (C) 2001-2005 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 3 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, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #include <gegl.h>
24 #include <gtk/gtk.h>
25 
26 #include "libgimpwidgets/gimpwidgets.h"
27 
28 #include "widgets-types.h"
29 
30 #include "core/gimp.h"
31 #include "core/gimpcontext.h"
32 #include "core/gimpmarshal.h"
33 
34 #include "gimpdialogfactory.h"
35 #include "gimpdock.h"
36 #include "gimpdockable.h"
37 #include "gimpdockbook.h"
38 #include "gimpdockcolumns.h"
39 #include "gimpdockcontainer.h"
40 #include "gimpdockwindow.h"
41 #include "gimppanedbox.h"
42 #include "gimpuimanager.h"
43 #include "gimpwidgets-utils.h"
44 
45 #include "gimp-intl.h"
46 
47 
48 #define DEFAULT_DOCK_FONT_SCALE  PANGO_SCALE_SMALL
49 
50 
51 enum
52 {
53   BOOK_ADDED,
54   BOOK_REMOVED,
55   DESCRIPTION_INVALIDATED,
56   GEOMETRY_INVALIDATED,
57   LAST_SIGNAL
58 };
59 
60 
61 struct _GimpDockPrivate
62 {
63   GtkWidget         *temp_vbox;
64   GtkWidget         *main_vbox;
65   GtkWidget         *paned_vbox;
66 
67   GList             *dockbooks;
68 
69   gint               ID;
70 };
71 
72 
73 static void       gimp_dock_dispose                (GObject      *object);
74 
75 static void       gimp_dock_style_set              (GtkWidget    *widget,
76                                                     GtkStyle     *prev_style);
77 static gchar    * gimp_dock_real_get_description   (GimpDock     *dock,
78                                                     gboolean      complete);
79 static void       gimp_dock_real_book_added        (GimpDock     *dock,
80                                                     GimpDockbook *dockbook);
81 static void       gimp_dock_real_book_removed      (GimpDock     *dock,
82                                                     GimpDockbook *dockbook);
83 static void       gimp_dock_invalidate_description (GimpDock     *dock);
84 static gboolean   gimp_dock_dropped_cb             (GtkWidget    *source,
85                                                     gint          insert_index,
86                                                     gpointer      data);
87 
88 
89 G_DEFINE_TYPE_WITH_PRIVATE (GimpDock, gimp_dock, GTK_TYPE_BOX)
90 
91 #define parent_class gimp_dock_parent_class
92 
93 static guint dock_signals[LAST_SIGNAL] = { 0 };
94 
95 
96 static void
gimp_dock_class_init(GimpDockClass * klass)97 gimp_dock_class_init (GimpDockClass *klass)
98 {
99   GObjectClass   *object_class = G_OBJECT_CLASS (klass);
100   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
101 
102   dock_signals[BOOK_ADDED] =
103     g_signal_new ("book-added",
104                   G_TYPE_FROM_CLASS (klass),
105                   G_SIGNAL_RUN_FIRST,
106                   G_STRUCT_OFFSET (GimpDockClass, book_added),
107                   NULL, NULL,
108                   gimp_marshal_VOID__OBJECT,
109                   G_TYPE_NONE, 1,
110                   GIMP_TYPE_DOCKBOOK);
111 
112   dock_signals[BOOK_REMOVED] =
113     g_signal_new ("book-removed",
114                   G_TYPE_FROM_CLASS (klass),
115                   G_SIGNAL_RUN_FIRST,
116                   G_STRUCT_OFFSET (GimpDockClass, book_removed),
117                   NULL, NULL,
118                   gimp_marshal_VOID__OBJECT,
119                   G_TYPE_NONE, 1,
120                   GIMP_TYPE_DOCKBOOK);
121 
122   dock_signals[DESCRIPTION_INVALIDATED] =
123     g_signal_new ("description-invalidated",
124                   G_TYPE_FROM_CLASS (klass),
125                   G_SIGNAL_RUN_FIRST,
126                   G_STRUCT_OFFSET (GimpDockClass, description_invalidated),
127                   NULL, NULL,
128                   gimp_marshal_VOID__VOID,
129                   G_TYPE_NONE, 0);
130 
131   dock_signals[GEOMETRY_INVALIDATED] =
132     g_signal_new ("geometry-invalidated",
133                   G_TYPE_FROM_CLASS (klass),
134                   G_SIGNAL_RUN_FIRST,
135                   G_STRUCT_OFFSET (GimpDockClass, geometry_invalidated),
136                   NULL, NULL,
137                   gimp_marshal_VOID__VOID,
138                   G_TYPE_NONE, 0);
139 
140   object_class->dispose          = gimp_dock_dispose;
141 
142   widget_class->style_set        = gimp_dock_style_set;
143 
144   klass->get_description         = gimp_dock_real_get_description;
145   klass->set_host_geometry_hints = NULL;
146   klass->book_added              = gimp_dock_real_book_added;
147   klass->book_removed            = gimp_dock_real_book_removed;
148   klass->description_invalidated = NULL;
149   klass->geometry_invalidated    = NULL;
150 
151   gtk_widget_class_install_style_property (widget_class,
152                                            g_param_spec_double ("font-scale",
153                                                                 NULL, NULL,
154                                                                 0.0,
155                                                                 G_MAXDOUBLE,
156                                                                 DEFAULT_DOCK_FONT_SCALE,
157                                                                 GIMP_PARAM_READABLE));
158 }
159 
160 static void
gimp_dock_init(GimpDock * dock)161 gimp_dock_init (GimpDock *dock)
162 {
163   static gint  dock_ID = 1;
164   gchar       *name    = NULL;
165 
166   gtk_orientable_set_orientation (GTK_ORIENTABLE (dock),
167                                   GTK_ORIENTATION_VERTICAL);
168 
169   dock->p = gimp_dock_get_instance_private (dock);
170   dock->p->ID             = dock_ID++;
171 
172   name = g_strdup_printf ("gimp-internal-dock-%d", dock->p->ID);
173   gtk_widget_set_name (GTK_WIDGET (dock), name);
174   g_free (name);
175 
176   dock->p->temp_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
177   gtk_box_pack_start (GTK_BOX (dock), dock->p->temp_vbox, FALSE, FALSE, 0);
178   /* Never show it */
179 
180   dock->p->main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
181   gtk_box_pack_start (GTK_BOX (dock), dock->p->main_vbox, TRUE, TRUE, 0);
182   gtk_widget_show (dock->p->main_vbox);
183 
184   dock->p->paned_vbox = gimp_paned_box_new (FALSE, 0, GTK_ORIENTATION_VERTICAL);
185   gimp_paned_box_set_dropped_cb (GIMP_PANED_BOX (dock->p->paned_vbox),
186                                  gimp_dock_dropped_cb,
187                                  dock);
188   gtk_box_pack_start (GTK_BOX (dock->p->main_vbox), dock->p->paned_vbox,
189                       TRUE, TRUE, 0);
190   gtk_widget_show (dock->p->paned_vbox);
191 }
192 
193 static void
gimp_dock_dispose(GObject * object)194 gimp_dock_dispose (GObject *object)
195 {
196   GimpDock *dock = GIMP_DOCK (object);
197 
198   while (dock->p->dockbooks)
199     {
200       GimpDockbook *dockbook = dock->p->dockbooks->data;
201 
202       g_object_ref (dockbook);
203       gimp_dock_remove_book (dock, dockbook);
204       gtk_widget_destroy (GTK_WIDGET (dockbook));
205       g_object_unref (dockbook);
206     }
207 
208   G_OBJECT_CLASS (parent_class)->dispose (object);
209 }
210 
211 static void
gimp_dock_style_set(GtkWidget * widget,GtkStyle * prev_style)212 gimp_dock_style_set (GtkWidget *widget,
213                      GtkStyle  *prev_style)
214 {
215   GimpDock *dock       = GIMP_DOCK (widget);
216   gdouble   font_scale = 1.0;
217 
218   GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
219 
220   gtk_widget_style_get (widget,
221                         "font-scale", &font_scale,
222                         NULL);
223 
224   if (font_scale != 1.0)
225     {
226       PangoContext         *context;
227       PangoFontDescription *font_desc;
228       gint                  font_size;
229       gchar                *font_str;
230       gchar                *rc_string;
231 
232       context = gtk_widget_get_pango_context (widget);
233       font_desc = pango_context_get_font_description (context);
234       font_desc = pango_font_description_copy (font_desc);
235 
236       font_size = pango_font_description_get_size (font_desc);
237       font_size = font_scale * font_size;
238       pango_font_description_set_size (font_desc, font_size);
239 
240       font_str = pango_font_description_to_string (font_desc);
241       pango_font_description_free (font_desc);
242 
243       rc_string =
244         g_strdup_printf ("style \"gimp-dock-style\""
245                          "{"
246                          "  font_name = \"%s\""
247                          "}"
248                          "widget \"*.gimp-internal-dock-%d.*\" style \"gimp-dock-style\"",
249                          font_str,
250                          dock->p->ID);
251       g_free (font_str);
252 
253       gtk_rc_parse_string (rc_string);
254       g_free (rc_string);
255 
256       gtk_widget_reset_rc_styles (widget);
257     }
258 }
259 
260 static gchar *
gimp_dock_real_get_description(GimpDock * dock,gboolean complete)261 gimp_dock_real_get_description (GimpDock *dock,
262                                 gboolean  complete)
263 {
264   GString *desc;
265   GList   *list;
266 
267   desc = g_string_new (NULL);
268 
269   for (list = gimp_dock_get_dockbooks (dock);
270        list;
271        list = g_list_next (list))
272     {
273       GimpDockbook *dockbook = list->data;
274       GList        *children;
275       GList        *child;
276 
277       if (complete)
278         {
279           /* Include all dockables */
280           children = gtk_container_get_children (GTK_CONTAINER (dockbook));
281         }
282       else
283         {
284           GtkWidget *dockable = NULL;
285           gint       page_num = 0;
286 
287           page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (dockbook));
288           dockable = gtk_notebook_get_nth_page (GTK_NOTEBOOK (dockbook), page_num);
289 
290           /* Only include active dockables */
291           children = g_list_append (NULL, dockable);
292         }
293 
294       for (child = children; child; child = g_list_next (child))
295         {
296           GimpDockable *dockable = child->data;
297 
298           g_string_append (desc, gimp_dockable_get_name (dockable));
299 
300           if (g_list_next (child))
301             g_string_append (desc, GIMP_DOCK_DOCKABLE_SEPARATOR);
302         }
303 
304       g_list_free (children);
305 
306       if (g_list_next (list))
307         g_string_append (desc, GIMP_DOCK_BOOK_SEPARATOR);
308     }
309 
310   return g_string_free (desc, FALSE);
311 }
312 
313 static void
gimp_dock_real_book_added(GimpDock * dock,GimpDockbook * dockbook)314 gimp_dock_real_book_added (GimpDock     *dock,
315                            GimpDockbook *dockbook)
316 {
317   g_signal_connect_object (dockbook, "switch-page",
318                            G_CALLBACK (gimp_dock_invalidate_description),
319                            dock, G_CONNECT_SWAPPED);
320 }
321 
322 static void
gimp_dock_real_book_removed(GimpDock * dock,GimpDockbook * dockbook)323 gimp_dock_real_book_removed (GimpDock     *dock,
324                              GimpDockbook *dockbook)
325 {
326   g_signal_handlers_disconnect_by_func (dockbook,
327                                         gimp_dock_invalidate_description,
328                                         dock);
329 }
330 
331 static void
gimp_dock_invalidate_description(GimpDock * dock)332 gimp_dock_invalidate_description (GimpDock *dock)
333 {
334   g_return_if_fail (GIMP_IS_DOCK (dock));
335 
336   g_signal_emit (dock, dock_signals[DESCRIPTION_INVALIDATED], 0);
337 }
338 
339 static gboolean
gimp_dock_dropped_cb(GtkWidget * source,gint insert_index,gpointer data)340 gimp_dock_dropped_cb (GtkWidget *source,
341                       gint       insert_index,
342                       gpointer   data)
343 {
344   GimpDock          *dock     = GIMP_DOCK (data);
345   GimpDockable      *dockable = gimp_dockbook_drag_source_to_dockable (source);
346   GimpDialogFactory *factory;
347   GtkWidget         *dockbook = NULL;
348 
349   if (!dockable )
350     return FALSE;
351 
352   /*  if dropping to the same dock, take care that we don't try
353    *  to reorder the *only* dockable in the dock
354    */
355   if (gimp_dockbook_get_dock (gimp_dockable_get_dockbook (dockable)) == dock)
356     {
357       GList *children;
358       gint   n_books;
359       gint   n_dockables;
360 
361       n_books = g_list_length (gimp_dock_get_dockbooks (dock));
362 
363       children = gtk_container_get_children (GTK_CONTAINER (gimp_dockable_get_dockbook (dockable)));
364       n_dockables = g_list_length (children);
365       g_list_free (children);
366 
367       if (n_books == 1 && n_dockables == 1)
368         return TRUE; /* successfully do nothing */
369     }
370 
371   /* Detach the dockable from the old dockbook */
372   g_object_ref (dockable);
373   gimp_dockbook_remove (gimp_dockable_get_dockbook (dockable), dockable);
374 
375   /* Create a new dockbook */
376   factory = gimp_dock_get_dialog_factory (dock);
377   dockbook = gimp_dockbook_new (gimp_dialog_factory_get_menu_factory (factory));
378   gimp_dock_add_book (dock, GIMP_DOCKBOOK (dockbook), insert_index);
379 
380   /* Add the dockable to new new dockbook */
381   gimp_dockbook_add (GIMP_DOCKBOOK (dockbook), dockable, -1);
382   g_object_unref (dockable);
383 
384   return TRUE;
385 }
386 
387 
388 /*  public functions  */
389 
390 /**
391  * gimp_dock_get_description:
392  * @dock:
393  * @complete: If %TRUE, only includes the active dockables, i.e. not the
394  *            dockables in a non-active GtkNotebook tab
395  *
396  * Returns: A string describing the contents of the dock.
397  **/
398 gchar *
gimp_dock_get_description(GimpDock * dock,gboolean complete)399 gimp_dock_get_description (GimpDock *dock,
400                            gboolean  complete)
401 {
402   g_return_val_if_fail (GIMP_IS_DOCK (dock), NULL);
403 
404   if (GIMP_DOCK_GET_CLASS (dock)->get_description)
405     return GIMP_DOCK_GET_CLASS (dock)->get_description (dock, complete);
406 
407   return NULL;
408 }
409 
410 /**
411  * gimp_dock_set_host_geometry_hints:
412  * @dock:   The dock
413  * @window: The #GtkWindow to adapt to hosting the dock
414  *
415  * Some docks have some specific needs on the #GtkWindow they are
416  * in. This function allows such docks to perform any such setup on
417  * the #GtkWindow they are in/will be put in.
418  **/
419 void
gimp_dock_set_host_geometry_hints(GimpDock * dock,GtkWindow * window)420 gimp_dock_set_host_geometry_hints (GimpDock  *dock,
421                                    GtkWindow *window)
422 {
423   g_return_if_fail (GIMP_IS_DOCK (dock));
424   g_return_if_fail (GTK_IS_WINDOW (window));
425 
426   if (GIMP_DOCK_GET_CLASS (dock)->set_host_geometry_hints)
427     GIMP_DOCK_GET_CLASS (dock)->set_host_geometry_hints (dock, window);
428 }
429 
430 /**
431  * gimp_dock_invalidate_geometry:
432  * @dock:
433  *
434  * Call when the dock needs to setup its host #GtkWindow with
435  * GtkDock::set_host_geometry_hints().
436  **/
437 void
gimp_dock_invalidate_geometry(GimpDock * dock)438 gimp_dock_invalidate_geometry (GimpDock *dock)
439 {
440   g_return_if_fail (GIMP_IS_DOCK (dock));
441 
442   g_signal_emit (dock, dock_signals[GEOMETRY_INVALIDATED], 0);
443 }
444 
445 /**
446  * gimp_dock_update_with_context:
447  * @dock:
448  * @context:
449  *
450  * Set the @context on all dockables in the @dock.
451  **/
452 void
gimp_dock_update_with_context(GimpDock * dock,GimpContext * context)453 gimp_dock_update_with_context (GimpDock    *dock,
454                                GimpContext *context)
455 {
456   GList *iter = NULL;
457 
458   for (iter = gimp_dock_get_dockbooks (dock);
459        iter;
460        iter = g_list_next (iter))
461     {
462       GimpDockbook *dockbook = GIMP_DOCKBOOK (iter->data);
463 
464       gimp_dockbook_update_with_context (dockbook, context);
465     }
466 }
467 
468 /**
469  * gimp_dock_get_context:
470  * @dock:
471  *
472  * Returns: The #GimpContext for the #GimpDockWindow the @dock is in.
473  **/
474 GimpContext *
gimp_dock_get_context(GimpDock * dock)475 gimp_dock_get_context (GimpDock *dock)
476 {
477   GimpContext *context = NULL;
478 
479   g_return_val_if_fail (GIMP_IS_DOCK (dock), NULL);
480 
481   /* First try GimpDockColumns */
482   if (! context)
483     {
484       GimpDockColumns *dock_columns;
485 
486       dock_columns =
487         GIMP_DOCK_COLUMNS (gtk_widget_get_ancestor (GTK_WIDGET (dock),
488                                                     GIMP_TYPE_DOCK_COLUMNS));
489 
490       if (dock_columns)
491         context = gimp_dock_columns_get_context (dock_columns);
492     }
493 
494   /* Then GimpDockWindow */
495   if (! context)
496     {
497       GimpDockWindow *dock_window = gimp_dock_window_from_dock (dock);
498 
499       if (dock_window)
500         context = gimp_dock_window_get_context (dock_window);
501     }
502 
503   return context;
504 }
505 
506 /**
507  * gimp_dock_get_dialog_factory:
508  * @dock:
509  *
510  * Returns: The #GimpDialogFactory for the #GimpDockWindow the @dock
511  *          is in.
512  **/
513 GimpDialogFactory *
gimp_dock_get_dialog_factory(GimpDock * dock)514 gimp_dock_get_dialog_factory (GimpDock *dock)
515 {
516   GimpDialogFactory *dialog_factory = NULL;
517 
518   g_return_val_if_fail (GIMP_IS_DOCK (dock), NULL);
519 
520   /* First try GimpDockColumns */
521   if (! dialog_factory)
522     {
523       GimpDockColumns *dock_columns;
524 
525       dock_columns =
526         GIMP_DOCK_COLUMNS (gtk_widget_get_ancestor (GTK_WIDGET (dock),
527                                                     GIMP_TYPE_DOCK_COLUMNS));
528 
529       if (dock_columns)
530         dialog_factory = gimp_dock_columns_get_dialog_factory (dock_columns);
531     }
532 
533   /* Then GimpDockWindow */
534   if (! dialog_factory)
535     {
536       GimpDockWindow *dock_window = gimp_dock_window_from_dock (dock);
537 
538       if (dock_window)
539         dialog_factory = gimp_dock_container_get_dialog_factory (GIMP_DOCK_CONTAINER (dock_window));
540     }
541 
542   return dialog_factory;
543 }
544 
545 /**
546  * gimp_dock_get_ui_manager:
547  * @dock:
548  *
549  * Returns: The #GimpUIManager for the #GimpDockWindow the @dock is
550  *          in.
551  **/
552 GimpUIManager *
gimp_dock_get_ui_manager(GimpDock * dock)553 gimp_dock_get_ui_manager (GimpDock *dock)
554 {
555   GimpUIManager *ui_manager = NULL;
556 
557   g_return_val_if_fail (GIMP_IS_DOCK (dock), NULL);
558 
559   /* First try GimpDockColumns */
560   if (! ui_manager)
561     {
562       GimpDockColumns *dock_columns;
563 
564       dock_columns =
565         GIMP_DOCK_COLUMNS (gtk_widget_get_ancestor (GTK_WIDGET (dock),
566                                                     GIMP_TYPE_DOCK_COLUMNS));
567 
568       if (dock_columns)
569         ui_manager = gimp_dock_columns_get_ui_manager (dock_columns);
570     }
571 
572   /* Then GimpDockContainer */
573   if (! ui_manager)
574     {
575       GimpDockWindow *dock_window = gimp_dock_window_from_dock (dock);
576 
577       if (dock_window)
578         {
579           GimpDockContainer *dock_container = GIMP_DOCK_CONTAINER (dock_window);
580 
581           ui_manager = gimp_dock_container_get_ui_manager (dock_container);
582         }
583     }
584 
585   return ui_manager;
586 }
587 
588 GList *
gimp_dock_get_dockbooks(GimpDock * dock)589 gimp_dock_get_dockbooks (GimpDock *dock)
590 {
591   g_return_val_if_fail (GIMP_IS_DOCK (dock), NULL);
592 
593   return dock->p->dockbooks;
594 }
595 
596 gint
gimp_dock_get_n_dockables(GimpDock * dock)597 gimp_dock_get_n_dockables (GimpDock *dock)
598 {
599   GList *list = NULL;
600   gint   n    = 0;
601 
602   g_return_val_if_fail (GIMP_IS_DOCK (dock), 0);
603 
604   for (list = dock->p->dockbooks; list; list = list->next)
605     n += gtk_notebook_get_n_pages (GTK_NOTEBOOK (list->data));
606 
607   return n;
608 }
609 
610 GtkWidget *
gimp_dock_get_main_vbox(GimpDock * dock)611 gimp_dock_get_main_vbox (GimpDock *dock)
612 {
613   g_return_val_if_fail (GIMP_IS_DOCK (dock), NULL);
614 
615   return dock->p->main_vbox;
616 }
617 
618 GtkWidget *
gimp_dock_get_vbox(GimpDock * dock)619 gimp_dock_get_vbox (GimpDock *dock)
620 {
621   g_return_val_if_fail (GIMP_IS_DOCK (dock), NULL);
622 
623   return dock->p->paned_vbox;
624 }
625 
626 gint
gimp_dock_get_id(GimpDock * dock)627 gimp_dock_get_id (GimpDock *dock)
628 {
629   g_return_val_if_fail (GIMP_IS_DOCK (dock), 0);
630 
631   return dock->p->ID;
632 }
633 
634 void
gimp_dock_set_id(GimpDock * dock,gint ID)635 gimp_dock_set_id (GimpDock *dock,
636                   gint      ID)
637 {
638   g_return_if_fail (GIMP_IS_DOCK (dock));
639 
640   dock->p->ID = ID;
641 }
642 
643 void
gimp_dock_add(GimpDock * dock,GimpDockable * dockable,gint section,gint position)644 gimp_dock_add (GimpDock     *dock,
645                GimpDockable *dockable,
646                gint          section,
647                gint          position)
648 {
649   GimpDockbook *dockbook;
650 
651   g_return_if_fail (GIMP_IS_DOCK (dock));
652   g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
653   g_return_if_fail (gimp_dockable_get_dockbook (dockable) == NULL);
654 
655   dockbook = GIMP_DOCKBOOK (dock->p->dockbooks->data);
656 
657   gimp_dockbook_add (dockbook, dockable, position);
658 }
659 
660 void
gimp_dock_remove(GimpDock * dock,GimpDockable * dockable)661 gimp_dock_remove (GimpDock     *dock,
662                   GimpDockable *dockable)
663 {
664   g_return_if_fail (GIMP_IS_DOCK (dock));
665   g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
666   g_return_if_fail (gimp_dockable_get_dockbook (dockable) != NULL);
667   g_return_if_fail (gimp_dockbook_get_dock (gimp_dockable_get_dockbook (dockable)) == dock);
668 
669   gimp_dockbook_remove (gimp_dockable_get_dockbook (dockable), dockable);
670 }
671 
672 void
gimp_dock_add_book(GimpDock * dock,GimpDockbook * dockbook,gint index)673 gimp_dock_add_book (GimpDock     *dock,
674                     GimpDockbook *dockbook,
675                     gint          index)
676 {
677   g_return_if_fail (GIMP_IS_DOCK (dock));
678   g_return_if_fail (GIMP_IS_DOCKBOOK (dockbook));
679   g_return_if_fail (gimp_dockbook_get_dock (dockbook) == NULL);
680 
681   gimp_dockbook_set_dock (dockbook, dock);
682 
683   g_signal_connect_object (dockbook, "dockable-added",
684                            G_CALLBACK (gimp_dock_invalidate_description),
685                            dock, G_CONNECT_SWAPPED);
686   g_signal_connect_object (dockbook, "dockable-removed",
687                            G_CALLBACK (gimp_dock_invalidate_description),
688                            dock, G_CONNECT_SWAPPED);
689   g_signal_connect_object (dockbook, "dockable-reordered",
690                            G_CALLBACK (gimp_dock_invalidate_description),
691                            dock, G_CONNECT_SWAPPED);
692 
693   dock->p->dockbooks = g_list_insert (dock->p->dockbooks, dockbook, index);
694   gimp_paned_box_add_widget (GIMP_PANED_BOX (dock->p->paned_vbox),
695                              GTK_WIDGET (dockbook),
696                              index);
697   gtk_widget_show (GTK_WIDGET (dockbook));
698 
699   gimp_dock_invalidate_description (dock);
700 
701   g_signal_emit (dock, dock_signals[BOOK_ADDED], 0, dockbook);
702 }
703 
704 void
gimp_dock_remove_book(GimpDock * dock,GimpDockbook * dockbook)705 gimp_dock_remove_book (GimpDock     *dock,
706                        GimpDockbook *dockbook)
707 {
708   g_return_if_fail (GIMP_IS_DOCK (dock));
709   g_return_if_fail (GIMP_IS_DOCKBOOK (dockbook));
710   g_return_if_fail (gimp_dockbook_get_dock (dockbook) == dock);
711 
712   gimp_dockbook_set_dock (dockbook, NULL);
713 
714   g_signal_handlers_disconnect_by_func (dockbook,
715                                         gimp_dock_invalidate_description,
716                                         dock);
717 
718   /* Ref the dockbook so we can emit the "book-removed" signal and
719    * pass it as a parameter before it's destroyed
720    */
721   g_object_ref (dockbook);
722 
723   dock->p->dockbooks = g_list_remove (dock->p->dockbooks, dockbook);
724   gimp_paned_box_remove_widget (GIMP_PANED_BOX (dock->p->paned_vbox),
725                                 GTK_WIDGET (dockbook));
726 
727   gimp_dock_invalidate_description (dock);
728 
729   g_signal_emit (dock, dock_signals[BOOK_REMOVED], 0, dockbook);
730 
731   g_object_unref (dockbook);
732 }
733 
734 /**
735  * gimp_dock_temp_add:
736  * @dock:
737  * @widget:
738  *
739  * Method to temporarily add a widget to the dock, for example to make
740  * font-scale style property to be applied temporarily to the
741  * child.
742  **/
743 void
gimp_dock_temp_add(GimpDock * dock,GtkWidget * child)744 gimp_dock_temp_add (GimpDock  *dock,
745                     GtkWidget *child)
746 {
747   g_return_if_fail (GIMP_IS_DOCK (dock));
748   g_return_if_fail (GTK_IS_WIDGET (child));
749 
750   gtk_box_pack_start (GTK_BOX (dock->p->temp_vbox), child, FALSE, FALSE, 0);
751 }
752 
753 /**
754  * gimp_dock_temp_remove:
755  * @dock:
756  * @child:
757  *
758  * Removes a temporary child added with gimp_dock_temp_add().
759  **/
760 void
gimp_dock_temp_remove(GimpDock * dock,GtkWidget * child)761 gimp_dock_temp_remove (GimpDock  *dock,
762                        GtkWidget *child)
763 {
764   g_return_if_fail (GIMP_IS_DOCK (dock));
765   g_return_if_fail (GTK_IS_WIDGET (child));
766 
767   gtk_container_remove (GTK_CONTAINER (dock->p->temp_vbox), child);
768 }
769