1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimpcontainerview.c
5  * Copyright (C) 2001-2010 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/gimpcontainer.h"
33 #include "core/gimpcontext.h"
34 #include "core/gimpmarshal.h"
35 #include "core/gimptreehandler.h"
36 #include "core/gimpviewable.h"
37 
38 #include "gimpcontainerview.h"
39 #include "gimpdnd.h"
40 #include "gimpviewrenderer.h"
41 #include "gimpuimanager.h"
42 #include "gimpcontainertreeview.h"
43 
44 
45 enum
46 {
47   SELECT_ITEM,
48   ACTIVATE_ITEM,
49   CONTEXT_ITEM,
50   LAST_SIGNAL
51 };
52 
53 
54 #define GIMP_CONTAINER_VIEW_GET_PRIVATE(obj) (gimp_container_view_get_private ((GimpContainerView *) (obj)))
55 
56 
57 typedef struct _GimpContainerViewPrivate GimpContainerViewPrivate;
58 
59 struct _GimpContainerViewPrivate
60 {
61   GimpContainer   *container;
62   GimpContext     *context;
63 
64   GHashTable      *item_hash;
65 
66   gint             view_size;
67   gint             view_border_width;
68   gboolean         reorderable;
69   GtkSelectionMode selection_mode;
70 
71   /*  initialized by subclass  */
72   GtkWidget       *dnd_widget;
73 
74   GimpTreeHandler *name_changed_handler;
75   GimpTreeHandler *expanded_changed_handler;
76 };
77 
78 
79 /*  local function prototypes  */
80 
81 static GimpContainerViewPrivate *
82               gimp_container_view_get_private        (GimpContainerView *view);
83 
84 static void   gimp_container_view_real_set_container (GimpContainerView *view,
85                                                       GimpContainer     *container);
86 static void   gimp_container_view_real_set_context   (GimpContainerView *view,
87                                                       GimpContext       *context);
88 static void   gimp_container_view_real_set_selection_mode (GimpContainerView *view,
89                                                            GtkSelectionMode   mode);
90 
91 static void   gimp_container_view_clear_items      (GimpContainerView  *view);
92 static void   gimp_container_view_real_clear_items (GimpContainerView  *view);
93 
94 static void   gimp_container_view_add_container    (GimpContainerView  *view,
95                                                     GimpContainer      *container);
96 static void   gimp_container_view_add_foreach      (GimpViewable       *viewable,
97                                                     GimpContainerView  *view);
98 static void   gimp_container_view_add              (GimpContainerView  *view,
99                                                     GimpViewable       *viewable,
100                                                     GimpContainer      *container);
101 
102 static void   gimp_container_view_remove_container (GimpContainerView  *view,
103                                                     GimpContainer      *container);
104 static void   gimp_container_view_remove_foreach   (GimpViewable       *viewable,
105                                                     GimpContainerView  *view);
106 static void   gimp_container_view_remove           (GimpContainerView  *view,
107                                                     GimpViewable       *viewable,
108                                                     GimpContainer      *container);
109 
110 static void   gimp_container_view_reorder          (GimpContainerView  *view,
111                                                     GimpViewable       *viewable,
112                                                     gint                new_index,
113                                                     GimpContainer      *container);
114 
115 static void   gimp_container_view_freeze           (GimpContainerView  *view,
116                                                     GimpContainer      *container);
117 static void   gimp_container_view_thaw             (GimpContainerView  *view,
118                                                     GimpContainer      *container);
119 static void   gimp_container_view_name_changed     (GimpViewable       *viewable,
120                                                     GimpContainerView  *view);
121 static void   gimp_container_view_expanded_changed (GimpViewable       *viewable,
122                                                     GimpContainerView  *view);
123 
124 static void   gimp_container_view_connect_context    (GimpContainerView *view);
125 static void   gimp_container_view_disconnect_context (GimpContainerView *view);
126 
127 static void   gimp_container_view_context_changed  (GimpContext        *context,
128                                                     GimpViewable       *viewable,
129                                                     GimpContainerView  *view);
130 static void   gimp_container_view_viewable_dropped (GtkWidget          *widget,
131                                                     gint                x,
132                                                     gint                y,
133                                                     GimpViewable       *viewable,
134                                                     gpointer            data);
135 static void  gimp_container_view_button_viewable_dropped (GtkWidget    *widget,
136                                                           gint          x,
137                                                           gint          y,
138                                                           GimpViewable *viewable,
139                                                           gpointer      data);
140 static gint  gimp_container_view_real_get_selected (GimpContainerView    *view,
141                                                     GList               **list);
142 
143 
144 G_DEFINE_INTERFACE (GimpContainerView, gimp_container_view, GTK_TYPE_WIDGET)
145 
146 
147 static guint view_signals[LAST_SIGNAL] = { 0 };
148 
149 
150 static void
gimp_container_view_default_init(GimpContainerViewInterface * iface)151 gimp_container_view_default_init (GimpContainerViewInterface *iface)
152 {
153   view_signals[SELECT_ITEM] =
154     g_signal_new ("select-item",
155                   G_TYPE_FROM_INTERFACE (iface),
156                   G_SIGNAL_RUN_LAST,
157                   G_STRUCT_OFFSET (GimpContainerViewInterface, select_item),
158                   NULL, NULL,
159                   gimp_marshal_BOOLEAN__OBJECT_POINTER,
160                   G_TYPE_BOOLEAN, 2,
161                   GIMP_TYPE_OBJECT,
162                   G_TYPE_POINTER);
163 
164   view_signals[ACTIVATE_ITEM] =
165     g_signal_new ("activate-item",
166                   G_TYPE_FROM_INTERFACE (iface),
167                   G_SIGNAL_RUN_FIRST,
168                   G_STRUCT_OFFSET (GimpContainerViewInterface, activate_item),
169                   NULL, NULL,
170                   gimp_marshal_VOID__OBJECT_POINTER,
171                   G_TYPE_NONE, 2,
172                   GIMP_TYPE_OBJECT,
173                   G_TYPE_POINTER);
174 
175   view_signals[CONTEXT_ITEM] =
176     g_signal_new ("context-item",
177                   G_TYPE_FROM_INTERFACE (iface),
178                   G_SIGNAL_RUN_FIRST,
179                   G_STRUCT_OFFSET (GimpContainerViewInterface, context_item),
180                   NULL, NULL,
181                   gimp_marshal_VOID__OBJECT_POINTER,
182                   G_TYPE_NONE, 2,
183                   GIMP_TYPE_OBJECT,
184                   G_TYPE_POINTER);
185 
186   iface->select_item        = NULL;
187   iface->activate_item      = NULL;
188   iface->context_item       = NULL;
189 
190   iface->set_container      = gimp_container_view_real_set_container;
191   iface->set_context        = gimp_container_view_real_set_context;
192   iface->set_selection_mode = gimp_container_view_real_set_selection_mode;
193   iface->insert_item        = NULL;
194   iface->insert_item_after  = NULL;
195   iface->remove_item        = NULL;
196   iface->reorder_item       = NULL;
197   iface->rename_item        = NULL;
198   iface->expand_item        = NULL;
199   iface->clear_items        = gimp_container_view_real_clear_items;
200   iface->set_view_size      = NULL;
201   iface->get_selected       = gimp_container_view_real_get_selected;
202 
203   iface->insert_data_free   = NULL;
204   iface->model_is_tree      = FALSE;
205 
206   g_object_interface_install_property (iface,
207                                        g_param_spec_object ("container",
208                                                             NULL, NULL,
209                                                             GIMP_TYPE_CONTAINER,
210                                                             GIMP_PARAM_READWRITE));
211 
212   g_object_interface_install_property (iface,
213                                        g_param_spec_object ("context",
214                                                             NULL, NULL,
215                                                             GIMP_TYPE_CONTEXT,
216                                                             GIMP_PARAM_READWRITE));
217 
218   g_object_interface_install_property (iface,
219                                        g_param_spec_enum ("selection-mode",
220                                                           NULL, NULL,
221                                                           GTK_TYPE_SELECTION_MODE,
222                                                           GTK_SELECTION_SINGLE,
223                                                           GIMP_PARAM_READWRITE));
224 
225   g_object_interface_install_property (iface,
226                                        g_param_spec_boolean ("reorderable",
227                                                              NULL, NULL,
228                                                              FALSE,
229                                                              GIMP_PARAM_READWRITE));
230 
231   g_object_interface_install_property (iface,
232                                        g_param_spec_int ("view-size",
233                                                          NULL, NULL,
234                                                          1, GIMP_VIEWABLE_MAX_PREVIEW_SIZE,
235                                                          GIMP_VIEW_SIZE_MEDIUM,
236                                                          GIMP_PARAM_READWRITE |
237                                                          G_PARAM_CONSTRUCT));
238 
239   g_object_interface_install_property (iface,
240                                        g_param_spec_int ("view-border-width",
241                                                          NULL, NULL,
242                                                          0,
243                                                          GIMP_VIEW_MAX_BORDER_WIDTH,
244                                                          1,
245                                                          GIMP_PARAM_READWRITE |
246                                                          G_PARAM_CONSTRUCT));
247 }
248 
249 static void
gimp_container_view_private_dispose(GimpContainerView * view,GimpContainerViewPrivate * private)250 gimp_container_view_private_dispose (GimpContainerView        *view,
251                                      GimpContainerViewPrivate *private)
252 {
253   if (private->container)
254     gimp_container_view_set_container (view, NULL);
255 
256   if (private->context)
257     gimp_container_view_set_context (view, NULL);
258 }
259 
260 static void
gimp_container_view_private_finalize(GimpContainerViewPrivate * private)261 gimp_container_view_private_finalize (GimpContainerViewPrivate *private)
262 {
263   if (private->item_hash)
264     {
265       g_hash_table_destroy (private->item_hash);
266       private->item_hash = NULL;
267     }
268   g_clear_pointer (&private->name_changed_handler,
269                    gimp_tree_handler_disconnect);
270   g_clear_pointer (&private->expanded_changed_handler,
271                    gimp_tree_handler_disconnect);
272 
273   g_slice_free (GimpContainerViewPrivate, private);
274 }
275 
276 static GimpContainerViewPrivate *
gimp_container_view_get_private(GimpContainerView * view)277 gimp_container_view_get_private (GimpContainerView *view)
278 {
279   GimpContainerViewPrivate *private;
280 
281   static GQuark private_key = 0;
282 
283   g_return_val_if_fail (GIMP_IS_CONTAINER_VIEW (view), NULL);
284 
285   if (! private_key)
286     private_key = g_quark_from_static_string ("gimp-container-view-private");
287 
288   private = g_object_get_qdata ((GObject *) view, private_key);
289 
290   if (! private)
291     {
292       GimpContainerViewInterface *view_iface;
293 
294       view_iface = GIMP_CONTAINER_VIEW_GET_INTERFACE (view);
295 
296       private = g_slice_new0 (GimpContainerViewPrivate);
297 
298       private->view_border_width = 1;
299 
300       private->item_hash = g_hash_table_new_full (g_direct_hash,
301                                                   g_direct_equal,
302                                                   NULL,
303                                                   view_iface->insert_data_free);
304 
305       g_object_set_qdata_full ((GObject *) view, private_key, private,
306                                (GDestroyNotify) gimp_container_view_private_finalize);
307 
308       g_signal_connect (view, "destroy",
309                         G_CALLBACK (gimp_container_view_private_dispose),
310                         private);
311     }
312 
313   return private;
314 }
315 
316 /**
317  * gimp_container_view_install_properties:
318  * @klass: the class structure for a type deriving from #GObject
319  *
320  * Installs the necessary properties for a class implementing
321  * #GimpContainerView. A #GimpContainerViewProp property is installed
322  * for each property, using the values from the #GimpContainerViewProp
323  * enumeration. The caller must make sure itself that the enumeration
324  * values don't collide with some other property values they
325  * are using (that's what %GIMP_CONTAINER_VIEW_PROP_LAST is good for).
326  **/
327 void
gimp_container_view_install_properties(GObjectClass * klass)328 gimp_container_view_install_properties (GObjectClass *klass)
329 {
330   g_object_class_override_property (klass,
331                                     GIMP_CONTAINER_VIEW_PROP_CONTAINER,
332                                     "container");
333   g_object_class_override_property (klass,
334                                     GIMP_CONTAINER_VIEW_PROP_CONTEXT,
335                                     "context");
336   g_object_class_override_property (klass,
337                                     GIMP_CONTAINER_VIEW_PROP_SELECTION_MODE,
338                                     "selection-mode");
339   g_object_class_override_property (klass,
340                                     GIMP_CONTAINER_VIEW_PROP_REORDERABLE,
341                                     "reorderable");
342   g_object_class_override_property (klass,
343                                     GIMP_CONTAINER_VIEW_PROP_VIEW_SIZE,
344                                     "view-size");
345   g_object_class_override_property (klass,
346                                     GIMP_CONTAINER_VIEW_PROP_VIEW_BORDER_WIDTH,
347                                     "view-border-width");
348 }
349 
350 GimpContainer *
gimp_container_view_get_container(GimpContainerView * view)351 gimp_container_view_get_container (GimpContainerView *view)
352 {
353   GimpContainerViewPrivate *private;
354 
355   g_return_val_if_fail (GIMP_IS_CONTAINER_VIEW (view), NULL);
356 
357   private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
358 
359   return private->container;
360 }
361 
362 void
gimp_container_view_set_container(GimpContainerView * view,GimpContainer * container)363 gimp_container_view_set_container (GimpContainerView *view,
364                                    GimpContainer     *container)
365 {
366   GimpContainerViewPrivate *private;
367 
368   g_return_if_fail (GIMP_IS_CONTAINER_VIEW (view));
369   g_return_if_fail (container == NULL || GIMP_IS_CONTAINER (container));
370   if (container)
371     g_return_if_fail (g_type_is_a (gimp_container_get_children_type (container),
372                                    GIMP_TYPE_VIEWABLE));
373 
374   private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
375 
376   if (container != private->container)
377     {
378       GIMP_CONTAINER_VIEW_GET_INTERFACE (view)->set_container (view, container);
379 
380       g_object_notify (G_OBJECT (view), "container");
381     }
382 }
383 
384 static void
gimp_container_view_real_set_container(GimpContainerView * view,GimpContainer * container)385 gimp_container_view_real_set_container (GimpContainerView *view,
386                                         GimpContainer     *container)
387 {
388   GimpContainerViewPrivate *private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
389 
390   if (private->container)
391     {
392       if (private->context)
393         gimp_container_view_disconnect_context (view);
394 
395       gimp_container_view_select_item (view, NULL);
396 
397       /* freeze/thaw is only supported for the toplevel container */
398       g_signal_handlers_disconnect_by_func (private->container,
399                                             gimp_container_view_freeze,
400                                             view);
401       g_signal_handlers_disconnect_by_func (private->container,
402                                             gimp_container_view_thaw,
403                                             view);
404 
405       if (! gimp_container_frozen (private->container))
406         gimp_container_view_remove_container (view, private->container);
407     }
408 
409   private->container = container;
410 
411   if (private->container)
412     {
413       if (! gimp_container_frozen (private->container))
414         gimp_container_view_add_container (view, private->container);
415 
416       /* freeze/thaw is only supported for the toplevel container */
417       g_signal_connect_object (private->container, "freeze",
418                                G_CALLBACK (gimp_container_view_freeze),
419                                view,
420                                G_CONNECT_SWAPPED);
421       g_signal_connect_object (private->container, "thaw",
422                                G_CALLBACK (gimp_container_view_thaw),
423                                view,
424                                G_CONNECT_SWAPPED);
425 
426       if (private->context)
427         gimp_container_view_connect_context (view);
428     }
429 }
430 
431 GimpContext *
gimp_container_view_get_context(GimpContainerView * view)432 gimp_container_view_get_context (GimpContainerView *view)
433 {
434   GimpContainerViewPrivate *private;
435 
436   g_return_val_if_fail (GIMP_IS_CONTAINER_VIEW (view), NULL);
437 
438   private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
439 
440   return private->context;
441 }
442 
443 void
gimp_container_view_set_context(GimpContainerView * view,GimpContext * context)444 gimp_container_view_set_context (GimpContainerView *view,
445                                  GimpContext       *context)
446 {
447   GimpContainerViewPrivate *private;
448 
449   g_return_if_fail (GIMP_IS_CONTAINER_VIEW (view));
450   g_return_if_fail (context == NULL || GIMP_IS_CONTEXT (context));
451 
452   private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
453 
454   if (context != private->context)
455     {
456       GIMP_CONTAINER_VIEW_GET_INTERFACE (view)->set_context (view, context);
457 
458       g_object_notify (G_OBJECT (view), "context");
459     }
460 }
461 
462 static void
gimp_container_view_real_set_context(GimpContainerView * view,GimpContext * context)463 gimp_container_view_real_set_context (GimpContainerView *view,
464                                       GimpContext       *context)
465 {
466   GimpContainerViewPrivate *private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
467 
468   if (private->context &&
469       private->container)
470     {
471       gimp_container_view_disconnect_context (view);
472     }
473 
474   g_set_object (&private->context, context);
475 
476   if (private->context &&
477       private->container)
478     {
479       gimp_container_view_connect_context (view);
480     }
481 }
482 
483 GtkSelectionMode
gimp_container_view_get_selection_mode(GimpContainerView * view)484 gimp_container_view_get_selection_mode (GimpContainerView *view)
485 {
486   GimpContainerViewPrivate *private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
487 
488   return private->selection_mode;
489 }
490 
491 void
gimp_container_view_set_selection_mode(GimpContainerView * view,GtkSelectionMode mode)492 gimp_container_view_set_selection_mode (GimpContainerView *view,
493                                         GtkSelectionMode   mode)
494 {
495   g_return_if_fail (GIMP_IS_CONTAINER_VIEW (view));
496   g_return_if_fail (mode == GTK_SELECTION_SINGLE ||
497                     mode == GTK_SELECTION_MULTIPLE);
498 
499   GIMP_CONTAINER_VIEW_GET_INTERFACE (view)->set_selection_mode (view, mode);
500 }
501 
502 static void
gimp_container_view_real_set_selection_mode(GimpContainerView * view,GtkSelectionMode mode)503 gimp_container_view_real_set_selection_mode (GimpContainerView *view,
504                                              GtkSelectionMode   mode)
505 {
506   GimpContainerViewPrivate *private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
507 
508   private->selection_mode = mode;
509 }
510 
511 gint
gimp_container_view_get_view_size(GimpContainerView * view,gint * view_border_width)512 gimp_container_view_get_view_size (GimpContainerView *view,
513                                    gint              *view_border_width)
514 {
515   GimpContainerViewPrivate *private;
516 
517   g_return_val_if_fail (GIMP_IS_CONTAINER_VIEW (view), 0);
518 
519   private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
520 
521   if (view_border_width)
522     *view_border_width = private->view_border_width;
523 
524   return private->view_size;
525 }
526 
527 void
gimp_container_view_set_view_size(GimpContainerView * view,gint view_size,gint view_border_width)528 gimp_container_view_set_view_size (GimpContainerView *view,
529                                    gint               view_size,
530                                    gint               view_border_width)
531 {
532   GimpContainerViewPrivate *private;
533 
534   g_return_if_fail (GIMP_IS_CONTAINER_VIEW (view));
535   g_return_if_fail (view_size >  0 &&
536                     view_size <= GIMP_VIEWABLE_MAX_PREVIEW_SIZE);
537   g_return_if_fail (view_border_width >= 0 &&
538                     view_border_width <= GIMP_VIEW_MAX_BORDER_WIDTH);
539 
540   private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
541 
542   if (private->view_size         != view_size ||
543       private->view_border_width != view_border_width)
544     {
545       private->view_size         = view_size;
546       private->view_border_width = view_border_width;
547 
548       GIMP_CONTAINER_VIEW_GET_INTERFACE (view)->set_view_size (view);
549 
550       g_object_freeze_notify (G_OBJECT (view));
551       g_object_notify (G_OBJECT (view), "view-size");
552       g_object_notify (G_OBJECT (view), "view-border-width");
553       g_object_thaw_notify (G_OBJECT (view));
554     }
555 }
556 
557 gboolean
gimp_container_view_get_reorderable(GimpContainerView * view)558 gimp_container_view_get_reorderable (GimpContainerView *view)
559 {
560   GimpContainerViewPrivate *private;
561 
562   g_return_val_if_fail (GIMP_IS_CONTAINER_VIEW (view), FALSE);
563 
564   private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
565 
566   return private->reorderable;
567 }
568 
569 void
gimp_container_view_set_reorderable(GimpContainerView * view,gboolean reorderable)570 gimp_container_view_set_reorderable (GimpContainerView *view,
571                                      gboolean           reorderable)
572 {
573   GimpContainerViewPrivate *private;
574 
575   g_return_if_fail (GIMP_IS_CONTAINER_VIEW (view));
576 
577   private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
578 
579   private->reorderable = reorderable ? TRUE : FALSE;
580   g_object_notify (G_OBJECT (view), "reorderable");
581 }
582 
583 GtkWidget *
gimp_container_view_get_dnd_widget(GimpContainerView * view)584 gimp_container_view_get_dnd_widget (GimpContainerView *view)
585 {
586   GimpContainerViewPrivate *private;
587 
588   g_return_val_if_fail (GIMP_IS_CONTAINER_VIEW (view), NULL);
589 
590   private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
591 
592   return private->dnd_widget;
593 }
594 
595 void
gimp_container_view_set_dnd_widget(GimpContainerView * view,GtkWidget * dnd_widget)596 gimp_container_view_set_dnd_widget (GimpContainerView *view,
597                                     GtkWidget         *dnd_widget)
598 {
599   GimpContainerViewPrivate *private;
600 
601   g_return_if_fail (GIMP_IS_CONTAINER_VIEW (view));
602   g_return_if_fail (dnd_widget == NULL || GTK_IS_WIDGET (dnd_widget));
603 
604   private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
605 
606   private->dnd_widget = dnd_widget;
607 }
608 
609 void
gimp_container_view_enable_dnd(GimpContainerView * view,GtkButton * button,GType children_type)610 gimp_container_view_enable_dnd (GimpContainerView *view,
611                                 GtkButton         *button,
612                                 GType              children_type)
613 {
614   g_return_if_fail (GIMP_IS_CONTAINER_VIEW (view));
615   g_return_if_fail (GTK_IS_BUTTON (button));
616 
617   gimp_dnd_viewable_dest_add (GTK_WIDGET (button),
618                               children_type,
619                               gimp_container_view_button_viewable_dropped,
620                               view);
621 }
622 
623 gboolean
gimp_container_view_select_item(GimpContainerView * view,GimpViewable * viewable)624 gimp_container_view_select_item (GimpContainerView *view,
625                                  GimpViewable      *viewable)
626 {
627   GimpContainerViewPrivate *private;
628   gboolean                  success = FALSE;
629   gpointer                  insert_data;
630 
631   g_return_val_if_fail (GIMP_IS_CONTAINER_VIEW (view), FALSE);
632   g_return_val_if_fail (viewable == NULL || GIMP_IS_VIEWABLE (viewable), FALSE);
633 
634   private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
635 
636   if (gimp_container_frozen (private->container))
637     return TRUE;
638 
639   insert_data = g_hash_table_lookup (private->item_hash, viewable);
640 
641   g_signal_emit (view, view_signals[SELECT_ITEM], 0,
642                  viewable, insert_data, &success);
643 
644   return success;
645 }
646 
647 void
gimp_container_view_activate_item(GimpContainerView * view,GimpViewable * viewable)648 gimp_container_view_activate_item (GimpContainerView *view,
649                                    GimpViewable      *viewable)
650 {
651   GimpContainerViewPrivate *private;
652   gpointer                  insert_data;
653 
654   g_return_if_fail (GIMP_IS_CONTAINER_VIEW (view));
655   g_return_if_fail (GIMP_IS_VIEWABLE (viewable));
656 
657   private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
658 
659   if (gimp_container_frozen (private->container))
660     return;
661 
662   insert_data = g_hash_table_lookup (private->item_hash, viewable);
663 
664   g_signal_emit (view, view_signals[ACTIVATE_ITEM], 0,
665                  viewable, insert_data);
666 }
667 
668 void
gimp_container_view_context_item(GimpContainerView * view,GimpViewable * viewable)669 gimp_container_view_context_item (GimpContainerView *view,
670                                   GimpViewable      *viewable)
671 {
672   GimpContainerViewPrivate *private;
673   gpointer                  insert_data;
674 
675   g_return_if_fail (GIMP_IS_CONTAINER_VIEW (view));
676   g_return_if_fail (GIMP_IS_VIEWABLE (viewable));
677 
678   private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
679 
680   if (gimp_container_frozen (private->container))
681     return;
682 
683   insert_data = g_hash_table_lookup (private->item_hash, viewable);
684 
685   g_signal_emit (view, view_signals[CONTEXT_ITEM], 0,
686                  viewable, insert_data);
687 }
688 
689 gpointer
gimp_container_view_lookup(GimpContainerView * view,GimpViewable * viewable)690 gimp_container_view_lookup (GimpContainerView *view,
691                             GimpViewable      *viewable)
692 {
693   GimpContainerViewPrivate *private;
694 
695   g_return_val_if_fail (GIMP_IS_CONTAINER_VIEW (view), NULL);
696   g_return_val_if_fail (viewable == NULL || GIMP_IS_VIEWABLE (viewable), NULL);
697 
698   /*  we handle the NULL viewable here as a workaround for bug #149906 */
699   if (! viewable)
700     return NULL;
701 
702   private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
703 
704   return g_hash_table_lookup (private->item_hash, viewable);
705 }
706 
707 gboolean
gimp_container_view_item_selected(GimpContainerView * view,GimpViewable * viewable)708 gimp_container_view_item_selected (GimpContainerView *view,
709                                    GimpViewable      *viewable)
710 {
711   GimpContainerViewPrivate *private;
712   gboolean                  success;
713 
714   g_return_val_if_fail (GIMP_IS_CONTAINER_VIEW (view), FALSE);
715   g_return_val_if_fail (GIMP_IS_VIEWABLE (viewable), FALSE);
716 
717   private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
718 
719   /* HACK */
720   if (private->container && private->context)
721     {
722       GType        children_type;
723       const gchar *signal_name;
724 
725       children_type = gimp_container_get_children_type (private->container);
726       signal_name   = gimp_context_type_to_signal_name (children_type);
727 
728       if (signal_name)
729         {
730           gimp_context_set_by_type (private->context, children_type,
731                                     GIMP_OBJECT (viewable));
732           return TRUE;
733         }
734     }
735 
736   success = gimp_container_view_select_item (view, viewable);
737 
738 #if 0
739   if (success && private->container && private->context)
740     {
741       GimpContext *context;
742       GType        children_type;
743 
744       /*  ref and remember the context because private->context may
745        *  become NULL by calling gimp_context_set_by_type()
746        */
747       context       = g_object_ref (private->context);
748       children_type = gimp_container_get_children_type (private->container);
749 
750       g_signal_handlers_block_by_func (context,
751                                        gimp_container_view_context_changed,
752                                        view);
753 
754       gimp_context_set_by_type (context, children_type, GIMP_OBJECT (viewable));
755 
756       g_signal_handlers_unblock_by_func (context,
757                                          gimp_container_view_context_changed,
758                                          view);
759 
760       g_object_unref (context);
761     }
762 #endif
763 
764   return success;
765 }
766 
767 gboolean
gimp_container_view_multi_selected(GimpContainerView * view,GList * items)768 gimp_container_view_multi_selected (GimpContainerView *view,
769                                     GList             *items)
770 {
771   guint                     selected_count;
772   gboolean                  success = FALSE;
773 
774   g_return_val_if_fail (GIMP_IS_CONTAINER_VIEW (view), FALSE);
775 
776   selected_count = g_list_length (items);
777 
778   if (selected_count == 0)
779     {
780       /* do nothing */
781     }
782   else if (selected_count == 1)
783     {
784       success = gimp_container_view_item_selected (view, items->data);
785     }
786   else
787     {
788       success = FALSE;
789       g_signal_emit (view, view_signals[SELECT_ITEM], 0,
790                      NULL, items, &success);
791     }
792 
793   return success;
794 }
795 
796 gint
gimp_container_view_get_selected(GimpContainerView * view,GList ** list)797 gimp_container_view_get_selected (GimpContainerView  *view,
798                                   GList             **list)
799 {
800   g_return_val_if_fail (GIMP_IS_CONTAINER_VIEW (view), 0);
801 
802   return GIMP_CONTAINER_VIEW_GET_INTERFACE (view)->get_selected (view, list);
803 }
804 
805 static gint
gimp_container_view_real_get_selected(GimpContainerView * view,GList ** list)806 gimp_container_view_real_get_selected (GimpContainerView    *view,
807                                        GList               **list)
808 {
809   GimpContainerViewPrivate *private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
810   GType                     children_type;
811   GimpObject               *object;
812 
813   if (list)
814     *list = NULL;
815 
816   if (! private->container || ! private->context)
817     return 0;
818 
819   children_type = gimp_container_get_children_type (private->container);
820   object = gimp_context_get_by_type (private->context,
821                                      children_type);
822 
823   if (list && object)
824     *list = g_list_append (*list, object);
825 
826   return object ? 1 : 0;
827 }
828 
829 void
gimp_container_view_item_activated(GimpContainerView * view,GimpViewable * viewable)830 gimp_container_view_item_activated (GimpContainerView *view,
831                                     GimpViewable      *viewable)
832 {
833   g_return_if_fail (GIMP_IS_CONTAINER_VIEW (view));
834   g_return_if_fail (GIMP_IS_VIEWABLE (viewable));
835 
836   gimp_container_view_activate_item (view, viewable);
837 }
838 
839 void
gimp_container_view_item_context(GimpContainerView * view,GimpViewable * viewable)840 gimp_container_view_item_context (GimpContainerView *view,
841                                   GimpViewable      *viewable)
842 {
843   g_return_if_fail (GIMP_IS_CONTAINER_VIEW (view));
844   g_return_if_fail (GIMP_IS_VIEWABLE (viewable));
845 
846   gimp_container_view_context_item (view, viewable);
847 }
848 
849 void
gimp_container_view_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)850 gimp_container_view_set_property (GObject      *object,
851                                   guint         property_id,
852                                   const GValue *value,
853                                   GParamSpec   *pspec)
854 {
855   GimpContainerView *view = GIMP_CONTAINER_VIEW (object);
856 
857   switch (property_id)
858     {
859     case GIMP_CONTAINER_VIEW_PROP_CONTAINER:
860       gimp_container_view_set_container (view, g_value_get_object (value));
861       break;
862     case GIMP_CONTAINER_VIEW_PROP_CONTEXT:
863       gimp_container_view_set_context (view, g_value_get_object (value));
864       break;
865     case GIMP_CONTAINER_VIEW_PROP_SELECTION_MODE:
866       gimp_container_view_set_selection_mode (view, g_value_get_enum (value));
867       break;
868     case GIMP_CONTAINER_VIEW_PROP_REORDERABLE:
869       gimp_container_view_set_reorderable (view, g_value_get_boolean (value));
870       break;
871     case GIMP_CONTAINER_VIEW_PROP_VIEW_SIZE:
872     case GIMP_CONTAINER_VIEW_PROP_VIEW_BORDER_WIDTH:
873       {
874         gint size, border;
875 
876         size = gimp_container_view_get_view_size (view, &border);
877 
878         if (property_id == GIMP_CONTAINER_VIEW_PROP_VIEW_SIZE)
879           size = g_value_get_int (value);
880         else
881           border = g_value_get_int (value);
882 
883         gimp_container_view_set_view_size (view, size, border);
884       }
885       break;
886     default:
887       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
888       break;
889     }
890 }
891 
892 void
gimp_container_view_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)893 gimp_container_view_get_property (GObject    *object,
894                                   guint       property_id,
895                                   GValue     *value,
896                                   GParamSpec *pspec)
897 {
898   GimpContainerView *view = GIMP_CONTAINER_VIEW (object);
899 
900   switch (property_id)
901     {
902     case GIMP_CONTAINER_VIEW_PROP_CONTAINER:
903       g_value_set_object (value, gimp_container_view_get_container (view));
904       break;
905     case GIMP_CONTAINER_VIEW_PROP_CONTEXT:
906       g_value_set_object (value, gimp_container_view_get_context (view));
907       break;
908     case GIMP_CONTAINER_VIEW_PROP_SELECTION_MODE:
909       g_value_set_enum (value, gimp_container_view_get_selection_mode (view));
910       break;
911     case GIMP_CONTAINER_VIEW_PROP_REORDERABLE:
912       g_value_set_boolean (value, gimp_container_view_get_reorderable (view));
913       break;
914     case GIMP_CONTAINER_VIEW_PROP_VIEW_SIZE:
915     case GIMP_CONTAINER_VIEW_PROP_VIEW_BORDER_WIDTH:
916       {
917         gint size, border;
918 
919         size = gimp_container_view_get_view_size (view, &border);
920 
921         if (property_id == GIMP_CONTAINER_VIEW_PROP_VIEW_SIZE)
922           g_value_set_int (value, size);
923         else
924           g_value_set_int (value, border);
925       }
926       break;
927     default:
928       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
929       break;
930     }
931 }
932 
933 static void
gimp_container_view_clear_items(GimpContainerView * view)934 gimp_container_view_clear_items (GimpContainerView *view)
935 {
936   GIMP_CONTAINER_VIEW_GET_INTERFACE (view)->clear_items (view);
937 }
938 
939 static void
gimp_container_view_real_clear_items(GimpContainerView * view)940 gimp_container_view_real_clear_items (GimpContainerView *view)
941 {
942   GimpContainerViewPrivate *private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
943 
944   g_hash_table_remove_all (private->item_hash);
945 }
946 
947 static void
gimp_container_view_add_container(GimpContainerView * view,GimpContainer * container)948 gimp_container_view_add_container (GimpContainerView *view,
949                                    GimpContainer     *container)
950 {
951   GimpContainerViewPrivate *private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
952 
953   gimp_container_foreach (container,
954                           (GFunc) gimp_container_view_add_foreach,
955                           view);
956 
957   if (container == private->container)
958     {
959       GType              children_type;
960       GimpViewableClass *viewable_class;
961 
962       children_type  = gimp_container_get_children_type (container);
963       viewable_class = g_type_class_ref (children_type);
964 
965       private->name_changed_handler =
966         gimp_tree_handler_connect (container,
967                                    viewable_class->name_changed_signal,
968                                    G_CALLBACK (gimp_container_view_name_changed),
969                                    view);
970 
971       if (GIMP_CONTAINER_VIEW_GET_INTERFACE (view)->expand_item)
972         {
973           private->expanded_changed_handler =
974             gimp_tree_handler_connect (container,
975                                        "expanded-changed",
976                                        G_CALLBACK (gimp_container_view_expanded_changed),
977                                        view);
978         }
979 
980       g_type_class_unref (viewable_class);
981     }
982 
983   g_signal_connect_object (container, "add",
984                            G_CALLBACK (gimp_container_view_add),
985                            view,
986                            G_CONNECT_SWAPPED);
987   g_signal_connect_object (container, "remove",
988                            G_CALLBACK (gimp_container_view_remove),
989                            view,
990                            G_CONNECT_SWAPPED);
991   g_signal_connect_object (container, "reorder",
992                            G_CALLBACK (gimp_container_view_reorder),
993                            view,
994                            G_CONNECT_SWAPPED);
995 }
996 
997 static void
gimp_container_view_add_foreach(GimpViewable * viewable,GimpContainerView * view)998 gimp_container_view_add_foreach (GimpViewable      *viewable,
999                                  GimpContainerView *view)
1000 {
1001   GimpContainerViewInterface *view_iface;
1002   GimpContainerViewPrivate   *private;
1003   GimpViewable               *parent;
1004   GimpContainer              *children;
1005   gpointer                    parent_insert_data = NULL;
1006   gpointer                    insert_data;
1007 
1008   view_iface = GIMP_CONTAINER_VIEW_GET_INTERFACE (view);
1009   private    = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
1010 
1011   parent = gimp_viewable_get_parent (viewable);
1012 
1013   if (parent)
1014     parent_insert_data = g_hash_table_lookup (private->item_hash, parent);
1015 
1016   insert_data = view_iface->insert_item (view, viewable,
1017                                          parent_insert_data, -1);
1018 
1019   g_hash_table_insert (private->item_hash, viewable, insert_data);
1020 
1021   if (view_iface->insert_item_after)
1022     view_iface->insert_item_after (view, viewable, insert_data);
1023 
1024   children = gimp_viewable_get_children (viewable);
1025 
1026   if (children)
1027     gimp_container_view_add_container (view, children);
1028 }
1029 
1030 static void
gimp_container_view_add(GimpContainerView * view,GimpViewable * viewable,GimpContainer * container)1031 gimp_container_view_add (GimpContainerView *view,
1032                          GimpViewable      *viewable,
1033                          GimpContainer     *container)
1034 {
1035   GimpContainerViewInterface *view_iface;
1036   GimpContainerViewPrivate   *private;
1037   GimpViewable               *parent;
1038   GimpContainer              *children;
1039   gpointer                    parent_insert_data = NULL;
1040   gpointer                    insert_data;
1041   gint                        index;
1042 
1043   view_iface = GIMP_CONTAINER_VIEW_GET_INTERFACE (view);
1044   private    = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
1045 
1046   index = gimp_container_get_child_index (container,
1047                                           GIMP_OBJECT (viewable));
1048 
1049   parent = gimp_viewable_get_parent (viewable);
1050 
1051   if (parent)
1052     parent_insert_data = g_hash_table_lookup (private->item_hash, parent);
1053 
1054   insert_data = view_iface->insert_item (view, viewable,
1055                                          parent_insert_data, index);
1056 
1057   g_hash_table_insert (private->item_hash, viewable, insert_data);
1058 
1059   if (view_iface->insert_item_after)
1060     view_iface->insert_item_after (view, viewable, insert_data);
1061 
1062   children = gimp_viewable_get_children (viewable);
1063 
1064   if (children)
1065     gimp_container_view_add_container (view, children);
1066 }
1067 
1068 static void
gimp_container_view_remove_container(GimpContainerView * view,GimpContainer * container)1069 gimp_container_view_remove_container (GimpContainerView *view,
1070                                       GimpContainer     *container)
1071 {
1072   GimpContainerViewPrivate *private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
1073 
1074   g_object_ref (container);
1075 
1076   g_signal_handlers_disconnect_by_func (container,
1077                                         gimp_container_view_add,
1078                                         view);
1079   g_signal_handlers_disconnect_by_func (container,
1080                                         gimp_container_view_remove,
1081                                         view);
1082   g_signal_handlers_disconnect_by_func (container,
1083                                         gimp_container_view_reorder,
1084                                         view);
1085 
1086   if (container == private->container)
1087     {
1088       g_clear_pointer (&private->name_changed_handler,
1089                        gimp_tree_handler_disconnect);
1090       g_clear_pointer (&private->expanded_changed_handler,
1091                        gimp_tree_handler_disconnect);
1092 
1093       /* optimization: when the toplevel container gets removed, call
1094        * clear_items() which will get rid of all view widget stuff
1095        * *and* empty private->item_hash, so below call to
1096        * remove_foreach() will only disconnect all containers but not
1097        * remove all items individually (because they are gone from
1098        * item_hash).
1099        */
1100       gimp_container_view_clear_items (view);
1101     }
1102 
1103   gimp_container_foreach (container,
1104                           (GFunc) gimp_container_view_remove_foreach,
1105                           view);
1106 
1107   g_object_unref (container);
1108 }
1109 
1110 static void
gimp_container_view_remove_foreach(GimpViewable * viewable,GimpContainerView * view)1111 gimp_container_view_remove_foreach (GimpViewable      *viewable,
1112                                     GimpContainerView *view)
1113 {
1114   gimp_container_view_remove (view, viewable, NULL);
1115 }
1116 
1117 static void
gimp_container_view_remove(GimpContainerView * view,GimpViewable * viewable,GimpContainer * unused)1118 gimp_container_view_remove (GimpContainerView *view,
1119                             GimpViewable      *viewable,
1120                             GimpContainer     *unused)
1121 {
1122   GimpContainerViewPrivate *private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
1123   GimpContainer            *children;
1124   gpointer                  insert_data;
1125 
1126   children = gimp_viewable_get_children (viewable);
1127 
1128   if (children)
1129     gimp_container_view_remove_container (view, children);
1130 
1131   insert_data = g_hash_table_lookup (private->item_hash, viewable);
1132 
1133   if (insert_data)
1134     {
1135       GIMP_CONTAINER_VIEW_GET_INTERFACE (view)->remove_item (view,
1136                                                              viewable,
1137                                                              insert_data);
1138 
1139       g_hash_table_remove (private->item_hash, viewable);
1140     }
1141 }
1142 
1143 static void
gimp_container_view_reorder(GimpContainerView * view,GimpViewable * viewable,gint new_index,GimpContainer * container)1144 gimp_container_view_reorder (GimpContainerView *view,
1145                              GimpViewable      *viewable,
1146                              gint               new_index,
1147                              GimpContainer     *container)
1148 {
1149   GimpContainerViewPrivate *private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
1150   gpointer                  insert_data;
1151 
1152   insert_data = g_hash_table_lookup (private->item_hash, viewable);
1153 
1154   if (insert_data)
1155     {
1156       GIMP_CONTAINER_VIEW_GET_INTERFACE (view)->reorder_item (view,
1157                                                               viewable,
1158                                                               new_index,
1159                                                               insert_data);
1160     }
1161 }
1162 
1163 static void
gimp_container_view_freeze(GimpContainerView * view,GimpContainer * container)1164 gimp_container_view_freeze (GimpContainerView *view,
1165                             GimpContainer     *container)
1166 {
1167   gimp_container_view_remove_container (view, container);
1168 }
1169 
1170 static void
gimp_container_view_thaw(GimpContainerView * view,GimpContainer * container)1171 gimp_container_view_thaw (GimpContainerView *view,
1172                           GimpContainer     *container)
1173 {
1174   GimpContainerViewPrivate *private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
1175 
1176   gimp_container_view_add_container (view, container);
1177 
1178   if (private->context)
1179     {
1180       GType        children_type;
1181       const gchar *signal_name;
1182 
1183       children_type = gimp_container_get_children_type (private->container);
1184       signal_name   = gimp_context_type_to_signal_name (children_type);
1185 
1186       if (signal_name)
1187         {
1188           GimpObject *object;
1189 
1190           object = gimp_context_get_by_type (private->context, children_type);
1191 
1192           gimp_container_view_select_item (view, GIMP_VIEWABLE (object));
1193         }
1194     }
1195 }
1196 
1197 static void
gimp_container_view_name_changed(GimpViewable * viewable,GimpContainerView * view)1198 gimp_container_view_name_changed (GimpViewable      *viewable,
1199                                   GimpContainerView *view)
1200 {
1201   GimpContainerViewPrivate *private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
1202   gpointer                  insert_data;
1203 
1204   insert_data = g_hash_table_lookup (private->item_hash, viewable);
1205 
1206   if (insert_data)
1207     {
1208       GIMP_CONTAINER_VIEW_GET_INTERFACE (view)->rename_item (view,
1209                                                              viewable,
1210                                                              insert_data);
1211     }
1212 }
1213 
1214 static void
gimp_container_view_expanded_changed(GimpViewable * viewable,GimpContainerView * view)1215 gimp_container_view_expanded_changed (GimpViewable      *viewable,
1216                                       GimpContainerView *view)
1217 {
1218   GimpContainerViewPrivate *private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
1219   gpointer                  insert_data;
1220 
1221   insert_data = g_hash_table_lookup (private->item_hash, viewable);
1222 
1223   if (insert_data)
1224     {
1225       GIMP_CONTAINER_VIEW_GET_INTERFACE (view)->expand_item (view,
1226                                                              viewable,
1227                                                              insert_data);
1228     }
1229 }
1230 
1231 static void
gimp_container_view_connect_context(GimpContainerView * view)1232 gimp_container_view_connect_context (GimpContainerView *view)
1233 {
1234   GimpContainerViewPrivate *private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
1235   GType                     children_type;
1236   const gchar              *signal_name;
1237 
1238   children_type = gimp_container_get_children_type (private->container);
1239   signal_name   = gimp_context_type_to_signal_name (children_type);
1240 
1241   if (signal_name)
1242     {
1243       g_signal_connect_object (private->context, signal_name,
1244                                G_CALLBACK (gimp_container_view_context_changed),
1245                                view,
1246                                0);
1247 
1248       if (private->dnd_widget)
1249         gimp_dnd_viewable_dest_add (private->dnd_widget,
1250                                     children_type,
1251                                     gimp_container_view_viewable_dropped,
1252                                     view);
1253 
1254       if (! gimp_container_frozen (private->container))
1255         {
1256           GimpObject *object = gimp_context_get_by_type (private->context,
1257                                                          children_type);
1258 
1259           gimp_container_view_select_item (view, GIMP_VIEWABLE (object));
1260         }
1261     }
1262 }
1263 
1264 static void
gimp_container_view_disconnect_context(GimpContainerView * view)1265 gimp_container_view_disconnect_context (GimpContainerView *view)
1266 {
1267   GimpContainerViewPrivate *private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
1268   GType                     children_type;
1269   const gchar              *signal_name;
1270 
1271   children_type = gimp_container_get_children_type (private->container);
1272   signal_name   = gimp_context_type_to_signal_name (children_type);
1273 
1274   if (signal_name)
1275     {
1276       g_signal_handlers_disconnect_by_func (private->context,
1277                                             gimp_container_view_context_changed,
1278                                             view);
1279 
1280       if (private->dnd_widget)
1281         {
1282           gtk_drag_dest_unset (private->dnd_widget);
1283           gimp_dnd_viewable_dest_remove (private->dnd_widget,
1284                                          children_type);
1285         }
1286     }
1287 }
1288 
1289 static void
gimp_container_view_context_changed(GimpContext * context,GimpViewable * viewable,GimpContainerView * view)1290 gimp_container_view_context_changed (GimpContext       *context,
1291                                      GimpViewable      *viewable,
1292                                      GimpContainerView *view)
1293 {
1294   if (! gimp_container_view_select_item (view, viewable))
1295     g_warning ("%s: select_item() failed (should not happen)", G_STRFUNC);
1296 }
1297 
1298 static void
gimp_container_view_viewable_dropped(GtkWidget * widget,gint x,gint y,GimpViewable * viewable,gpointer data)1299 gimp_container_view_viewable_dropped (GtkWidget    *widget,
1300                                       gint          x,
1301                                       gint          y,
1302                                       GimpViewable *viewable,
1303                                       gpointer      data)
1304 {
1305   GimpContainerView        *view    = GIMP_CONTAINER_VIEW (data);
1306   GimpContainerViewPrivate *private = GIMP_CONTAINER_VIEW_GET_PRIVATE (view);
1307 
1308   if (viewable && private->container &&
1309       gimp_container_have (private->container, GIMP_OBJECT (viewable)))
1310     {
1311       gimp_container_view_item_selected (view, viewable);
1312     }
1313 }
1314 
1315 static void
gimp_container_view_button_viewable_dropped(GtkWidget * widget,gint x,gint y,GimpViewable * viewable,gpointer data)1316 gimp_container_view_button_viewable_dropped (GtkWidget    *widget,
1317                                              gint          x,
1318                                              gint          y,
1319                                              GimpViewable *viewable,
1320                                              gpointer      data)
1321 {
1322   GimpContainerView *view = GIMP_CONTAINER_VIEW (data);
1323 
1324   if (viewable && gimp_container_view_lookup (view, viewable))
1325     {
1326       gimp_container_view_item_selected (view, viewable);
1327 
1328       gtk_button_clicked (GTK_BUTTON (widget));
1329     }
1330 }
1331 
1332