1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimpdockbook.c
5  * Copyright (C) 2001-2007 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 <string.h>
24 
25 #include <gegl.h>
26 #include <gtk/gtk.h>
27 
28 #include "libgimpwidgets/gimpwidgets.h"
29 
30 #include "widgets-types.h"
31 
32 #include "config/gimpguiconfig.h"
33 
34 #include "core/gimp.h"
35 #include "core/gimpcontext.h"
36 #include "core/gimpmarshal.h"
37 
38 #include "gimpactiongroup.h"
39 #include "gimpdialogfactory.h"
40 #include "gimpdnd.h"
41 #include "gimpdock.h"
42 #include "gimpdockable.h"
43 #include "gimpdockbook.h"
44 #include "gimpdocked.h"
45 #include "gimpdockcontainer.h"
46 #include "gimpdockwindow.h"
47 #include "gimphelp-ids.h"
48 #include "gimpmenufactory.h"
49 #include "gimppanedbox.h"
50 #include "gimpstringaction.h"
51 #include "gimpuimanager.h"
52 #include "gimpview.h"
53 #include "gimpwidgets-utils.h"
54 
55 #include "gimp-log.h"
56 #include "gimp-intl.h"
57 
58 #define DEFAULT_TAB_BORDER           0
59 #define DEFAULT_TAB_ICON_SIZE        GTK_ICON_SIZE_BUTTON
60 #define DND_WIDGET_ICON_SIZE         GTK_ICON_SIZE_BUTTON
61 #define MENU_WIDGET_ICON_SIZE        GTK_ICON_SIZE_MENU
62 #define MENU_WIDGET_SPACING          4
63 #define TAB_HOVER_TIMEOUT            500
64 #define GIMP_DOCKABLE_DETACH_REF_KEY "gimp-dockable-detach-ref"
65 
66 
67 enum
68 {
69   DOCKABLE_ADDED,
70   DOCKABLE_REMOVED,
71   DOCKABLE_REORDERED,
72   LAST_SIGNAL
73 };
74 
75 /* List of candidates for the automatic style, starting with the
76  * biggest first
77  */
78 static const GimpTabStyle gimp_tab_style_candidates[] =
79 {
80   GIMP_TAB_STYLE_PREVIEW_BLURB,
81   GIMP_TAB_STYLE_PREVIEW_NAME,
82   GIMP_TAB_STYLE_PREVIEW
83 };
84 
85 
86 typedef struct
87 {
88   GimpDockbookDragCallback callback;
89   gpointer                 data;
90 } GimpDockbookDragCallbackData;
91 
92 struct _GimpDockbookPrivate
93 {
94   GimpDock       *dock;
95   GimpUIManager  *ui_manager;
96 
97   guint           tab_hover_timeout;
98   GimpDockable   *tab_hover_dockable;
99 
100   GimpPanedBox   *drag_handler;
101 
102   /* Cache for "what actual tab style for automatic styles can we use
103    * for a given dockbook width
104    */
105   gint            min_width_for_style[G_N_ELEMENTS (gimp_tab_style_candidates)];
106 
107   /* We need a list separate from the GtkContainer children list,
108    * because we need to do calculations for all dockables before we
109    * can add a dockable as a child, namely automatic tab style
110    * calculations
111    */
112   GList          *dockables;
113 
114   GtkWidget      *menu_button;
115 };
116 
117 
118 static void         gimp_dockbook_dispose                     (GObject        *object);
119 static void         gimp_dockbook_finalize                    (GObject        *object);
120 static void         gimp_dockbook_size_allocate               (GtkWidget      *widget,
121                                                                GtkAllocation  *allocation);
122 static void         gimp_dockbook_style_set                   (GtkWidget      *widget,
123                                                                GtkStyle       *prev_style);
124 static void         gimp_dockbook_drag_leave                  (GtkWidget      *widget,
125                                                                GdkDragContext *context,
126                                                                guint           time);
127 static gboolean     gimp_dockbook_drag_motion                 (GtkWidget      *widget,
128                                                                GdkDragContext *context,
129                                                                gint            x,
130                                                                gint            y,
131                                                                guint           time);
132 static gboolean     gimp_dockbook_drag_drop                   (GtkWidget      *widget,
133                                                                GdkDragContext *context,
134                                                                gint            x,
135                                                                gint            y,
136                                                                guint           time);
137 static gboolean     gimp_dockbook_popup_menu                  (GtkWidget      *widget);
138 static gboolean     gimp_dockbook_menu_button_press           (GimpDockbook   *dockbook,
139                                                                GdkEventButton *bevent,
140                                                                GtkWidget      *button);
141 static gboolean     gimp_dockbook_show_menu                   (GimpDockbook   *dockbook);
142 static void         gimp_dockbook_menu_end                    (GimpDockable   *dockable);
143 static void         gimp_dockbook_dockable_added              (GimpDockbook   *dockbook,
144                                                                GimpDockable   *dockable);
145 static void         gimp_dockbook_dockable_removed            (GimpDockbook   *dockbook,
146                                                                GimpDockable   *dockable);
147 static void         gimp_dockbook_recreate_tab_widgets        (GimpDockbook   *dockbook,
148                                                                gboolean        only_auto);
149 static void         gimp_dockbook_tab_drag_source_setup       (GtkWidget      *widget,
150                                                                GimpDockable   *dockable);
151 static void         gimp_dockbook_tab_drag_begin              (GtkWidget      *widget,
152                                                                GdkDragContext *context,
153                                                                GimpDockable   *dockable);
154 static void         gimp_dockbook_tab_drag_end                (GtkWidget      *widget,
155                                                                GdkDragContext *context,
156                                                                GimpDockable   *dockable);
157 static gboolean     gimp_dockbook_tab_drag_failed             (GtkWidget      *widget,
158                                                                GdkDragContext *context,
159                                                                GtkDragResult   result,
160                                                                GimpDockable   *dockable);
161 static void         gimp_dockbook_tab_drag_leave              (GtkWidget      *widget,
162                                                                GdkDragContext *context,
163                                                                guint           time,
164                                                                GimpDockable   *dockable);
165 static gboolean     gimp_dockbook_tab_drag_motion             (GtkWidget      *widget,
166                                                                GdkDragContext *context,
167                                                                gint            x,
168                                                                gint            y,
169                                                                guint           time,
170                                                                GimpDockable   *dockable);
171 static gboolean     gimp_dockbook_tab_drag_drop               (GtkWidget      *widget,
172                                                                GdkDragContext *context,
173                                                                gint            x,
174                                                                gint            y,
175                                                                guint           time);
176 static GimpTabStyle gimp_dockbook_tab_style_to_preferred       (GimpTabStyle    tab_style,
177                                                                GimpDockable   *dockable);
178 static void         gimp_dockbook_refresh_tab_layout_lut      (GimpDockbook   *dockbook);
179 static void         gimp_dockbook_update_automatic_tab_style  (GimpDockbook   *dockbook);
180 static GtkWidget *  gimp_dockable_create_event_box_tab_widget (GimpDockable   *dockable,
181                                                                GimpContext    *context,
182                                                                GimpTabStyle    tab_style,
183                                                                GtkIconSize     size);
184 static GtkIconSize  gimp_dockbook_get_tab_icon_size           (GimpDockbook   *dockbook);
185 static gint         gimp_dockbook_get_tab_border              (GimpDockbook   *dockbook);
186 static void         gimp_dockbook_add_tab_timeout             (GimpDockbook   *dockbook,
187                                                                GimpDockable   *dockable);
188 static void         gimp_dockbook_remove_tab_timeout          (GimpDockbook   *dockbook);
189 static gboolean     gimp_dockbook_tab_timeout                 (GimpDockbook   *dockbook);
190 static void         gimp_dockbook_tab_locked_notify           (GimpDockable   *dockable,
191                                                                GParamSpec     *pspec,
192                                                                GimpDockbook   *dockbook);
193 static void         gimp_dockbook_help_func                   (const gchar    *help_id,
194                                                                gpointer        help_data);
195 static const gchar *gimp_dockbook_get_tab_style_name          (GimpTabStyle    tab_style);
196 
197 static void         gimp_dockbook_config_size_changed         (GimpGuiConfig   *config,
198                                                                GimpDockbook    *dockbook);
199 
200 
201 G_DEFINE_TYPE_WITH_PRIVATE (GimpDockbook, gimp_dockbook, GTK_TYPE_NOTEBOOK)
202 
203 #define parent_class gimp_dockbook_parent_class
204 
205 static guint dockbook_signals[LAST_SIGNAL] = { 0 };
206 
207 static const GtkTargetEntry dialog_target_table[] = { GIMP_TARGET_DIALOG };
208 
209 static GList *drag_callbacks = NULL;
210 
211 
212 static void
gimp_dockbook_class_init(GimpDockbookClass * klass)213 gimp_dockbook_class_init (GimpDockbookClass *klass)
214 {
215   GObjectClass   *object_class = G_OBJECT_CLASS (klass);
216   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
217 
218   dockbook_signals[DOCKABLE_ADDED] =
219     g_signal_new ("dockable-added",
220                   G_TYPE_FROM_CLASS (klass),
221                   G_SIGNAL_RUN_FIRST,
222                   G_STRUCT_OFFSET (GimpDockbookClass, dockable_added),
223                   NULL, NULL,
224                   gimp_marshal_VOID__OBJECT,
225                   G_TYPE_NONE, 1,
226                   GIMP_TYPE_DOCKABLE);
227 
228   dockbook_signals[DOCKABLE_REMOVED] =
229     g_signal_new ("dockable-removed",
230                   G_TYPE_FROM_CLASS (klass),
231                   G_SIGNAL_RUN_FIRST,
232                   G_STRUCT_OFFSET (GimpDockbookClass, dockable_removed),
233                   NULL, NULL,
234                   gimp_marshal_VOID__OBJECT,
235                   G_TYPE_NONE, 1,
236                   GIMP_TYPE_DOCKABLE);
237 
238   dockbook_signals[DOCKABLE_REORDERED] =
239     g_signal_new ("dockable-reordered",
240                   G_TYPE_FROM_CLASS (klass),
241                   G_SIGNAL_RUN_FIRST,
242                   G_STRUCT_OFFSET (GimpDockbookClass, dockable_reordered),
243                   NULL, NULL,
244                   gimp_marshal_VOID__OBJECT,
245                   G_TYPE_NONE, 1,
246                   GIMP_TYPE_DOCKABLE);
247 
248   object_class->dispose     = gimp_dockbook_dispose;
249   object_class->finalize    = gimp_dockbook_finalize;
250 
251   widget_class->size_allocate = gimp_dockbook_size_allocate;
252   widget_class->style_set     = gimp_dockbook_style_set;
253   widget_class->drag_leave    = gimp_dockbook_drag_leave;
254   widget_class->drag_motion   = gimp_dockbook_drag_motion;
255   widget_class->drag_drop     = gimp_dockbook_drag_drop;
256   widget_class->popup_menu    = gimp_dockbook_popup_menu;
257 
258   klass->dockable_added     = gimp_dockbook_dockable_added;
259   klass->dockable_removed   = gimp_dockbook_dockable_removed;
260   klass->dockable_reordered = NULL;
261 
262   gtk_widget_class_install_style_property (widget_class,
263                                            g_param_spec_int ("tab-border",
264                                                              NULL, NULL,
265                                                              0, G_MAXINT,
266                                                              DEFAULT_TAB_BORDER,
267                                                              GIMP_PARAM_READABLE));
268   gtk_widget_class_install_style_property (widget_class,
269                                            g_param_spec_enum ("tab-icon-size",
270                                                               NULL, NULL,
271                                                               GTK_TYPE_ICON_SIZE,
272                                                               DEFAULT_TAB_ICON_SIZE,
273                                                               GIMP_PARAM_READABLE));
274 }
275 
276 static void
gimp_dockbook_init(GimpDockbook * dockbook)277 gimp_dockbook_init (GimpDockbook *dockbook)
278 {
279   GtkNotebook *notebook = GTK_NOTEBOOK (dockbook);
280   GtkWidget   *image    = NULL;
281 
282   dockbook->p = gimp_dockbook_get_instance_private (dockbook);
283 
284   /* Various init */
285   gtk_notebook_popup_enable (notebook);
286   gtk_notebook_set_scrollable (notebook, TRUE);
287   gtk_notebook_set_show_border (notebook, FALSE);
288   gtk_notebook_set_show_tabs (notebook, TRUE);
289 
290   gtk_drag_dest_set (GTK_WIDGET (dockbook),
291                      0,
292                      dialog_target_table, G_N_ELEMENTS (dialog_target_table),
293                      GDK_ACTION_MOVE);
294 
295   /* Menu button */
296   dockbook->p->menu_button = gtk_button_new ();
297   gtk_widget_set_can_focus (dockbook->p->menu_button, FALSE);
298   gtk_button_set_relief (GTK_BUTTON (dockbook->p->menu_button),
299                          GTK_RELIEF_NONE);
300   gtk_notebook_set_action_widget (notebook,
301                                   dockbook->p->menu_button,
302                                   GTK_PACK_END);
303   gtk_widget_show (dockbook->p->menu_button);
304 
305   image = gtk_image_new_from_icon_name (GIMP_ICON_MENU_LEFT,
306                                         GTK_ICON_SIZE_MENU);
307   gtk_image_set_pixel_size (GTK_IMAGE (image), 12);
308   gtk_image_set_from_icon_name (GTK_IMAGE (image), GIMP_ICON_MENU_LEFT,
309                                 GTK_ICON_SIZE_MENU);
310   gtk_container_add (GTK_CONTAINER (dockbook->p->menu_button), image);
311   gtk_widget_show (image);
312 
313   gimp_help_set_help_data (dockbook->p->menu_button, _("Configure this tab"),
314                            GIMP_HELP_DOCK_TAB_MENU);
315 
316   g_signal_connect_swapped (dockbook->p->menu_button, "button-press-event",
317                             G_CALLBACK (gimp_dockbook_menu_button_press),
318                             dockbook);
319 }
320 
321 static void
gimp_dockbook_dispose(GObject * object)322 gimp_dockbook_dispose (GObject *object)
323 {
324   GimpDockbook *dockbook = GIMP_DOCKBOOK (object);
325 
326   g_signal_handlers_disconnect_by_func (dockbook->p->ui_manager->gimp->config,
327                                         gimp_dockbook_config_size_changed,
328                                         dockbook);
329 
330   gimp_dockbook_remove_tab_timeout (dockbook);
331 
332   while (dockbook->p->dockables)
333     {
334       GimpDockable *dockable = dockbook->p->dockables->data;
335 
336       g_object_ref (dockable);
337       gimp_dockbook_remove (dockbook, dockable);
338       gtk_widget_destroy (GTK_WIDGET (dockable));
339       g_object_unref (dockable);
340     }
341 
342   G_OBJECT_CLASS (parent_class)->dispose (object);
343 }
344 
345 static void
gimp_dockbook_finalize(GObject * object)346 gimp_dockbook_finalize (GObject *object)
347 {
348   GimpDockbook *dockbook = GIMP_DOCKBOOK (object);
349 
350   g_clear_object (&dockbook->p->ui_manager);
351 
352   G_OBJECT_CLASS (parent_class)->finalize (object);
353 }
354 
355 static void
gimp_dockbook_size_allocate(GtkWidget * widget,GtkAllocation * allocation)356 gimp_dockbook_size_allocate (GtkWidget      *widget,
357                              GtkAllocation  *allocation)
358 {
359   GimpDockbook *dockbook = GIMP_DOCKBOOK (widget);
360 
361   GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
362 
363   /* Update tab styles, also recreates if changed */
364   gimp_dockbook_update_automatic_tab_style (dockbook);
365 }
366 
367 static void
gimp_dockbook_style_set(GtkWidget * widget,GtkStyle * prev_style)368 gimp_dockbook_style_set (GtkWidget *widget,
369                          GtkStyle  *prev_style)
370 {
371   GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
372 
373   /* Don't attempt to construct widgets that require a GimpContext if
374    * we are detached from a top-level, we're either on our way to
375    * destruction, in which case we don't care, or we will be given a
376    * new parent, in which case the widget style will be reset again
377    * anyway, i.e. this function will be called again
378    */
379   if (! gtk_widget_is_toplevel (gtk_widget_get_toplevel (widget)))
380     return;
381 
382   gimp_dockbook_recreate_tab_widgets (GIMP_DOCKBOOK (widget),
383                                       FALSE /*only_auto*/);
384 }
385 
386 static void
gimp_dockbook_drag_leave(GtkWidget * widget,GdkDragContext * context,guint time)387 gimp_dockbook_drag_leave (GtkWidget      *widget,
388                           GdkDragContext *context,
389                           guint           time)
390 {
391   gimp_highlight_widget (widget, FALSE);
392 }
393 
394 static gboolean
gimp_dockbook_drag_motion(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time)395 gimp_dockbook_drag_motion (GtkWidget      *widget,
396                            GdkDragContext *context,
397                            gint            x,
398                            gint            y,
399                            guint           time)
400 {
401   GimpDockbook *dockbook = GIMP_DOCKBOOK (widget);
402 
403   if (gimp_paned_box_will_handle_drag (dockbook->p->drag_handler,
404                                        widget,
405                                        context,
406                                        x, y,
407                                        time))
408     {
409       gdk_drag_status (context, 0, time);
410       gimp_highlight_widget (widget, FALSE);
411 
412       return FALSE;
413     }
414 
415   gdk_drag_status (context, GDK_ACTION_MOVE, time);
416   gimp_highlight_widget (widget, TRUE);
417 
418   /* Return TRUE so drag_leave() is called */
419   return TRUE;
420 }
421 
422 static gboolean
gimp_dockbook_drag_drop(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time)423 gimp_dockbook_drag_drop (GtkWidget      *widget,
424                          GdkDragContext *context,
425                          gint            x,
426                          gint            y,
427                          guint           time)
428 {
429   GimpDockbook *dockbook = GIMP_DOCKBOOK (widget);
430   gboolean      dropped;
431 
432   if (gimp_paned_box_will_handle_drag (dockbook->p->drag_handler,
433                                        widget,
434                                        context,
435                                        x, y,
436                                        time))
437     {
438       return FALSE;
439     }
440 
441   dropped = gimp_dockbook_drop_dockable (dockbook,
442                                          gtk_drag_get_source_widget (context));
443 
444   gtk_drag_finish (context, dropped, TRUE, time);
445 
446   return TRUE;
447 }
448 
449 static gboolean
gimp_dockbook_popup_menu(GtkWidget * widget)450 gimp_dockbook_popup_menu (GtkWidget *widget)
451 {
452   return gimp_dockbook_show_menu (GIMP_DOCKBOOK (widget));
453 }
454 
455 static gboolean
gimp_dockbook_menu_button_press(GimpDockbook * dockbook,GdkEventButton * bevent,GtkWidget * button)456 gimp_dockbook_menu_button_press (GimpDockbook   *dockbook,
457                                  GdkEventButton *bevent,
458                                  GtkWidget      *button)
459 {
460   gboolean handled = FALSE;
461 
462   if (bevent->button == 1 && bevent->type == GDK_BUTTON_PRESS)
463     handled = gimp_dockbook_show_menu (dockbook);
464 
465   return handled;
466 }
467 
468 static void
gimp_dockbook_menu_position(GtkMenu * menu,gint * x,gint * y,gpointer data)469 gimp_dockbook_menu_position (GtkMenu  *menu,
470                              gint     *x,
471                              gint     *y,
472                              gpointer  data)
473 {
474   GimpDockbook *dockbook = GIMP_DOCKBOOK (data);
475 
476   gimp_button_menu_position (dockbook->p->menu_button, menu, GTK_POS_LEFT, x, y);
477 }
478 
479 static gboolean
gimp_dockbook_show_menu(GimpDockbook * dockbook)480 gimp_dockbook_show_menu (GimpDockbook *dockbook)
481 {
482   GimpUIManager *dockbook_ui_manager;
483   GimpUIManager *dialog_ui_manager;
484   const gchar   *dialog_ui_path;
485   gpointer       dialog_popup_data;
486   GtkWidget     *parent_menu_widget;
487   GimpAction    *parent_menu_action;
488   GimpDockable  *dockable;
489   gint           page_num;
490 
491   dockbook_ui_manager = gimp_dockbook_get_ui_manager (dockbook);
492 
493   if (! dockbook_ui_manager)
494     return FALSE;
495 
496   parent_menu_widget =
497     gimp_ui_manager_get_widget (dockbook_ui_manager,
498                                 "/dockable-popup/dockable-menu");
499   parent_menu_action =
500     gimp_ui_manager_get_action (dockbook_ui_manager,
501                                 "/dockable-popup/dockable-menu");
502 
503   if (! parent_menu_widget || ! parent_menu_action)
504     return FALSE;
505 
506   page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (dockbook));
507   dockable = GIMP_DOCKABLE (gtk_notebook_get_nth_page (GTK_NOTEBOOK (dockbook),
508                                                        page_num));
509 
510   if (! dockable)
511     return FALSE;
512 
513   dialog_ui_manager = gimp_dockable_get_menu (dockable,
514                                               &dialog_ui_path,
515                                               &dialog_popup_data);
516 
517   if (dialog_ui_manager && dialog_ui_path)
518     {
519       GtkWidget  *child_menu_widget;
520       GimpAction *child_menu_action;
521       gchar      *label;
522 
523       child_menu_widget =
524         gimp_ui_manager_get_widget (dialog_ui_manager, dialog_ui_path);
525 
526       if (! child_menu_widget)
527         {
528           g_warning ("%s: UI manager '%s' has no widget at path '%s'",
529                      G_STRFUNC, dialog_ui_manager->name, dialog_ui_path);
530           return FALSE;
531         }
532 
533       child_menu_action =
534         gimp_ui_manager_get_action (dialog_ui_manager,
535                                     dialog_ui_path);
536 
537       if (! child_menu_action)
538         {
539           g_warning ("%s: UI manager '%s' has no action at path '%s'",
540                      G_STRFUNC, dialog_ui_manager->name, dialog_ui_path);
541           return FALSE;
542         }
543 
544       g_object_get (child_menu_action,
545                     "label", &label,
546                     NULL);
547 
548       g_object_set (parent_menu_action,
549                     "label",     label,
550                     "icon-name", gimp_dockable_get_icon_name (dockable),
551                     "visible",   TRUE,
552                     NULL);
553 
554       g_free (label);
555 
556       if (! GTK_IS_MENU (child_menu_widget))
557         {
558           g_warning ("%s: child_menu_widget (%p) is not a GtkMenu",
559                      G_STRFUNC, child_menu_widget);
560           return FALSE;
561         }
562 
563       {
564         GtkWidget *image = gimp_dockable_get_icon (dockable,
565                                                    GTK_ICON_SIZE_MENU);
566 
567         gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (parent_menu_widget),
568                                        image);
569         gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (parent_menu_widget),
570                                                    TRUE);
571         gtk_widget_show (image);
572       }
573 
574       gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent_menu_widget),
575                                  child_menu_widget);
576 
577       gimp_ui_manager_update (dialog_ui_manager, dialog_popup_data);
578     }
579   else
580     {
581       g_object_set (parent_menu_action, "visible", FALSE, NULL);
582     }
583 
584   /*  an action callback may destroy both dockable and dockbook, so
585    *  reference them for gimp_dockbook_menu_end()
586    */
587   g_object_ref (dockable);
588   g_object_set_data_full (G_OBJECT (dockable), GIMP_DOCKABLE_DETACH_REF_KEY,
589                           g_object_ref (dockbook),
590                           g_object_unref);
591 
592   gimp_ui_manager_update (dockbook_ui_manager, dockable);
593   gimp_ui_manager_ui_popup (dockbook_ui_manager, "/dockable-popup",
594                             GTK_WIDGET (dockable),
595                             gimp_dockbook_menu_position, dockbook,
596                             (GDestroyNotify) gimp_dockbook_menu_end, dockable);
597 
598   return TRUE;
599 }
600 
601 static void
gimp_dockbook_menu_end(GimpDockable * dockable)602 gimp_dockbook_menu_end (GimpDockable *dockable)
603 {
604   GimpUIManager *dialog_ui_manager;
605   const gchar   *dialog_ui_path;
606   gpointer       dialog_popup_data;
607 
608   dialog_ui_manager = gimp_dockable_get_menu (dockable,
609                                               &dialog_ui_path,
610                                               &dialog_popup_data);
611 
612   if (dialog_ui_manager && dialog_ui_path)
613     {
614       GtkWidget *child_menu_widget =
615         gimp_ui_manager_get_widget (dialog_ui_manager, dialog_ui_path);
616 
617       if (child_menu_widget)
618         gtk_menu_detach (GTK_MENU (child_menu_widget));
619     }
620 
621   /*  release gimp_dockbook_show_menu()'s references  */
622   g_object_set_data (G_OBJECT (dockable), GIMP_DOCKABLE_DETACH_REF_KEY, NULL);
623   g_object_unref (dockable);
624 }
625 
626 static void
gimp_dockbook_dockable_added(GimpDockbook * dockbook,GimpDockable * dockable)627 gimp_dockbook_dockable_added (GimpDockbook *dockbook,
628                               GimpDockable *dockable)
629 {
630   gtk_notebook_set_current_page (GTK_NOTEBOOK (dockbook),
631                                  gtk_notebook_page_num (GTK_NOTEBOOK (dockbook),
632                                                         GTK_WIDGET (dockable)));
633 }
634 
635 static void
gimp_dockbook_dockable_removed(GimpDockbook * dockbook,GimpDockable * dockable)636 gimp_dockbook_dockable_removed (GimpDockbook *dockbook,
637                                 GimpDockable *dockable)
638 {
639 }
640 
641 /**
642  * gimp_dockbook_get_dockable_tab_width:
643  * @dockable:
644  * @tab_style:
645  *
646  * Returns: Width of tab when the dockable is using the specified tab
647  *          style.
648  **/
649 static gint
gimp_dockbook_get_dockable_tab_width(GimpDockbook * dockbook,GimpDockable * dockable,GimpTabStyle tab_style)650 gimp_dockbook_get_dockable_tab_width (GimpDockbook *dockbook,
651                                       GimpDockable *dockable,
652                                       GimpTabStyle  tab_style)
653 {
654   GtkRequisition  dockable_request;
655   GtkWidget      *tab_widget;
656 
657   tab_widget =
658     gimp_dockable_create_event_box_tab_widget (dockable,
659                                                gimp_dock_get_context (dockbook->p->dock),
660                                                tab_style,
661                                                gimp_dockbook_get_tab_icon_size (dockbook));
662 
663   /* So font-scale is applied. We can't apply styles without having a
664    * GdkScreen :(
665    */
666   gimp_dock_temp_add (dockbook->p->dock, tab_widget);
667 
668   gtk_widget_size_request (tab_widget, &dockable_request);
669 
670   /* Also destroys the widget */
671   gimp_dock_temp_remove (dockbook->p->dock, tab_widget);
672 
673   return dockable_request.width;
674 }
675 
676 /**
677  * gimp_dockbook_tab_style_to_preferred:
678  * @tab_style:
679  * @dockable:
680  *
681  * The list of tab styles to try in automatic mode only consists of
682  * preview styles. For some dockables, like the tool options dockable,
683  * we rather want to use the icon tab styles for the automatic
684  * mode. This function is used to convert tab styles for such
685  * dockables.
686  *
687  * Returns: An icon tab style if the dockable prefers icon tab styles
688  *          in automatic mode.
689  **/
690 static GimpTabStyle
gimp_dockbook_tab_style_to_preferred(GimpTabStyle tab_style,GimpDockable * dockable)691 gimp_dockbook_tab_style_to_preferred (GimpTabStyle  tab_style,
692                                      GimpDockable *dockable)
693 {
694   GimpDocked *docked = GIMP_DOCKED (gtk_bin_get_child (GTK_BIN (dockable)));
695 
696   if (gimp_docked_get_prefer_icon (docked))
697     tab_style = gimp_preview_tab_style_to_icon (tab_style);
698 
699   return tab_style;
700 }
701 
702 /**
703  * gimp_dockbook_refresh_tab_layout_lut:
704  * @dockbook:
705  *
706  * For each given set of tab widgets, there is a fixed mapping between
707  * the width of the dockbook and the actual tab style to use for auto
708  * tab widgets. This function refreshes that look-up table.
709  **/
710 static void
gimp_dockbook_refresh_tab_layout_lut(GimpDockbook * dockbook)711 gimp_dockbook_refresh_tab_layout_lut (GimpDockbook *dockbook)
712 {
713   GList *auto_dockables        = NULL;
714   GList *iter                  = NULL;
715   gint   fixed_tab_style_space = 0;
716   int    i                     = 0;
717 
718   /* Calculate space taken by dockables with fixed tab styles */
719   fixed_tab_style_space = 0;
720   for (iter = dockbook->p->dockables; iter; iter = g_list_next (iter))
721     {
722       GimpDockable *dockable  = GIMP_DOCKABLE (iter->data);
723       GimpTabStyle  tab_style = gimp_dockable_get_tab_style (dockable);
724 
725       if (tab_style == GIMP_TAB_STYLE_AUTOMATIC)
726         auto_dockables = g_list_prepend (auto_dockables, dockable);
727       else
728         fixed_tab_style_space +=
729           gimp_dockbook_get_dockable_tab_width (dockbook,
730                                                 dockable,
731                                                 tab_style);
732     }
733 
734   /* Calculate space taken with auto tab style for all candidates */
735   for (i = 0; i < G_N_ELEMENTS (gimp_tab_style_candidates); i++)
736     {
737       gint         size_with_candidate = 0;
738       GimpTabStyle candidate           = gimp_tab_style_candidates[i];
739 
740       for (iter = auto_dockables; iter; iter = g_list_next (iter))
741         {
742           GimpDockable *dockable = GIMP_DOCKABLE (iter->data);
743           GimpTabStyle  style_to_use;
744 
745           style_to_use = gimp_dockbook_tab_style_to_preferred (candidate,
746                                                               dockable);
747           size_with_candidate +=
748             gimp_dockbook_get_dockable_tab_width (dockbook,
749                                                   dockable,
750                                                   style_to_use);
751         }
752 
753       dockbook->p->min_width_for_style[i] =
754         fixed_tab_style_space + size_with_candidate;
755 
756       GIMP_LOG (AUTO_TAB_STYLE, "Total tab space taken for auto tab style %s = %d",
757                 gimp_dockbook_get_tab_style_name (candidate),
758                 dockbook->p->min_width_for_style[i]);
759     }
760 
761   g_list_free (auto_dockables);
762 }
763 
764 /**
765  * gimp_dockbook_update_automatic_tab_style:
766  * @dockbook:
767  *
768  * Based on widget allocation, sets actual tab style for dockables
769  * with automatic tab styles. Takes care of recreating tab widgets if
770  * necessary.
771  **/
772 static void
gimp_dockbook_update_automatic_tab_style(GimpDockbook * dockbook)773 gimp_dockbook_update_automatic_tab_style (GimpDockbook *dockbook)
774 {
775   GtkWidget    *widget              = GTK_WIDGET (dockbook);
776   gboolean      changed             = FALSE;
777   GList        *iter                = NULL;
778   GtkAllocation dockbook_allocation = { 0, };
779   GtkAllocation button_allocation   = { 0, };
780   GimpTabStyle  tab_style           = 0;
781   int           i                   = 0;
782   gint          available_space     = 0;
783   guint         tab_hborder         = 0;
784   gint          xthickness          = 0;
785   gint          tab_curvature       = 0;
786   gint          focus_width         = 0;
787   gint          tab_overlap         = 0;
788   gint          tab_padding         = 0;
789   gint          border_loss         = 0;
790   gint          action_widget_size  = 0;
791 
792   xthickness = gtk_widget_get_style (widget)->xthickness;
793   g_object_get (widget,
794                 "tab-hborder", &tab_hborder,
795                 NULL);
796   gtk_widget_style_get (widget,
797                         "tab-curvature",    &tab_curvature,
798                         "focus-line-width", &focus_width,
799                         "tab-overlap",      &tab_overlap,
800                         NULL);
801   gtk_widget_get_allocation (dockbook->p->menu_button,
802                              &button_allocation);
803 
804   /* Calculate available space. Based on code in GTK+ internal
805    * functions gtk_notebook_size_request() and
806    * gtk_notebook_pages_allocate()
807    */
808   gtk_widget_get_allocation (widget, &dockbook_allocation);
809 
810   /* Border on both sides */
811   border_loss = gtk_container_get_border_width (GTK_CONTAINER (dockbook)) * 2;
812 
813   /* Space taken by action widget */
814   action_widget_size = button_allocation.width + xthickness;
815 
816   /* Space taken by the tabs but not the tab widgets themselves */
817   tab_padding = gtk_notebook_get_n_pages (GTK_NOTEBOOK (dockbook)) *
818                 (2 * (xthickness + tab_curvature + focus_width + tab_hborder) -
819                  tab_overlap);
820 
821   available_space = dockbook_allocation.width
822     - border_loss
823     - action_widget_size
824     - tab_padding
825     - tab_overlap;
826 
827   GIMP_LOG (AUTO_TAB_STYLE, "\n"
828             "  available_space             = %d where\n"
829             "    dockbook_allocation.width = %d\n"
830             "    border_loss               = %d\n"
831             "    action_widget_size        = %d\n"
832             "    tab_padding               = %d\n"
833             "    tab_overlap               = %d\n",
834             available_space,
835             dockbook_allocation.width,
836             border_loss,
837             action_widget_size,
838             tab_padding,
839             tab_overlap);
840 
841   /* Try all candidates, if we don't get any hit we still end up on
842    * the smallest style (which we always fall back to if we don't get
843    * a better match)
844    */
845   for (i = 0; i < G_N_ELEMENTS (gimp_tab_style_candidates); i++)
846     {
847       tab_style = gimp_tab_style_candidates[i];
848       if (available_space > dockbook->p->min_width_for_style[i])
849         {
850           GIMP_LOG (AUTO_TAB_STYLE, "Choosing tab style %s",
851                     gimp_dockbook_get_tab_style_name (tab_style));
852           break;
853         }
854     }
855 
856   for (iter = dockbook->p->dockables; iter; iter = g_list_next (iter))
857     {
858       GimpDockable *dockable         = GIMP_DOCKABLE (iter->data);
859       GimpTabStyle  actual_tab_style = tab_style;
860 
861       if (gimp_dockable_get_tab_style (dockable) != GIMP_TAB_STYLE_AUTOMATIC)
862         continue;
863 
864       actual_tab_style = gimp_dockbook_tab_style_to_preferred (tab_style,
865                                                               dockable);
866 
867       if (gimp_dockable_set_actual_tab_style (dockable, actual_tab_style))
868         changed = TRUE;
869     }
870 
871   if (changed)
872     gimp_dockbook_recreate_tab_widgets (dockbook,
873                                         TRUE /*only_auto*/);
874 }
875 
876 GtkWidget *
gimp_dockbook_new(GimpMenuFactory * menu_factory)877 gimp_dockbook_new (GimpMenuFactory *menu_factory)
878 {
879   GimpDockbook *dockbook;
880 
881   g_return_val_if_fail (GIMP_IS_MENU_FACTORY (menu_factory), NULL);
882 
883   dockbook = g_object_new (GIMP_TYPE_DOCKBOOK, NULL);
884 
885   dockbook->p->ui_manager = gimp_menu_factory_manager_new (menu_factory,
886                                                            "<Dockable>",
887                                                            dockbook,
888                                                            FALSE);
889 
890   g_signal_connect (dockbook->p->ui_manager->gimp->config,
891                     "size-changed",
892                     G_CALLBACK (gimp_dockbook_config_size_changed),
893                     dockbook);
894 
895   gimp_help_connect (GTK_WIDGET (dockbook), gimp_dockbook_help_func,
896                      GIMP_HELP_DOCK, dockbook);
897 
898   return GTK_WIDGET (dockbook);
899 }
900 
901 GimpDock *
gimp_dockbook_get_dock(GimpDockbook * dockbook)902 gimp_dockbook_get_dock (GimpDockbook *dockbook)
903 {
904   g_return_val_if_fail (GIMP_IS_DOCKBOOK (dockbook), NULL);
905 
906   return dockbook->p->dock;
907 }
908 
909 void
gimp_dockbook_set_dock(GimpDockbook * dockbook,GimpDock * dock)910 gimp_dockbook_set_dock (GimpDockbook *dockbook,
911                         GimpDock     *dock)
912 {
913   g_return_if_fail (GIMP_IS_DOCKBOOK (dockbook));
914   g_return_if_fail (dock == NULL || GIMP_IS_DOCK (dock));
915 
916   dockbook->p->dock = dock;
917 }
918 
919 GimpUIManager *
gimp_dockbook_get_ui_manager(GimpDockbook * dockbook)920 gimp_dockbook_get_ui_manager (GimpDockbook *dockbook)
921 {
922   g_return_val_if_fail (GIMP_IS_DOCKBOOK (dockbook), NULL);
923 
924   return dockbook->p->ui_manager;
925 }
926 
927 void
gimp_dockbook_add(GimpDockbook * dockbook,GimpDockable * dockable,gint position)928 gimp_dockbook_add (GimpDockbook *dockbook,
929                    GimpDockable *dockable,
930                    gint          position)
931 {
932   GtkWidget *tab_widget;
933   GtkWidget *menu_widget;
934 
935   g_return_if_fail (GIMP_IS_DOCKBOOK (dockbook));
936   g_return_if_fail (dockbook->p->dock != NULL);
937   g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
938   g_return_if_fail (gimp_dockable_get_dockbook (dockable) == NULL);
939 
940   GIMP_LOG (DND, "Adding GimpDockable %p to GimpDockbook %p", dockable, dockbook);
941 
942   /* Add to internal list before doing automatic tab style
943    * calculations
944    */
945   dockbook->p->dockables = g_list_insert (dockbook->p->dockables,
946                                           dockable,
947                                           position);
948 
949   gimp_dockbook_update_auto_tab_style (dockbook);
950 
951   /* Create the new tab widget, it will get the correct tab style now */
952   tab_widget = gimp_dockbook_create_tab_widget (dockbook, dockable);
953 
954   g_return_if_fail (GTK_IS_WIDGET (tab_widget));
955 
956   gimp_dockable_set_drag_handler (dockable, dockbook->p->drag_handler);
957 
958   /* For the notebook right-click menu, always use the icon style */
959   menu_widget =
960     gimp_dockable_create_tab_widget (dockable,
961                                      gimp_dock_get_context (dockbook->p->dock),
962                                      GIMP_TAB_STYLE_ICON_BLURB,
963                                      MENU_WIDGET_ICON_SIZE);
964 
965   g_return_if_fail (GTK_IS_WIDGET (menu_widget));
966 
967   if (position == -1)
968     {
969       gtk_notebook_append_page_menu (GTK_NOTEBOOK (dockbook),
970                                      GTK_WIDGET (dockable),
971                                      tab_widget,
972                                      menu_widget);
973     }
974   else
975     {
976       gtk_notebook_insert_page_menu (GTK_NOTEBOOK (dockbook),
977                                      GTK_WIDGET (dockable),
978                                      tab_widget,
979                                      menu_widget,
980                                      position);
981     }
982 
983   gtk_widget_show (GTK_WIDGET (dockable));
984 
985   gimp_dockable_set_dockbook (dockable, dockbook);
986 
987   gimp_dockable_set_context (dockable, gimp_dock_get_context (dockbook->p->dock));
988 
989   g_signal_connect (dockable, "notify::locked",
990                     G_CALLBACK (gimp_dockbook_tab_locked_notify),
991                     dockbook);
992 
993   g_signal_emit (dockbook, dockbook_signals[DOCKABLE_ADDED], 0, dockable);
994 }
995 
996 /**
997  * gimp_dockbook_add_from_dialog_factory:
998  * @dockbook:    The #DockBook
999  * @identifiers: The dockable identifier(s)
1000  * @position:    The insert position
1001  *
1002  * Add a dockable from the dialog factory associated with the dockbook.
1003  **/
1004 GtkWidget *
gimp_dockbook_add_from_dialog_factory(GimpDockbook * dockbook,const gchar * identifiers,gint position)1005 gimp_dockbook_add_from_dialog_factory (GimpDockbook *dockbook,
1006                                        const gchar  *identifiers,
1007                                        gint          position)
1008 {
1009   GtkWidget *dockable;
1010   GimpDock  *dock;
1011   gchar     *identifier;
1012   gchar     *p;
1013 
1014   g_return_val_if_fail (GIMP_IS_DOCKBOOK (dockbook), NULL);
1015   g_return_val_if_fail (identifiers != NULL, NULL);
1016 
1017   identifier = g_strdup (identifiers);
1018 
1019   p = strchr (identifier, '|');
1020 
1021   if (p)
1022     *p = '\0';
1023 
1024   dock     = gimp_dockbook_get_dock (dockbook);
1025   dockable = gimp_dialog_factory_dockable_new (gimp_dock_get_dialog_factory (dock),
1026                                                dock,
1027                                                identifier, -1);
1028 
1029   g_free (identifier);
1030 
1031   /*  Maybe gimp_dialog_factory_dockable_new() returned an already
1032    *  existing singleton dockable, so check if it already is
1033    *  attached to a dockbook.
1034    */
1035   if (dockable && ! gimp_dockable_get_dockbook (GIMP_DOCKABLE (dockable)))
1036     gimp_dockbook_add (dockbook, GIMP_DOCKABLE (dockable), position);
1037 
1038   if (dockable)
1039     gimp_dockable_set_drag_pos (GIMP_DOCKABLE (dockable),
1040                                 GIMP_DOCKABLE_DRAG_OFFSET,
1041                                 GIMP_DOCKABLE_DRAG_OFFSET);
1042   return dockable;
1043 }
1044 
1045 void
gimp_dockbook_remove(GimpDockbook * dockbook,GimpDockable * dockable)1046 gimp_dockbook_remove (GimpDockbook *dockbook,
1047                       GimpDockable *dockable)
1048 {
1049   g_return_if_fail (GIMP_IS_DOCKBOOK (dockbook));
1050   g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
1051   g_return_if_fail (gimp_dockable_get_dockbook (dockable) == dockbook);
1052 
1053   GIMP_LOG (DND, "Removing GimpDockable %p from GimpDockbook %p", dockable, dockbook);
1054 
1055   gimp_dockable_set_drag_handler (dockable, NULL);
1056 
1057   g_object_ref (dockable);
1058 
1059   g_signal_handlers_disconnect_by_func (dockable,
1060                                         G_CALLBACK (gimp_dockbook_tab_locked_notify),
1061                                         dockbook);
1062 
1063   if (dockbook->p->tab_hover_dockable == dockable)
1064     gimp_dockbook_remove_tab_timeout (dockbook);
1065 
1066   gimp_dockable_set_dockbook (dockable, NULL);
1067 
1068   gimp_dockable_set_context (dockable, NULL);
1069 
1070   gtk_container_remove (GTK_CONTAINER (dockbook), GTK_WIDGET (dockable));
1071   dockbook->p->dockables = g_list_remove (dockbook->p->dockables,
1072                                           dockable);
1073 
1074   g_signal_emit (dockbook, dockbook_signals[DOCKABLE_REMOVED], 0, dockable);
1075 
1076   g_object_unref (dockable);
1077 
1078   if (dockbook->p->dock)
1079     {
1080       GList *children = gtk_container_get_children (GTK_CONTAINER (dockbook));
1081 
1082       if (children)
1083         gimp_dockbook_update_auto_tab_style (dockbook);
1084       else
1085         gimp_dock_remove_book (dockbook->p->dock, dockbook);
1086 
1087       g_list_free (children);
1088     }
1089 }
1090 
1091 /**
1092  * gimp_dockbook_update_with_context:
1093  * @dockbook:
1094  * @context:
1095  *
1096  * Set @context on all dockables in @dockbook.
1097  **/
1098 void
gimp_dockbook_update_with_context(GimpDockbook * dockbook,GimpContext * context)1099 gimp_dockbook_update_with_context (GimpDockbook *dockbook,
1100                                    GimpContext  *context)
1101 {
1102   GList *children = gtk_container_get_children (GTK_CONTAINER (dockbook));
1103   GList *iter     = NULL;
1104 
1105   for (iter = children;
1106        iter;
1107        iter = g_list_next (iter))
1108     {
1109       GimpDockable *dockable = GIMP_DOCKABLE (iter->data);
1110 
1111       gimp_dockable_set_context (dockable, context);
1112     }
1113 
1114   g_list_free (children);
1115 }
1116 
1117 GtkWidget *
gimp_dockbook_create_tab_widget(GimpDockbook * dockbook,GimpDockable * dockable)1118 gimp_dockbook_create_tab_widget (GimpDockbook *dockbook,
1119                                  GimpDockable *dockable)
1120 {
1121   GtkWidget      *tab_widget;
1122   GimpDockWindow *dock_window;
1123   GimpAction     *action = NULL;
1124 
1125   tab_widget =
1126     gimp_dockable_create_event_box_tab_widget (dockable,
1127                                                gimp_dock_get_context (dockbook->p->dock),
1128                                                gimp_dockable_get_actual_tab_style (dockable),
1129                                                gimp_dockbook_get_tab_icon_size (dockbook));
1130 
1131   /* EEK */
1132   dock_window = gimp_dock_window_from_dock (dockbook->p->dock);
1133   if (dock_window &&
1134       gimp_dock_container_get_ui_manager (GIMP_DOCK_CONTAINER (dock_window)))
1135     {
1136       const gchar *dialog_id;
1137 
1138       dialog_id = g_object_get_data (G_OBJECT (dockable),
1139                                      "gimp-dialog-identifier");
1140 
1141       if (dialog_id)
1142         {
1143           GimpDockContainer *dock_container;
1144           GimpActionGroup   *group;
1145 
1146           dock_container = GIMP_DOCK_CONTAINER (dock_window);
1147 
1148           group = gimp_ui_manager_get_action_group
1149             (gimp_dock_container_get_ui_manager (dock_container), "dialogs");
1150 
1151           if (group)
1152             {
1153               GList *actions;
1154               GList *list;
1155 
1156               actions = gimp_action_group_list_actions (group);
1157 
1158               for (list = actions; list; list = g_list_next (list))
1159                 {
1160                   if (GIMP_IS_STRING_ACTION (list->data) &&
1161                       strstr (GIMP_STRING_ACTION (list->data)->value,
1162                               dialog_id))
1163                     {
1164                       action = list->data;
1165                       break;
1166                     }
1167                 }
1168 
1169               g_list_free (actions);
1170             }
1171         }
1172     }
1173 
1174   if (action)
1175     gimp_widget_set_accel_help (tab_widget, action);
1176   else
1177     gimp_help_set_help_data (tab_widget,
1178                              gimp_dockable_get_blurb (dockable),
1179                              gimp_dockable_get_help_id (dockable));
1180 
1181   g_object_set_data (G_OBJECT (tab_widget), "gimp-dockable", dockable);
1182 
1183   gimp_dockbook_tab_drag_source_setup (tab_widget, dockable);
1184 
1185   g_signal_connect_object (tab_widget, "drag-begin",
1186                            G_CALLBACK (gimp_dockbook_tab_drag_begin),
1187                            dockable, 0);
1188   g_signal_connect_object (tab_widget, "drag-end",
1189                            G_CALLBACK (gimp_dockbook_tab_drag_end),
1190                            dockable, 0);
1191   g_signal_connect_object (tab_widget, "drag-failed",
1192                            G_CALLBACK (gimp_dockbook_tab_drag_failed),
1193                            dockable, 0);
1194 
1195   g_signal_connect_object (dockable, "drag-begin",
1196                            G_CALLBACK (gimp_dockbook_tab_drag_begin),
1197                            dockable, 0);
1198   g_signal_connect_object (dockable, "drag-end",
1199                            G_CALLBACK (gimp_dockbook_tab_drag_end),
1200                            dockable, 0);
1201   g_signal_connect_object (dockable, "drag-failed",
1202                            G_CALLBACK (gimp_dockbook_tab_drag_failed),
1203                            dockable, 0);
1204 
1205   gtk_drag_dest_set (tab_widget,
1206                      0,
1207                      dialog_target_table, G_N_ELEMENTS (dialog_target_table),
1208                      GDK_ACTION_MOVE);
1209   g_signal_connect_object (tab_widget, "drag-leave",
1210                            G_CALLBACK (gimp_dockbook_tab_drag_leave),
1211                            dockable, 0);
1212   g_signal_connect_object (tab_widget, "drag-motion",
1213                            G_CALLBACK (gimp_dockbook_tab_drag_motion),
1214                            dockable, 0);
1215   g_signal_connect_object (tab_widget, "drag-drop",
1216                            G_CALLBACK (gimp_dockbook_tab_drag_drop),
1217                            dockbook, 0);
1218 
1219   return tab_widget;
1220 }
1221 
1222 /**
1223  * gimp_dockbook_update_auto_tab_style:
1224  * @dockbook:
1225  *
1226  * Refresh the table that we use to map dockbook width to actual auto
1227  * tab style, then update auto tabs (also recreate tab widgets if
1228  * necessary).
1229  **/
1230 void
gimp_dockbook_update_auto_tab_style(GimpDockbook * dockbook)1231 gimp_dockbook_update_auto_tab_style (GimpDockbook *dockbook)
1232 {
1233   g_return_if_fail (GIMP_IS_DOCKBOOK (dockbook));
1234 
1235   gimp_dockbook_refresh_tab_layout_lut (dockbook);
1236   gimp_dockbook_update_automatic_tab_style (dockbook);
1237 }
1238 
1239 gboolean
gimp_dockbook_drop_dockable(GimpDockbook * dockbook,GtkWidget * drag_source)1240 gimp_dockbook_drop_dockable (GimpDockbook *dockbook,
1241                              GtkWidget    *drag_source)
1242 {
1243   g_return_val_if_fail (GIMP_IS_DOCKBOOK (dockbook), FALSE);
1244 
1245   if (drag_source)
1246     {
1247       GimpDockable *dockable =
1248         gimp_dockbook_drag_source_to_dockable (drag_source);
1249 
1250       if (dockable)
1251         {
1252           if (gimp_dockable_get_dockbook (dockable) == dockbook)
1253             {
1254               gtk_notebook_reorder_child (GTK_NOTEBOOK (dockbook),
1255                                           GTK_WIDGET (dockable), -1);
1256             }
1257           else
1258             {
1259               g_object_ref (dockable);
1260 
1261               gimp_dockbook_remove (gimp_dockable_get_dockbook (dockable), dockable);
1262               gimp_dockbook_add (dockbook, dockable, -1);
1263 
1264               g_object_unref (dockable);
1265             }
1266 
1267           return TRUE;
1268         }
1269     }
1270 
1271   return FALSE;
1272 }
1273 
1274 /**
1275  * gimp_dockable_set_drag_handler:
1276  * @dockable:
1277  * @handler:
1278  *
1279  * Set a drag handler that will be asked if it will handle drag events
1280  * before the dockbook handles the event itself.
1281  **/
1282 void
gimp_dockbook_set_drag_handler(GimpDockbook * dockbook,GimpPanedBox * drag_handler)1283 gimp_dockbook_set_drag_handler (GimpDockbook *dockbook,
1284                                 GimpPanedBox *drag_handler)
1285 {
1286   g_return_if_fail (GIMP_IS_DOCKBOOK (dockbook));
1287 
1288   dockbook->p->drag_handler = drag_handler;
1289 }
1290 
1291 /**
1292  * gimp_dockbook_drag_source_to_dockable:
1293  * @drag_source: A drag-and-drop source widget
1294  *
1295  * Gets the dockable associated with a drag-and-drop source. If
1296  * successful, the function will also cleanup the dockable.
1297  *
1298  * Returns: The dockable
1299  **/
1300 GimpDockable *
gimp_dockbook_drag_source_to_dockable(GtkWidget * drag_source)1301 gimp_dockbook_drag_source_to_dockable (GtkWidget *drag_source)
1302 {
1303   GimpDockable *dockable = NULL;
1304 
1305   if (GIMP_IS_DOCKABLE (drag_source))
1306     dockable = GIMP_DOCKABLE (drag_source);
1307   else
1308     dockable = g_object_get_data (G_OBJECT (drag_source),
1309                                   "gimp-dockable");
1310   if (dockable)
1311     g_object_set_data (G_OBJECT (dockable),
1312                        "gimp-dock-drag-widget", NULL);
1313 
1314   return dockable;
1315 }
1316 
1317 void
gimp_dockbook_add_drag_callback(GimpDockbookDragCallback callback,gpointer data)1318 gimp_dockbook_add_drag_callback (GimpDockbookDragCallback callback,
1319                                  gpointer                 data)
1320 {
1321   GimpDockbookDragCallbackData *callback_data;
1322 
1323   callback_data = g_slice_new (GimpDockbookDragCallbackData);
1324 
1325   callback_data->callback = callback;
1326   callback_data->data     = data;
1327 
1328   drag_callbacks = g_list_prepend (drag_callbacks, callback_data);
1329 }
1330 
1331 void
gimp_dockbook_remove_drag_callback(GimpDockbookDragCallback callback,gpointer data)1332 gimp_dockbook_remove_drag_callback (GimpDockbookDragCallback callback,
1333                                     gpointer                 data)
1334 {
1335   GList *iter;
1336 
1337   iter = drag_callbacks;
1338 
1339   while (iter)
1340     {
1341       GimpDockbookDragCallbackData *callback_data = iter->data;
1342       GList                        *next          = g_list_next (iter);
1343 
1344       if (callback_data->callback == callback &&
1345           callback_data->data     == data)
1346         {
1347           g_slice_free (GimpDockbookDragCallbackData, callback_data);
1348 
1349           drag_callbacks = g_list_delete_link (drag_callbacks, iter);
1350         }
1351 
1352       iter = next;
1353     }
1354 }
1355 
1356 /*  tab DND source side  */
1357 
1358 static void
gimp_dockbook_recreate_tab_widgets(GimpDockbook * dockbook,gboolean only_auto)1359 gimp_dockbook_recreate_tab_widgets (GimpDockbook *dockbook,
1360                                     gboolean      only_auto)
1361 {
1362   GList *dockables = gtk_container_get_children (GTK_CONTAINER (dockbook));
1363   GList *iter      = NULL;
1364 
1365   g_object_set (dockbook,
1366                 "tab-border", gimp_dockbook_get_tab_border (dockbook),
1367                 NULL);
1368 
1369   for (iter = dockables; iter; iter = g_list_next (iter))
1370     {
1371       GimpDockable *dockable = GIMP_DOCKABLE (iter->data);
1372       GtkWidget *tab_widget;
1373 
1374       if (only_auto &&
1375           ! (gimp_dockable_get_tab_style (dockable) == GIMP_TAB_STYLE_AUTOMATIC))
1376         continue;
1377 
1378       tab_widget = gimp_dockbook_create_tab_widget (dockbook, dockable);
1379 
1380       gtk_notebook_set_tab_label (GTK_NOTEBOOK (dockbook),
1381                                   GTK_WIDGET (dockable),
1382                                   tab_widget);
1383     }
1384 
1385   g_list_free (dockables);
1386 }
1387 
1388 static void
gimp_dockbook_tab_drag_source_setup(GtkWidget * widget,GimpDockable * dockable)1389 gimp_dockbook_tab_drag_source_setup (GtkWidget    *widget,
1390                                      GimpDockable *dockable)
1391 {
1392   if (gimp_dockable_is_locked (dockable))
1393     {
1394       if (widget)
1395         gtk_drag_source_unset (widget);
1396 
1397       gtk_drag_source_unset (GTK_WIDGET (dockable));
1398     }
1399   else
1400     {
1401       if (widget)
1402         gtk_drag_source_set (widget,
1403                              GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
1404                              dialog_target_table,
1405                              G_N_ELEMENTS (dialog_target_table),
1406                              GDK_ACTION_MOVE);
1407 
1408       gtk_drag_source_set (GTK_WIDGET (dockable),
1409                            GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
1410                            dialog_target_table,
1411                            G_N_ELEMENTS (dialog_target_table),
1412                            GDK_ACTION_MOVE);
1413     }
1414 }
1415 
1416 static void
gimp_dockbook_tab_drag_begin(GtkWidget * widget,GdkDragContext * context,GimpDockable * dockable)1417 gimp_dockbook_tab_drag_begin (GtkWidget      *widget,
1418                               GdkDragContext *context,
1419                               GimpDockable   *dockable)
1420 {
1421   GtkAllocation   allocation;
1422   GtkWidget      *window;
1423   GtkWidget      *view;
1424   GList          *iter;
1425   GtkRequisition  requisition;
1426   gint            drag_x;
1427   gint            drag_y;
1428 
1429   gtk_widget_get_allocation (widget, &allocation);
1430 
1431   window = gtk_window_new (GTK_WINDOW_POPUP);
1432   gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DND);
1433   gtk_window_set_screen (GTK_WINDOW (window), gtk_widget_get_screen (widget));
1434 
1435   view = gimp_dockable_create_drag_widget (dockable);
1436   gtk_container_add (GTK_CONTAINER (window), view);
1437   gtk_widget_show (view);
1438 
1439   gtk_widget_size_request (view, &requisition);
1440 
1441   if (requisition.width < allocation.width)
1442     gtk_widget_set_size_request (view, allocation.width, -1);
1443 
1444   gtk_widget_show (window);
1445 
1446   g_object_set_data_full (G_OBJECT (dockable), "gimp-dock-drag-widget",
1447                           window,
1448                           (GDestroyNotify) gtk_widget_destroy);
1449 
1450   gimp_dockable_get_drag_pos (dockable, &drag_x, &drag_y);
1451   gtk_drag_set_icon_widget (context, window, drag_x, drag_y);
1452 
1453   iter = drag_callbacks;
1454 
1455   while (iter)
1456     {
1457       GimpDockbookDragCallbackData *callback_data = iter->data;
1458 
1459       iter = g_list_next (iter);
1460 
1461       callback_data->callback (context, TRUE, callback_data->data);
1462     }
1463 }
1464 
1465 static void
gimp_dockbook_tab_drag_end(GtkWidget * widget,GdkDragContext * context,GimpDockable * dockable)1466 gimp_dockbook_tab_drag_end (GtkWidget      *widget,
1467                             GdkDragContext *context,
1468                             GimpDockable   *dockable)
1469 {
1470   GList *iter;
1471 
1472   iter = drag_callbacks;
1473 
1474   while (iter)
1475     {
1476       GimpDockbookDragCallbackData *callback_data = iter->data;
1477 
1478       iter = g_list_next (iter);
1479 
1480       callback_data->callback (context, FALSE, callback_data->data);
1481     }
1482 }
1483 
1484 static gboolean
gimp_dockbook_tab_drag_failed(GtkWidget * widget,GdkDragContext * context,GtkDragResult result,GimpDockable * dockable)1485 gimp_dockbook_tab_drag_failed (GtkWidget      *widget,
1486                                GdkDragContext *context,
1487                                GtkDragResult   result,
1488                                GimpDockable   *dockable)
1489 {
1490   /* XXX The proper way is to handle "drag-end" signal instead.
1491    * Unfortunately this signal seems to be broken in various cases on
1492    * macOS/GTK+2 (see #1924). As a consequence, we made sure we don't
1493    * have anything to clean unconditionally (for instance we used to set
1494    * the dockable unsensitive, which anyway was only a visual clue and
1495    * is not really useful). Only thing left to handle is the dockable
1496    * detachment when dropping in a non-droppable area.
1497    */
1498   GtkWidget *drag_widget;
1499   GtkWidget *window;
1500 
1501   if (result == GTK_DRAG_RESULT_SUCCESS)
1502     {
1503       /* I don't think this should happen, considering we are in the
1504        * "drag-failed" handler, but let's be complete as it is a
1505        * possible GtkDragResult value. Just in case!
1506        */
1507       return FALSE;
1508     }
1509 
1510   drag_widget = g_object_get_data (G_OBJECT (dockable),
1511                                    "gimp-dock-drag-widget");
1512 
1513   /* The drag_widget should be present if the drop was not successful,
1514    * in which case, we pop up a new dock and move the dockable there.
1515    */
1516   g_return_val_if_fail (drag_widget, FALSE);
1517 
1518   g_object_set_data (G_OBJECT (dockable), "gimp-dock-drag-widget", NULL);
1519   gimp_dockable_detach (dockable);
1520 
1521   window = gtk_widget_get_toplevel (GTK_WIDGET (dockable));
1522   gtk_window_present (GTK_WINDOW (window));
1523 
1524   return TRUE;
1525 }
1526 
1527 
1528 /*  tab DND target side  */
1529 
1530 static void
gimp_dockbook_tab_drag_leave(GtkWidget * widget,GdkDragContext * context,guint time,GimpDockable * dockable)1531 gimp_dockbook_tab_drag_leave (GtkWidget      *widget,
1532                               GdkDragContext *context,
1533                               guint           time,
1534                               GimpDockable   *dockable)
1535 {
1536   GimpDockbook *dockbook = gimp_dockable_get_dockbook (dockable);
1537 
1538   gimp_dockbook_remove_tab_timeout (dockbook);
1539 
1540   gimp_highlight_widget (widget, FALSE);
1541 }
1542 
1543 static gboolean
gimp_dockbook_tab_drag_motion(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time,GimpDockable * dockable)1544 gimp_dockbook_tab_drag_motion (GtkWidget      *widget,
1545                                GdkDragContext *context,
1546                                gint            x,
1547                                gint            y,
1548                                guint           time,
1549                                GimpDockable   *dockable)
1550 {
1551   GimpDockbook  *dockbook = gimp_dockable_get_dockbook (dockable);
1552   GtkTargetList *target_list;
1553   GdkAtom        target_atom;
1554   gboolean       handle;
1555 
1556   if (gimp_paned_box_will_handle_drag (dockbook->p->drag_handler,
1557                                        widget,
1558                                        context,
1559                                        x, y,
1560                                        time))
1561     {
1562       gdk_drag_status (context, 0, time);
1563       gimp_highlight_widget (widget, FALSE);
1564 
1565       return FALSE;
1566     }
1567 
1568   if (! dockbook->p->tab_hover_timeout ||
1569       dockbook->p->tab_hover_dockable != dockable)
1570     {
1571       gint page_num;
1572 
1573       gimp_dockbook_remove_tab_timeout (dockbook);
1574 
1575       page_num = gtk_notebook_page_num (GTK_NOTEBOOK (dockbook),
1576                                         GTK_WIDGET (dockable));
1577 
1578       if (page_num != gtk_notebook_get_current_page (GTK_NOTEBOOK (dockbook)))
1579         gimp_dockbook_add_tab_timeout (dockbook, dockable);
1580     }
1581 
1582   target_list = gtk_drag_dest_get_target_list (widget);
1583   target_atom = gtk_drag_dest_find_target (widget, context, target_list);
1584 
1585   handle = gtk_target_list_find (target_list, target_atom, NULL);
1586 
1587   gdk_drag_status (context, handle ? GDK_ACTION_MOVE : 0, time);
1588   gimp_highlight_widget (widget, handle);
1589 
1590   /* Return TRUE so drag_leave() is called */
1591   return TRUE;
1592 }
1593 
1594 static gboolean
gimp_dockbook_tab_drag_drop(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time)1595 gimp_dockbook_tab_drag_drop (GtkWidget      *widget,
1596                              GdkDragContext *context,
1597                              gint            x,
1598                              gint            y,
1599                              guint           time)
1600 {
1601   GimpDockable *dest_dockable;
1602   GtkWidget    *source;
1603   gboolean      dropped = FALSE;
1604 
1605   dest_dockable = g_object_get_data (G_OBJECT (widget), "gimp-dockable");
1606 
1607   source = gtk_drag_get_source_widget (context);
1608 
1609   if (gimp_paned_box_will_handle_drag (gimp_dockable_get_drag_handler (dest_dockable),
1610                                        widget,
1611                                        context,
1612                                        x, y,
1613                                        time))
1614     {
1615       return FALSE;
1616     }
1617 
1618   if (dest_dockable && source)
1619     {
1620       GimpDockable *src_dockable =
1621         gimp_dockbook_drag_source_to_dockable (source);
1622 
1623       if (src_dockable)
1624         {
1625           gint dest_index;
1626 
1627           dest_index =
1628             gtk_notebook_page_num (GTK_NOTEBOOK (gimp_dockable_get_dockbook (dest_dockable)),
1629                                    GTK_WIDGET (dest_dockable));
1630 
1631           if (gimp_dockable_get_dockbook (src_dockable) !=
1632               gimp_dockable_get_dockbook (dest_dockable))
1633             {
1634               g_object_ref (src_dockable);
1635 
1636               gimp_dockbook_remove (gimp_dockable_get_dockbook (src_dockable), src_dockable);
1637               gimp_dockbook_add (gimp_dockable_get_dockbook (dest_dockable), src_dockable,
1638                                  dest_index);
1639 
1640               g_object_unref (src_dockable);
1641 
1642               dropped = TRUE;
1643             }
1644           else if (src_dockable != dest_dockable)
1645             {
1646               gtk_notebook_reorder_child (GTK_NOTEBOOK (gimp_dockable_get_dockbook (src_dockable)),
1647                                           GTK_WIDGET (src_dockable),
1648                                           dest_index);
1649 
1650               g_signal_emit (gimp_dockable_get_dockbook (src_dockable),
1651                              dockbook_signals[DOCKABLE_REORDERED], 0,
1652                              src_dockable);
1653 
1654               dropped = TRUE;
1655             }
1656         }
1657     }
1658 
1659   gtk_drag_finish (context, dropped, TRUE, time);
1660 
1661   return TRUE;
1662 }
1663 
1664 static GtkWidget *
gimp_dockable_create_event_box_tab_widget(GimpDockable * dockable,GimpContext * context,GimpTabStyle tab_style,GtkIconSize size)1665 gimp_dockable_create_event_box_tab_widget (GimpDockable *dockable,
1666                                            GimpContext  *context,
1667                                            GimpTabStyle  tab_style,
1668                                            GtkIconSize   size)
1669 {
1670   GtkWidget *tab_widget;
1671 
1672   tab_widget =
1673     gimp_dockable_create_tab_widget (dockable,
1674                                      context,
1675                                      tab_style,
1676                                      size);
1677 
1678   if (! GIMP_IS_VIEW (tab_widget))
1679     {
1680       GtkWidget *event_box;
1681 
1682       event_box = gtk_event_box_new ();
1683       gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE);
1684       gtk_event_box_set_above_child (GTK_EVENT_BOX (event_box), TRUE);
1685       gtk_container_add (GTK_CONTAINER (event_box), tab_widget);
1686       gtk_widget_show (tab_widget);
1687 
1688       tab_widget = event_box;
1689     }
1690 
1691   return tab_widget;
1692 }
1693 
1694 static GtkIconSize
gimp_dockbook_get_tab_icon_size(GimpDockbook * dockbook)1695 gimp_dockbook_get_tab_icon_size (GimpDockbook *dockbook)
1696 {
1697   Gimp        *gimp     = dockbook->p->ui_manager->gimp;
1698   GtkIconSize  tab_size = DEFAULT_TAB_ICON_SIZE;
1699   GimpIconSize size;
1700 
1701   size = gimp_gui_config_detect_icon_size (GIMP_GUI_CONFIG (gimp->config));
1702   /* Match GimpIconSize with GtkIconSize. */
1703   switch (size)
1704     {
1705     case GIMP_ICON_SIZE_SMALL:
1706     case GIMP_ICON_SIZE_MEDIUM:
1707       tab_size = GTK_ICON_SIZE_MENU;
1708       break;
1709     case GIMP_ICON_SIZE_LARGE:
1710       tab_size = GTK_ICON_SIZE_LARGE_TOOLBAR;
1711       break;
1712     case GIMP_ICON_SIZE_HUGE:
1713       tab_size = GTK_ICON_SIZE_DND;
1714       break;
1715     default:
1716       /* GIMP_ICON_SIZE_DEFAULT:
1717        * let's use the size set by the theme. */
1718       gtk_widget_style_get (GTK_WIDGET (dockbook),
1719                             "tab-icon-size", &tab_size,
1720                             NULL);
1721       break;
1722     }
1723 
1724   return tab_size;
1725 }
1726 
1727 static gint
gimp_dockbook_get_tab_border(GimpDockbook * dockbook)1728 gimp_dockbook_get_tab_border (GimpDockbook *dockbook)
1729 {
1730   Gimp         *gimp       = dockbook->p->ui_manager->gimp;
1731   gint          tab_border = DEFAULT_TAB_BORDER;
1732   GimpIconSize  size;
1733 
1734   gtk_widget_style_get (GTK_WIDGET (dockbook),
1735                         "tab-border", &tab_border,
1736                         NULL);
1737 
1738   size = gimp_gui_config_detect_icon_size (GIMP_GUI_CONFIG (gimp->config));
1739   /* Match GimpIconSize with GtkIconSize. */
1740   switch (size)
1741     {
1742     case GIMP_ICON_SIZE_SMALL:
1743       tab_border /= 2;
1744       break;
1745     case GIMP_ICON_SIZE_LARGE:
1746       tab_border *= 2;
1747       break;
1748     case GIMP_ICON_SIZE_HUGE:
1749       tab_border *= 3;
1750       break;
1751     default:
1752       /* GIMP_ICON_SIZE_MEDIUM and GIMP_ICON_SIZE_DEFAULT:
1753        * let's use the size set by the theme. */
1754       break;
1755     }
1756 
1757   return tab_border;
1758 }
1759 
1760 static void
gimp_dockbook_add_tab_timeout(GimpDockbook * dockbook,GimpDockable * dockable)1761 gimp_dockbook_add_tab_timeout (GimpDockbook *dockbook,
1762                                GimpDockable *dockable)
1763 {
1764   dockbook->p->tab_hover_timeout =
1765     g_timeout_add (TAB_HOVER_TIMEOUT,
1766                    (GSourceFunc) gimp_dockbook_tab_timeout,
1767                    dockbook);
1768 
1769   dockbook->p->tab_hover_dockable = dockable;
1770 }
1771 
1772 static void
gimp_dockbook_remove_tab_timeout(GimpDockbook * dockbook)1773 gimp_dockbook_remove_tab_timeout (GimpDockbook *dockbook)
1774 {
1775   if (dockbook->p->tab_hover_timeout)
1776     {
1777       g_source_remove (dockbook->p->tab_hover_timeout);
1778       dockbook->p->tab_hover_timeout  = 0;
1779       dockbook->p->tab_hover_dockable = NULL;
1780     }
1781 }
1782 
1783 static gboolean
gimp_dockbook_tab_timeout(GimpDockbook * dockbook)1784 gimp_dockbook_tab_timeout (GimpDockbook *dockbook)
1785 {
1786   gint page_num;
1787 
1788   GDK_THREADS_ENTER ();
1789 
1790   page_num = gtk_notebook_page_num (GTK_NOTEBOOK (dockbook),
1791                                     GTK_WIDGET (dockbook->p->tab_hover_dockable));
1792   gtk_notebook_set_current_page (GTK_NOTEBOOK (dockbook), page_num);
1793 
1794   dockbook->p->tab_hover_timeout  = 0;
1795   dockbook->p->tab_hover_dockable = NULL;
1796 
1797   GDK_THREADS_LEAVE ();
1798 
1799   return FALSE;
1800 }
1801 
1802 static void
gimp_dockbook_tab_locked_notify(GimpDockable * dockable,GParamSpec * pspec,GimpDockbook * dockbook)1803 gimp_dockbook_tab_locked_notify (GimpDockable *dockable,
1804                                  GParamSpec   *pspec,
1805                                  GimpDockbook *dockbook)
1806 {
1807   GtkWidget *tab_widget;
1808 
1809   tab_widget = gtk_notebook_get_tab_label (GTK_NOTEBOOK (dockbook),
1810                                            GTK_WIDGET (dockable));
1811 
1812   gimp_dockbook_tab_drag_source_setup (tab_widget, dockable);
1813 }
1814 
1815 static void
gimp_dockbook_help_func(const gchar * help_id,gpointer help_data)1816 gimp_dockbook_help_func (const gchar *help_id,
1817                          gpointer     help_data)
1818 {
1819   GimpDockbook *dockbook = GIMP_DOCKBOOK (help_data);
1820   GtkWidget    *dockable;
1821   gint          page_num;
1822 
1823   page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (dockbook));
1824 
1825   dockable = gtk_notebook_get_nth_page (GTK_NOTEBOOK (dockbook), page_num);
1826 
1827   if (GIMP_IS_DOCKABLE (dockable))
1828     gimp_standard_help_func (gimp_dockable_get_help_id (GIMP_DOCKABLE (dockable)),
1829                              NULL);
1830   else
1831     gimp_standard_help_func (GIMP_HELP_DOCK, NULL);
1832 }
1833 
1834 static const gchar *
gimp_dockbook_get_tab_style_name(GimpTabStyle tab_style)1835 gimp_dockbook_get_tab_style_name (GimpTabStyle tab_style)
1836 {
1837   return g_enum_get_value (g_type_class_peek (GIMP_TYPE_TAB_STYLE),
1838                            tab_style)->value_name;
1839 }
1840 
1841 static void
gimp_dockbook_config_size_changed(GimpGuiConfig * config,GimpDockbook * dockbook)1842 gimp_dockbook_config_size_changed (GimpGuiConfig *config,
1843                                    GimpDockbook  *dockbook)
1844 {
1845   gimp_dockbook_recreate_tab_widgets (dockbook, TRUE);
1846 }
1847