1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimpdockable.c
5  * Copyright (C) 2001-2003 Michael Natterer <mitch@gimp.org>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 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 "core/gimpcontext.h"
33 
34 #include "gimpdialogfactory.h"
35 #include "gimpdnd.h"
36 #include "gimpdock.h"
37 #include "gimpdockable.h"
38 #include "gimpdockbook.h"
39 #include "gimpdocked.h"
40 #include "gimpdockwindow.h"
41 #include "gimphelp-ids.h"
42 #include "gimppanedbox.h"
43 #include "gimpsessioninfo-aux.h"
44 #include "gimpsessionmanaged.h"
45 #include "gimpuimanager.h"
46 #include "gimpwidgets-utils.h"
47 
48 #include "gimp-intl.h"
49 
50 
51 enum
52 {
53   PROP_0,
54   PROP_LOCKED
55 };
56 
57 
58 struct _GimpDockablePrivate
59 {
60   gchar        *name;
61   gchar        *blurb;
62   gchar        *icon_name;
63   gchar        *help_id;
64   GimpTabStyle  tab_style;
65   GimpTabStyle  actual_tab_style;
66   gboolean      locked;
67 
68   GimpDockbook *dockbook;
69 
70   GimpContext  *context;
71 
72   GimpPanedBox *drag_handler;
73 
74   /*  drag icon hotspot  */
75   gint          drag_x;
76   gint          drag_y;
77 };
78 
79 
80 static void       gimp_dockable_session_managed_iface_init
81                                                   (GimpSessionManagedInterface
82                                                                   *iface);
83 static void       gimp_dockable_dispose           (GObject        *object);
84 static void       gimp_dockable_set_property      (GObject        *object,
85                                                    guint           property_id,
86                                                    const GValue   *value,
87                                                    GParamSpec     *pspec);
88 static void       gimp_dockable_get_property      (GObject        *object,
89                                                    guint           property_id,
90                                                    GValue         *value,
91                                                    GParamSpec     *pspec);
92 
93 static void       gimp_dockable_size_request      (GtkWidget      *widget,
94                                                    GtkRequisition *requisition);
95 static void       gimp_dockable_size_allocate     (GtkWidget      *widget,
96                                                    GtkAllocation  *allocation);
97 static void       gimp_dockable_drag_leave        (GtkWidget      *widget,
98                                                    GdkDragContext *context,
99                                                    guint           time);
100 static gboolean   gimp_dockable_drag_motion       (GtkWidget      *widget,
101                                                    GdkDragContext *context,
102                                                    gint            x,
103                                                    gint            y,
104                                                    guint           time);
105 static gboolean   gimp_dockable_drag_drop         (GtkWidget      *widget,
106                                                    GdkDragContext *context,
107                                                    gint            x,
108                                                    gint            y,
109                                                    guint           time);
110 
111 static void       gimp_dockable_style_set         (GtkWidget      *widget,
112                                                    GtkStyle       *prev_style);
113 
114 static void       gimp_dockable_add               (GtkContainer   *container,
115                                                    GtkWidget      *widget);
116 static GType      gimp_dockable_child_type        (GtkContainer   *container);
117 static GList    * gimp_dockable_get_aux_info      (GimpSessionManaged
118                                                                   *session_managed);
119 static void       gimp_dockable_set_aux_info      (GimpSessionManaged
120                                                                   *session_managed,
121                                                    GList          *aux_info);
122 
123 static GimpTabStyle
124                   gimp_dockable_convert_tab_style (GimpDockable   *dockable,
125                                                    GimpTabStyle    tab_style);
126 
127 
128 G_DEFINE_TYPE_WITH_CODE (GimpDockable, gimp_dockable, GTK_TYPE_BIN,
129                          G_ADD_PRIVATE (GimpDockable)
130                          G_IMPLEMENT_INTERFACE (GIMP_TYPE_SESSION_MANAGED,
131                                                 gimp_dockable_session_managed_iface_init))
132 
133 #define parent_class gimp_dockable_parent_class
134 
135 static const GtkTargetEntry dialog_target_table[] = { GIMP_TARGET_DIALOG };
136 
137 
138 static void
gimp_dockable_class_init(GimpDockableClass * klass)139 gimp_dockable_class_init (GimpDockableClass *klass)
140 {
141   GObjectClass      *object_class    = G_OBJECT_CLASS (klass);
142   GtkWidgetClass    *widget_class    = GTK_WIDGET_CLASS (klass);
143   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
144 
145   object_class->dispose       = gimp_dockable_dispose;
146   object_class->set_property  = gimp_dockable_set_property;
147   object_class->get_property  = gimp_dockable_get_property;
148 
149   widget_class->size_request  = gimp_dockable_size_request;
150   widget_class->size_allocate = gimp_dockable_size_allocate;
151   widget_class->style_set     = gimp_dockable_style_set;
152   widget_class->drag_leave    = gimp_dockable_drag_leave;
153   widget_class->drag_motion   = gimp_dockable_drag_motion;
154   widget_class->drag_drop     = gimp_dockable_drag_drop;
155 
156   container_class->add        = gimp_dockable_add;
157   container_class->child_type = gimp_dockable_child_type;
158 
159   g_object_class_install_property (object_class, PROP_LOCKED,
160                                    g_param_spec_boolean ("locked", NULL, NULL,
161                                                          FALSE,
162                                                          GIMP_PARAM_READWRITE));
163 
164   gtk_widget_class_install_style_property (widget_class,
165                                            g_param_spec_int ("content-border",
166                                                              NULL, NULL,
167                                                              0,
168                                                              G_MAXINT,
169                                                              0,
170                                                              GIMP_PARAM_READABLE));
171 }
172 
173 static void
gimp_dockable_init(GimpDockable * dockable)174 gimp_dockable_init (GimpDockable *dockable)
175 {
176   dockable->p = gimp_dockable_get_instance_private (dockable);
177   dockable->p->tab_style        = GIMP_TAB_STYLE_AUTOMATIC;
178   dockable->p->actual_tab_style = GIMP_TAB_STYLE_UNDEFINED;
179   dockable->p->drag_x           = GIMP_DOCKABLE_DRAG_OFFSET;
180   dockable->p->drag_y           = GIMP_DOCKABLE_DRAG_OFFSET;
181 
182   gtk_drag_dest_set (GTK_WIDGET (dockable),
183                      0,
184                      dialog_target_table, G_N_ELEMENTS (dialog_target_table),
185                      GDK_ACTION_MOVE);
186 }
187 
188 static void
gimp_dockable_session_managed_iface_init(GimpSessionManagedInterface * iface)189 gimp_dockable_session_managed_iface_init (GimpSessionManagedInterface *iface)
190 {
191   iface->get_aux_info = gimp_dockable_get_aux_info;
192   iface->set_aux_info = gimp_dockable_set_aux_info;
193 }
194 
195 static void
gimp_dockable_dispose(GObject * object)196 gimp_dockable_dispose (GObject *object)
197 {
198   GimpDockable *dockable = GIMP_DOCKABLE (object);
199 
200   if (dockable->p->context)
201     gimp_dockable_set_context (dockable, NULL);
202 
203   g_clear_pointer (&dockable->p->blurb,     g_free);
204   g_clear_pointer (&dockable->p->name,      g_free);
205   g_clear_pointer (&dockable->p->icon_name, g_free);
206   g_clear_pointer (&dockable->p->help_id,   g_free);
207 
208   G_OBJECT_CLASS (parent_class)->dispose (object);
209 }
210 
211 static void
gimp_dockable_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)212 gimp_dockable_set_property (GObject      *object,
213                             guint         property_id,
214                             const GValue *value,
215                             GParamSpec   *pspec)
216 {
217   GimpDockable *dockable = GIMP_DOCKABLE (object);
218 
219   switch (property_id)
220     {
221     case PROP_LOCKED:
222       gimp_dockable_set_locked (dockable, g_value_get_boolean (value));
223       break;
224     default:
225       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
226       break;
227     }
228 }
229 
230 static void
gimp_dockable_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)231 gimp_dockable_get_property (GObject    *object,
232                             guint       property_id,
233                             GValue     *value,
234                             GParamSpec *pspec)
235 {
236   GimpDockable *dockable = GIMP_DOCKABLE (object);
237 
238   switch (property_id)
239     {
240     case PROP_LOCKED:
241       g_value_set_boolean (value, dockable->p->locked);
242       break;
243     default:
244       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
245       break;
246     }
247 }
248 
249 static void
gimp_dockable_size_request(GtkWidget * widget,GtkRequisition * requisition)250 gimp_dockable_size_request (GtkWidget      *widget,
251                             GtkRequisition *requisition)
252 {
253   GtkContainer   *container = GTK_CONTAINER (widget);
254   GtkWidget      *child     = gtk_bin_get_child (GTK_BIN (widget));
255   GtkRequisition  child_requisition;
256   gint            border_width;
257 
258   border_width = gtk_container_get_border_width (container);
259 
260   requisition->width  = border_width * 2;
261   requisition->height = border_width * 2;
262 
263   if (child && gtk_widget_get_visible (child))
264     {
265       gtk_widget_size_request (child, &child_requisition);
266 
267       requisition->width  += child_requisition.width;
268       requisition->height += child_requisition.height;
269     }
270 }
271 
272 static void
gimp_dockable_size_allocate(GtkWidget * widget,GtkAllocation * allocation)273 gimp_dockable_size_allocate (GtkWidget     *widget,
274                              GtkAllocation *allocation)
275 {
276   GtkContainer   *container = GTK_CONTAINER (widget);
277   GtkWidget      *child     = gtk_bin_get_child (GTK_BIN (widget));
278 
279   GtkRequisition  button_requisition = { 0, };
280   GtkAllocation   child_allocation;
281   gint            border_width;
282 
283 
284   gtk_widget_set_allocation (widget, allocation);
285 
286   border_width = gtk_container_get_border_width (container);
287 
288   if (child && gtk_widget_get_visible (child))
289     {
290       child_allocation.x      = allocation->x + border_width;
291       child_allocation.y      = allocation->y + border_width;
292       child_allocation.width  = MAX (allocation->width  -
293                                      border_width * 2,
294                                      0);
295       child_allocation.height = MAX (allocation->height -
296                                      border_width * 2 -
297                                      button_requisition.height,
298                                      0);
299 
300       child_allocation.y += button_requisition.height;
301 
302       gtk_widget_size_allocate (child, &child_allocation);
303     }
304 }
305 
306 static void
gimp_dockable_drag_leave(GtkWidget * widget,GdkDragContext * context,guint time)307 gimp_dockable_drag_leave (GtkWidget      *widget,
308                           GdkDragContext *context,
309                           guint           time)
310 {
311   gimp_highlight_widget (widget, FALSE);
312 }
313 
314 static gboolean
gimp_dockable_drag_motion(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time)315 gimp_dockable_drag_motion (GtkWidget      *widget,
316                            GdkDragContext *context,
317                            gint            x,
318                            gint            y,
319                            guint           time)
320 {
321   GimpDockable *dockable = GIMP_DOCKABLE (widget);
322 
323   if (gimp_paned_box_will_handle_drag (dockable->p->drag_handler,
324                                        widget,
325                                        context,
326                                        x, y,
327                                        time))
328     {
329       gdk_drag_status (context, 0, time);
330       gimp_highlight_widget (widget, FALSE);
331 
332       return FALSE;
333     }
334 
335   gdk_drag_status (context, GDK_ACTION_MOVE, time);
336   gimp_highlight_widget (widget, TRUE);
337 
338   /* Return TRUE so drag_leave() is called */
339   return TRUE;
340 }
341 
342 static gboolean
gimp_dockable_drag_drop(GtkWidget * widget,GdkDragContext * context,gint x,gint y,guint time)343 gimp_dockable_drag_drop (GtkWidget      *widget,
344                          GdkDragContext *context,
345                          gint            x,
346                          gint            y,
347                          guint           time)
348 {
349   GimpDockable *dockable = GIMP_DOCKABLE (widget);
350   gboolean      dropped;
351 
352   if (gimp_paned_box_will_handle_drag (dockable->p->drag_handler,
353                                        widget,
354                                        context,
355                                        x, y,
356                                        time))
357     {
358       return FALSE;
359     }
360 
361   dropped = gimp_dockbook_drop_dockable (GIMP_DOCKABLE (widget)->p->dockbook,
362                                          gtk_drag_get_source_widget (context));
363 
364   gtk_drag_finish (context, dropped, TRUE, time);
365 
366   return TRUE;
367 }
368 
369 static void
gimp_dockable_style_set(GtkWidget * widget,GtkStyle * prev_style)370 gimp_dockable_style_set (GtkWidget *widget,
371                          GtkStyle  *prev_style)
372 {
373   gint content_border;
374 
375   GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
376 
377   gtk_widget_style_get (widget,
378                         "content-border", &content_border,
379                         NULL);
380 
381   gtk_container_set_border_width (GTK_CONTAINER (widget), content_border);
382 }
383 
384 
385 static void
gimp_dockable_add(GtkContainer * container,GtkWidget * widget)386 gimp_dockable_add (GtkContainer *container,
387                    GtkWidget    *widget)
388 {
389   GimpDockable *dockable;
390 
391   g_return_if_fail (gtk_bin_get_child (GTK_BIN (container)) == NULL);
392 
393   GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
394 
395   /*  not all tab styles are supported by all children  */
396   dockable = GIMP_DOCKABLE (container);
397   gimp_dockable_set_tab_style (dockable, dockable->p->tab_style);
398 }
399 
400 static GType
gimp_dockable_child_type(GtkContainer * container)401 gimp_dockable_child_type (GtkContainer *container)
402 {
403   if (gtk_bin_get_child (GTK_BIN (container)))
404     return G_TYPE_NONE;
405 
406   return GIMP_TYPE_DOCKED;
407 }
408 
409 static GtkWidget *
gimp_dockable_new_tab_widget_internal(GimpDockable * dockable,GimpContext * context,GimpTabStyle tab_style,GtkIconSize size,gboolean dnd)410 gimp_dockable_new_tab_widget_internal (GimpDockable *dockable,
411                                        GimpContext  *context,
412                                        GimpTabStyle  tab_style,
413                                        GtkIconSize   size,
414                                        gboolean      dnd)
415 {
416   GtkWidget *tab_widget = NULL;
417   GtkWidget *label      = NULL;
418   GtkWidget *icon       = NULL;
419 
420   switch (tab_style)
421     {
422     case GIMP_TAB_STYLE_NAME:
423     case GIMP_TAB_STYLE_ICON_NAME:
424     case GIMP_TAB_STYLE_PREVIEW_NAME:
425       label = gtk_label_new (dockable->p->name);
426       break;
427 
428     case GIMP_TAB_STYLE_BLURB:
429     case GIMP_TAB_STYLE_ICON_BLURB:
430     case GIMP_TAB_STYLE_PREVIEW_BLURB:
431       label = gtk_label_new (dockable->p->blurb);
432       break;
433 
434     default:
435       break;
436     }
437 
438   switch (tab_style)
439     {
440     case GIMP_TAB_STYLE_ICON:
441     case GIMP_TAB_STYLE_ICON_NAME:
442     case GIMP_TAB_STYLE_ICON_BLURB:
443       icon = gimp_dockable_get_icon (dockable, size);
444       break;
445 
446     case GIMP_TAB_STYLE_PREVIEW:
447     case GIMP_TAB_STYLE_PREVIEW_NAME:
448     case GIMP_TAB_STYLE_PREVIEW_BLURB:
449       {
450         GtkWidget *child = gtk_bin_get_child (GTK_BIN (dockable));
451 
452         if (child)
453           icon = gimp_docked_get_preview (GIMP_DOCKED (child),
454                                           context, size);
455 
456         if (! icon)
457           icon = gimp_dockable_get_icon (dockable, size);
458       }
459       break;
460 
461     default:
462       break;
463     }
464 
465   if (label && dnd)
466     gimp_label_set_attributes (GTK_LABEL (label),
467                                PANGO_ATTR_WEIGHT, PANGO_WEIGHT_SEMIBOLD,
468                                -1);
469 
470   switch (tab_style)
471     {
472     case GIMP_TAB_STYLE_ICON:
473     case GIMP_TAB_STYLE_PREVIEW:
474       tab_widget = icon;
475       break;
476 
477     case GIMP_TAB_STYLE_NAME:
478     case GIMP_TAB_STYLE_BLURB:
479       tab_widget = label;
480       break;
481 
482     case GIMP_TAB_STYLE_ICON_NAME:
483     case GIMP_TAB_STYLE_ICON_BLURB:
484     case GIMP_TAB_STYLE_PREVIEW_NAME:
485     case GIMP_TAB_STYLE_PREVIEW_BLURB:
486       tab_widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, dnd ? 6 : 2);
487 
488       gtk_box_pack_start (GTK_BOX (tab_widget), icon, FALSE, FALSE, 0);
489       gtk_widget_show (icon);
490 
491       gtk_box_pack_start (GTK_BOX (tab_widget), label, FALSE, FALSE, 0);
492       gtk_widget_show (label);
493       break;
494 
495     case GIMP_TAB_STYLE_UNDEFINED:
496     case GIMP_TAB_STYLE_AUTOMATIC:
497       g_warning ("Tab style error, unexpected code path taken, fix!");
498       break;
499     }
500 
501   return tab_widget;
502 }
503 
504 /*  public functions  */
505 
506 GtkWidget *
gimp_dockable_new(const gchar * name,const gchar * blurb,const gchar * icon_name,const gchar * help_id)507 gimp_dockable_new (const gchar *name,
508                    const gchar *blurb,
509                    const gchar *icon_name,
510                    const gchar *help_id)
511 {
512   GimpDockable *dockable;
513 
514   g_return_val_if_fail (name != NULL, NULL);
515   g_return_val_if_fail (icon_name != NULL, NULL);
516   g_return_val_if_fail (help_id != NULL, NULL);
517 
518   dockable = g_object_new (GIMP_TYPE_DOCKABLE, NULL);
519 
520   dockable->p->name      = g_strdup (name);
521   dockable->p->icon_name = g_strdup (icon_name);
522   dockable->p->help_id   = g_strdup (help_id);
523 
524   if (blurb)
525     dockable->p->blurb  = g_strdup (blurb);
526   else
527     dockable->p->blurb  = g_strdup (dockable->p->name);
528 
529   gimp_help_set_help_data (GTK_WIDGET (dockable), NULL, help_id);
530 
531   return GTK_WIDGET (dockable);
532 }
533 
534 void
gimp_dockable_set_dockbook(GimpDockable * dockable,GimpDockbook * dockbook)535 gimp_dockable_set_dockbook (GimpDockable *dockable,
536                             GimpDockbook *dockbook)
537 {
538   g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
539   g_return_if_fail (dockbook == NULL ||
540                     GIMP_IS_DOCKBOOK (dockbook));
541 
542   dockable->p->dockbook = dockbook;
543 }
544 
545 GimpDockbook *
gimp_dockable_get_dockbook(GimpDockable * dockable)546 gimp_dockable_get_dockbook (GimpDockable *dockable)
547 {
548   g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), NULL);
549 
550   return dockable->p->dockbook;
551 }
552 
553 GimpTabStyle
gimp_dockable_get_tab_style(GimpDockable * dockable)554 gimp_dockable_get_tab_style (GimpDockable *dockable)
555 {
556   g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), -1);
557 
558   return dockable->p->tab_style;
559 }
560 
561 /**
562  * gimp_dockable_get_actual_tab_style:
563  * @dockable:
564  *
565  * Get actual tab style, i.e. never "automatic". This state should
566  * actually be hold on a per-dockbook basis, but at this point that
567  * feels like over-engineering...
568  **/
569 GimpTabStyle
gimp_dockable_get_actual_tab_style(GimpDockable * dockable)570 gimp_dockable_get_actual_tab_style (GimpDockable *dockable)
571 {
572   g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), -1);
573 
574   return dockable->p->actual_tab_style;
575 }
576 
577 const gchar *
gimp_dockable_get_name(GimpDockable * dockable)578 gimp_dockable_get_name (GimpDockable *dockable)
579 {
580   g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), NULL);
581 
582   return dockable->p->name;
583 }
584 
585 const gchar *
gimp_dockable_get_blurb(GimpDockable * dockable)586 gimp_dockable_get_blurb (GimpDockable *dockable)
587 {
588   g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), NULL);
589 
590   return dockable->p->blurb;
591 }
592 
593 const gchar *
gimp_dockable_get_help_id(GimpDockable * dockable)594 gimp_dockable_get_help_id (GimpDockable *dockable)
595 {
596   g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), NULL);
597 
598   return dockable->p->help_id;
599 }
600 
601 const gchar *
gimp_dockable_get_icon_name(GimpDockable * dockable)602 gimp_dockable_get_icon_name (GimpDockable *dockable)
603 {
604   g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), NULL);
605 
606   return dockable->p->icon_name;
607 }
608 
609 GtkWidget *
gimp_dockable_get_icon(GimpDockable * dockable,GtkIconSize size)610 gimp_dockable_get_icon (GimpDockable *dockable,
611                         GtkIconSize   size)
612 {
613   g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), NULL);
614 
615   return gtk_image_new_from_icon_name (dockable->p->icon_name, size);
616 }
617 
618 gboolean
gimp_dockable_get_locked(GimpDockable * dockable)619 gimp_dockable_get_locked (GimpDockable *dockable)
620 {
621   g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), FALSE);
622 
623   return dockable->p->locked;
624 }
625 
626 void
gimp_dockable_set_drag_pos(GimpDockable * dockable,gint drag_x,gint drag_y)627 gimp_dockable_set_drag_pos (GimpDockable *dockable,
628                             gint          drag_x,
629                             gint          drag_y)
630 {
631   g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
632 
633   dockable->p->drag_x = drag_x;
634   dockable->p->drag_y = drag_y;
635 }
636 
637 void
gimp_dockable_get_drag_pos(GimpDockable * dockable,gint * drag_x,gint * drag_y)638 gimp_dockable_get_drag_pos (GimpDockable *dockable,
639                             gint         *drag_x,
640                             gint         *drag_y)
641 {
642   g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
643 
644   if (drag_x != NULL)
645     *drag_x = dockable->p->drag_x;
646   if (drag_y != NULL)
647     *drag_y = dockable->p->drag_y;
648 }
649 
650 GimpPanedBox *
gimp_dockable_get_drag_handler(GimpDockable * dockable)651 gimp_dockable_get_drag_handler (GimpDockable *dockable)
652 {
653   g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), NULL);
654 
655   return dockable->p->drag_handler;
656 }
657 
658 void
gimp_dockable_set_locked(GimpDockable * dockable,gboolean lock)659 gimp_dockable_set_locked (GimpDockable *dockable,
660                           gboolean      lock)
661 {
662   g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
663 
664   if (dockable->p->locked != lock)
665     {
666       dockable->p->locked = lock ? TRUE : FALSE;
667 
668       g_object_notify (G_OBJECT (dockable), "locked");
669     }
670 }
671 
672 gboolean
gimp_dockable_is_locked(GimpDockable * dockable)673 gimp_dockable_is_locked (GimpDockable *dockable)
674 {
675   g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), FALSE);
676 
677   return dockable->p->locked;
678 }
679 
680 
681 void
gimp_dockable_set_tab_style(GimpDockable * dockable,GimpTabStyle tab_style)682 gimp_dockable_set_tab_style (GimpDockable *dockable,
683                              GimpTabStyle  tab_style)
684 {
685   g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
686 
687   dockable->p->tab_style = gimp_dockable_convert_tab_style (dockable, tab_style);
688 
689   if (tab_style == GIMP_TAB_STYLE_AUTOMATIC)
690     gimp_dockable_set_actual_tab_style (dockable, GIMP_TAB_STYLE_UNDEFINED);
691   else
692     gimp_dockable_set_actual_tab_style (dockable, tab_style);
693 
694   if (dockable->p->dockbook)
695     gimp_dockbook_update_auto_tab_style (dockable->p->dockbook);
696 }
697 
698 /**
699  * gimp_dockable_set_actual_tab_style:
700  * @dockable:
701  * @tab_style:
702  *
703  * Sets actual tab style, meant for those that decides what
704  * "automatic" tab style means.
705  *
706  * Returns: %TRUE if changed, %FALSE otherwise.
707  **/
708 gboolean
gimp_dockable_set_actual_tab_style(GimpDockable * dockable,GimpTabStyle tab_style)709 gimp_dockable_set_actual_tab_style (GimpDockable *dockable,
710                                     GimpTabStyle  tab_style)
711 {
712   GimpTabStyle new_tab_style = gimp_dockable_convert_tab_style (dockable, tab_style);
713   GimpTabStyle old_tab_style = dockable->p->actual_tab_style;
714 
715   g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), FALSE);
716   g_return_val_if_fail (tab_style != GIMP_TAB_STYLE_AUTOMATIC, FALSE);
717 
718   dockable->p->actual_tab_style = new_tab_style;
719 
720   return new_tab_style != old_tab_style;
721 }
722 
723 GtkWidget *
gimp_dockable_create_tab_widget(GimpDockable * dockable,GimpContext * context,GimpTabStyle tab_style,GtkIconSize size)724 gimp_dockable_create_tab_widget (GimpDockable *dockable,
725                                  GimpContext  *context,
726                                  GimpTabStyle  tab_style,
727                                  GtkIconSize   size)
728 {
729   g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), NULL);
730   g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
731 
732   return gimp_dockable_new_tab_widget_internal (dockable, context,
733                                                 tab_style, size, FALSE);
734 }
735 
736 GtkWidget *
gimp_dockable_create_drag_widget(GimpDockable * dockable)737 gimp_dockable_create_drag_widget (GimpDockable *dockable)
738 {
739   GtkWidget *frame;
740   GtkWidget *widget;
741 
742   g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), NULL);
743 
744   frame = gtk_frame_new (NULL);
745   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
746 
747   widget = gimp_dockable_new_tab_widget_internal (dockable,
748                                                   dockable->p->context,
749                                                   GIMP_TAB_STYLE_ICON_BLURB,
750                                                   GTK_ICON_SIZE_DND,
751                                                   TRUE);
752   gtk_container_set_border_width (GTK_CONTAINER (widget), 6);
753   gtk_container_add (GTK_CONTAINER (frame), widget);
754   gtk_widget_show (widget);
755 
756   return frame;
757 }
758 
759 void
gimp_dockable_set_context(GimpDockable * dockable,GimpContext * context)760 gimp_dockable_set_context (GimpDockable *dockable,
761                            GimpContext  *context)
762 {
763   g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
764   g_return_if_fail (context == NULL || GIMP_IS_CONTEXT (context));
765 
766   if (context != dockable->p->context)
767     {
768       GtkWidget *child = gtk_bin_get_child (GTK_BIN (dockable));
769 
770       if (child)
771         gimp_docked_set_context (GIMP_DOCKED (child), context);
772 
773       dockable->p->context = context;
774     }
775 }
776 
777 GimpUIManager *
gimp_dockable_get_menu(GimpDockable * dockable,const gchar ** ui_path,gpointer * popup_data)778 gimp_dockable_get_menu (GimpDockable  *dockable,
779                         const gchar  **ui_path,
780                         gpointer      *popup_data)
781 {
782   GtkWidget *child;
783 
784   g_return_val_if_fail (GIMP_IS_DOCKABLE (dockable), NULL);
785   g_return_val_if_fail (ui_path != NULL, NULL);
786   g_return_val_if_fail (popup_data != NULL, NULL);
787 
788   child = gtk_bin_get_child (GTK_BIN (dockable));
789 
790   if (child)
791     return gimp_docked_get_menu (GIMP_DOCKED (child), ui_path, popup_data);
792 
793   return NULL;
794 }
795 
796 /**
797  * gimp_dockable_set_drag_handler:
798  * @dockable:
799  * @handler:
800  *
801  * Set a drag handler that will be asked if it will handle drag events
802  * before the dockable handles the event itself.
803  **/
804 void
gimp_dockable_set_drag_handler(GimpDockable * dockable,GimpPanedBox * handler)805 gimp_dockable_set_drag_handler (GimpDockable *dockable,
806                                 GimpPanedBox *handler)
807 {
808   g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
809 
810   dockable->p->drag_handler = handler;
811 }
812 
813 void
gimp_dockable_detach(GimpDockable * dockable)814 gimp_dockable_detach (GimpDockable *dockable)
815 {
816   GimpDialogFactory *dialog_factory;
817   GimpMenuFactory   *menu_factory;
818   GimpDockWindow    *src_dock_window;
819   GimpDock          *src_dock;
820   GtkWidget         *dock;
821   GimpDockWindow    *dock_window;
822   GtkWidget         *dockbook;
823 
824   g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
825   g_return_if_fail (GIMP_IS_DOCKBOOK (dockable->p->dockbook));
826 
827   src_dock        = gimp_dockbook_get_dock (dockable->p->dockbook);
828   src_dock_window = gimp_dock_window_from_dock (src_dock);
829 
830   dialog_factory = gimp_dock_get_dialog_factory (src_dock);
831   menu_factory   = gimp_dialog_factory_get_menu_factory (dialog_factory);
832 
833   dock = gimp_dock_with_window_new (dialog_factory,
834                                     gtk_widget_get_screen (GTK_WIDGET (dockable)),
835                                     gimp_widget_get_monitor (GTK_WIDGET (dockable)),
836                                     FALSE /*toolbox*/);
837   dock_window = gimp_dock_window_from_dock (GIMP_DOCK (dock));
838   gtk_window_set_position (GTK_WINDOW (dock_window), GTK_WIN_POS_MOUSE);
839   if (src_dock_window)
840     gimp_dock_window_setup (dock_window, src_dock_window);
841 
842   dockbook = gimp_dockbook_new (menu_factory);
843 
844   gimp_dock_add_book (GIMP_DOCK (dock), GIMP_DOCKBOOK (dockbook), 0);
845 
846   g_object_ref (dockable);
847 
848   gimp_dockbook_remove (dockable->p->dockbook, dockable);
849   gimp_dockbook_add (GIMP_DOCKBOOK (dockbook), dockable, 0);
850 
851   g_object_unref (dockable);
852 
853   gtk_widget_show (GTK_WIDGET (dock_window));
854   gtk_widget_show (dock);
855 }
856 
857 
858 /*  private functions  */
859 
860 static GList *
gimp_dockable_get_aux_info(GimpSessionManaged * session_managed)861 gimp_dockable_get_aux_info (GimpSessionManaged *session_managed)
862 {
863   GimpDockable *dockable;
864   GtkWidget    *child;
865 
866   g_return_val_if_fail (GIMP_IS_DOCKABLE (session_managed), NULL);
867 
868   dockable = GIMP_DOCKABLE (session_managed);
869 
870   child = gtk_bin_get_child (GTK_BIN (dockable));
871 
872   if (child)
873     return gimp_docked_get_aux_info (GIMP_DOCKED (child));
874 
875   return NULL;
876 }
877 
878 static void
gimp_dockable_set_aux_info(GimpSessionManaged * session_managed,GList * aux_info)879 gimp_dockable_set_aux_info (GimpSessionManaged *session_managed,
880                             GList              *aux_info)
881 {
882   GimpDockable *dockable;
883   GtkWidget    *child;
884 
885   g_return_if_fail (GIMP_IS_DOCKABLE (session_managed));
886 
887   dockable = GIMP_DOCKABLE (session_managed);
888 
889   child = gtk_bin_get_child (GTK_BIN (dockable));
890 
891   if (child)
892     gimp_docked_set_aux_info (GIMP_DOCKED (child), aux_info);
893 }
894 
895 static GimpTabStyle
gimp_dockable_convert_tab_style(GimpDockable * dockable,GimpTabStyle tab_style)896 gimp_dockable_convert_tab_style (GimpDockable   *dockable,
897                                  GimpTabStyle    tab_style)
898 {
899   GtkWidget *child = gtk_bin_get_child (GTK_BIN (dockable));
900 
901   if (child && ! GIMP_DOCKED_GET_INTERFACE (child)->get_preview)
902     tab_style = gimp_preview_tab_style_to_icon (tab_style);
903 
904   return tab_style;
905 }
906