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