]> Pileus Git - ~andy/gtk/blob - gtk/gtktoolpalette.c
Updated Norwegian nynorsk translation
[~andy/gtk] / gtk / gtktoolpalette.c
1 /* GtkToolPalette -- A tool palette with categories and DnD support
2  * Copyright (C) 2008  Openismus GmbH
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Authors:
18  *      Mathias Hasselmann
19  */
20
21 #include "config.h"
22
23 #include <string.h>
24 #include <gtk/gtk.h>
25
26 #include "gtktoolpaletteprivate.h"
27 #include "gtkmarshalers.h"
28 #include "gtktypebuiltins.h"
29 #include "gtkprivate.h"
30 #include "gtkscrollable.h"
31 #include "gtkorientableprivate.h"
32 #include "gtkintl.h"
33
34 #define DEFAULT_ICON_SIZE       GTK_ICON_SIZE_SMALL_TOOLBAR
35 #define DEFAULT_ORIENTATION     GTK_ORIENTATION_VERTICAL
36 #define DEFAULT_TOOLBAR_STYLE   GTK_TOOLBAR_ICONS
37
38 #define DEFAULT_CHILD_EXCLUSIVE FALSE
39 #define DEFAULT_CHILD_EXPAND    FALSE
40
41 /**
42  * SECTION:gtktoolpalette
43  * @Short_description: A tool palette with categories
44  * @Title: GtkToolPalette
45  *
46  * A #GtkToolPalette allows you to add #GtkToolItem<!-- -->s to a palette-like
47  * container with different categories and drag and drop support.
48  *
49  * A #GtkToolPalette is created with a call to gtk_tool_palette_new().
50  *
51  * #GtkToolItem<!-- -->s cannot be added directly to a #GtkToolPalette - 
52  * instead they are added to a #GtkToolItemGroup which can than be added
53  * to a #GtkToolPalette. To add a #GtkToolItemGroup to a #GtkToolPalette,
54  * use gtk_container_add().
55  *
56  * |[
57  * GtkWidget *palette, *group;
58  * GtkToolItem *item;
59  *
60  * palette = gtk_tool_palette_new ();
61  * group = gtk_tool_item_group_new (_("Test Category"));
62  * gtk_container_add (GTK_CONTAINER (palette), group);
63  *
64  * item = gtk_tool_button_new_from_stock (GTK_STOCK_OK);
65  * gtk_tool_item_group_insert (GTK_TOOL_ITEM_GROUP (group), item, -1);
66  * ]|
67  *
68  * The easiest way to use drag and drop with #GtkToolPalette is to call
69  * gtk_tool_palette_add_drag_dest() with the desired drag source @palette
70  * and the desired drag target @widget. Then gtk_tool_palette_get_drag_item()
71  * can be used to get the dragged item in the #GtkWidget::drag-data-received
72  * signal handler of the drag target.
73  *
74  * |[
75  * static void
76  * passive_canvas_drag_data_received (GtkWidget        *widget,
77  *                                    GdkDragContext   *context,
78  *                                    gint              x,
79  *                                    gint              y,
80  *                                    GtkSelectionData *selection,
81  *                                    guint             info,
82  *                                    guint             time,
83  *                                    gpointer          data)
84  * {
85  *   GtkWidget *palette;
86  *   GtkWidget *item;
87  *
88  *   /<!-- -->* Get the dragged item *<!-- -->/
89  *   palette = gtk_widget_get_ancestor (gtk_drag_get_source_widget (context),
90  *                                      GTK_TYPE_TOOL_PALETTE);
91  *   if (palette != NULL)
92  *     item = gtk_tool_palette_get_drag_item (GTK_TOOL_PALETTE (palette),
93  *                                            selection);
94  *
95  *   /<!-- -->* Do something with item *<!-- -->/
96  * }
97  *
98  * GtkWidget *target, palette;
99  *
100  * palette = gtk_tool_palette_new ();
101  * target = gtk_drawing_area_new ();
102  *
103  * g_signal_connect (G_OBJECT (target), "drag-data-received",
104  *                   G_CALLBACK (passive_canvas_drag_data_received), NULL);
105  * gtk_tool_palette_add_drag_dest (GTK_TOOL_PALETTE (palette), target,
106  *                                 GTK_DEST_DEFAULT_ALL,
107  *                                 GTK_TOOL_PALETTE_DRAG_ITEMS,
108  *                                 GDK_ACTION_COPY);
109  * ]|
110  *
111  * Since: 2.20
112  */
113
114 typedef struct _GtkToolItemGroupInfo   GtkToolItemGroupInfo;
115 typedef struct _GtkToolPaletteDragData GtkToolPaletteDragData;
116
117 enum
118 {
119   PROP_NONE,
120   PROP_ICON_SIZE,
121   PROP_ICON_SIZE_SET,
122   PROP_ORIENTATION,
123   PROP_TOOLBAR_STYLE,
124   PROP_HADJUSTMENT,
125   PROP_VADJUSTMENT,
126   PROP_HSCROLL_POLICY,
127   PROP_VSCROLL_POLICY
128 };
129
130 enum
131 {
132   CHILD_PROP_NONE,
133   CHILD_PROP_EXCLUSIVE,
134   CHILD_PROP_EXPAND,
135 };
136
137 struct _GtkToolItemGroupInfo
138 {
139   GtkToolItemGroup *widget;
140
141   gulong            notify_collapsed;
142   guint             pos;
143   guint             exclusive : 1;
144   guint             expand : 1;
145 };
146
147 struct _GtkToolPalettePrivate
148 {
149   GPtrArray* groups;
150
151   GtkAdjustment        *hadjustment;
152   GtkAdjustment        *vadjustment;
153
154   GtkIconSize           icon_size;
155   gboolean              icon_size_set;
156   GtkOrientation        orientation;
157   GtkToolbarStyle       style;
158   gboolean              style_set;
159
160   GtkWidget            *expanding_child;
161
162   GtkSizeGroup         *text_size_group;
163
164   GtkSettings          *settings;
165   gulong                settings_connection;
166
167   guint                 drag_source : 2;
168
169   /* GtkScrollablePolicy needs to be checked when
170    * driving the scrollable adjustment values */
171   guint hscroll_policy : 1;
172   guint vscroll_policy : 1;
173 };
174
175 struct _GtkToolPaletteDragData
176 {
177   GtkToolPalette *palette;
178   GtkWidget      *item;
179 };
180
181 static GdkAtom dnd_target_atom_item = GDK_NONE;
182 static GdkAtom dnd_target_atom_group = GDK_NONE;
183
184 static const GtkTargetEntry dnd_targets[] =
185 {
186   { "application/x-gtk-tool-palette-item", GTK_TARGET_SAME_APP, 0 },
187   { "application/x-gtk-tool-palette-group", GTK_TARGET_SAME_APP, 0 },
188 };
189
190 static void gtk_tool_palette_set_hadjustment (GtkToolPalette *palette,
191                                               GtkAdjustment  *adjustment);
192 static void gtk_tool_palette_set_vadjustment (GtkToolPalette *palette,
193                                               GtkAdjustment  *adjustment);
194
195
196 G_DEFINE_TYPE_WITH_CODE (GtkToolPalette,
197                gtk_tool_palette,
198                GTK_TYPE_CONTAINER,
199                G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL)
200                G_IMPLEMENT_INTERFACE (GTK_TYPE_SCROLLABLE, NULL))
201
202 static void
203 gtk_tool_palette_init (GtkToolPalette *palette)
204 {
205   palette->priv = G_TYPE_INSTANCE_GET_PRIVATE (palette,
206                                                GTK_TYPE_TOOL_PALETTE,
207                                                GtkToolPalettePrivate);
208
209   palette->priv->groups = g_ptr_array_sized_new (4);
210   g_ptr_array_set_free_func (palette->priv->groups, g_free);
211
212   palette->priv->icon_size = DEFAULT_ICON_SIZE;
213   palette->priv->icon_size_set = FALSE;
214   palette->priv->orientation = DEFAULT_ORIENTATION;
215   palette->priv->style = DEFAULT_TOOLBAR_STYLE;
216   palette->priv->style_set = FALSE;
217
218   palette->priv->text_size_group = gtk_size_group_new (GTK_SIZE_GROUP_BOTH);
219 }
220
221 static void
222 gtk_tool_palette_reconfigured (GtkToolPalette *palette)
223 {
224   guint i;
225
226   for (i = 0; i < palette->priv->groups->len; ++i)
227     {
228       GtkToolItemGroupInfo *info = g_ptr_array_index (palette->priv->groups, i);
229       if (info->widget)
230         _gtk_tool_item_group_palette_reconfigured (info->widget);
231     }
232
233   gtk_widget_queue_resize_no_redraw (GTK_WIDGET (palette));
234 }
235
236 static void
237 gtk_tool_palette_set_property (GObject      *object,
238                                guint         prop_id,
239                                const GValue *value,
240                                GParamSpec   *pspec)
241 {
242   GtkToolPalette *palette = GTK_TOOL_PALETTE (object);
243
244   switch (prop_id)
245     {
246       case PROP_ICON_SIZE:
247         if ((guint) g_value_get_enum (value) != palette->priv->icon_size)
248           {
249             palette->priv->icon_size = g_value_get_enum (value);
250             gtk_tool_palette_reconfigured (palette);
251           }
252         break;
253
254       case PROP_ICON_SIZE_SET:
255         if ((guint) g_value_get_enum (value) != palette->priv->icon_size)
256           {
257             palette->priv->icon_size_set = g_value_get_enum (value);
258             gtk_tool_palette_reconfigured (palette);
259           }
260         break;
261
262       case PROP_ORIENTATION:
263         if ((guint) g_value_get_enum (value) != palette->priv->orientation)
264           {
265             palette->priv->orientation = g_value_get_enum (value);
266             _gtk_orientable_set_style_classes (GTK_ORIENTABLE (palette));
267             gtk_tool_palette_reconfigured (palette);
268           }
269         break;
270
271       case PROP_TOOLBAR_STYLE:
272         if ((guint) g_value_get_enum (value) != palette->priv->style)
273           {
274             palette->priv->style = g_value_get_enum (value);
275             gtk_tool_palette_reconfigured (palette);
276           }
277         break;
278
279       case PROP_HADJUSTMENT:
280         gtk_tool_palette_set_hadjustment (palette, g_value_get_object (value));
281         break;
282
283       case PROP_VADJUSTMENT:
284         gtk_tool_palette_set_vadjustment (palette, g_value_get_object (value));
285         break;
286
287       case PROP_HSCROLL_POLICY:
288         palette->priv->hscroll_policy = g_value_get_enum (value);
289         gtk_widget_queue_resize (GTK_WIDGET (palette));
290         break;
291
292       case PROP_VSCROLL_POLICY:
293         palette->priv->vscroll_policy = g_value_get_enum (value);
294         gtk_widget_queue_resize (GTK_WIDGET (palette));
295         break;
296
297       default:
298         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
299         break;
300     }
301 }
302
303 static void
304 gtk_tool_palette_get_property (GObject    *object,
305                                guint       prop_id,
306                                GValue     *value,
307                                GParamSpec *pspec)
308 {
309   GtkToolPalette *palette = GTK_TOOL_PALETTE (object);
310
311   switch (prop_id)
312     {
313       case PROP_ICON_SIZE:
314         g_value_set_enum (value, gtk_tool_palette_get_icon_size (palette));
315         break;
316
317       case PROP_ICON_SIZE_SET:
318         g_value_set_boolean (value, palette->priv->icon_size_set);
319         break;
320
321       case PROP_ORIENTATION:
322         g_value_set_enum (value, palette->priv->orientation);
323         break;
324
325       case PROP_TOOLBAR_STYLE:
326         g_value_set_enum (value, gtk_tool_palette_get_style (palette));
327         break;
328
329       case PROP_HADJUSTMENT:
330         g_value_set_object (value, palette->priv->hadjustment);
331         break;
332
333       case PROP_VADJUSTMENT:
334         g_value_set_object (value, palette->priv->vadjustment);
335         break;
336
337       case PROP_HSCROLL_POLICY:
338         g_value_set_enum (value, palette->priv->hscroll_policy);
339         break;
340
341       case PROP_VSCROLL_POLICY:
342         g_value_set_enum (value, palette->priv->vscroll_policy);
343         break;
344
345       default:
346         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
347         break;
348     }
349 }
350
351 static void
352 gtk_tool_palette_dispose (GObject *object)
353 {
354   GtkToolPalette *palette = GTK_TOOL_PALETTE (object);
355   guint i;
356
357   if (palette->priv->hadjustment)
358     {
359       g_object_unref (palette->priv->hadjustment);
360       palette->priv->hadjustment = NULL;
361     }
362
363   if (palette->priv->vadjustment)
364     {
365       g_object_unref (palette->priv->vadjustment);
366       palette->priv->vadjustment = NULL;
367     }
368
369   for (i = 0; i < palette->priv->groups->len; ++i)
370     {
371       GtkToolItemGroupInfo *group = g_ptr_array_index (palette->priv->groups, i);
372
373       if (group->notify_collapsed)
374         {
375           g_signal_handler_disconnect (group->widget, group->notify_collapsed);
376           group->notify_collapsed = 0;
377         }
378     }
379
380   if (palette->priv->text_size_group)
381     {
382       g_object_unref (palette->priv->text_size_group);
383       palette->priv->text_size_group = NULL;
384     }
385
386   G_OBJECT_CLASS (gtk_tool_palette_parent_class)->dispose (object);
387 }
388
389 static void
390 gtk_tool_palette_finalize (GObject *object)
391 {
392   GtkToolPalette *palette = GTK_TOOL_PALETTE (object);
393
394   g_ptr_array_free (palette->priv->groups, TRUE);
395
396   G_OBJECT_CLASS (gtk_tool_palette_parent_class)->finalize (object);
397 }
398
399 static void
400 gtk_tool_palette_size_request (GtkWidget      *widget,
401                                GtkRequisition *requisition)
402 {
403   GtkToolPalette *palette = GTK_TOOL_PALETTE (widget);
404   GtkRequisition child_requisition;
405   guint border_width;
406   guint i;
407
408   border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
409
410   requisition->width = 0;
411   requisition->height = 0;
412
413   for (i = 0; i < palette->priv->groups->len; ++i)
414     {
415       GtkToolItemGroupInfo *group = g_ptr_array_index (palette->priv->groups, i);
416
417       if (!group->widget)
418         continue;
419
420       gtk_widget_get_preferred_size (GTK_WIDGET (group->widget),
421                                      &child_requisition, NULL);
422
423       if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
424         {
425           requisition->width = MAX (requisition->width, child_requisition.width);
426           requisition->height += child_requisition.height;
427         }
428       else
429         {
430           requisition->width += child_requisition.width;
431           requisition->height = MAX (requisition->height, child_requisition.height);
432         }
433     }
434
435   requisition->width += border_width * 2;
436   requisition->height += border_width * 2;
437 }
438
439 static void
440 gtk_tool_palette_get_preferred_width (GtkWidget *widget,
441                                       gint      *minimum,
442                                       gint      *natural)
443 {
444   GtkRequisition requisition;
445
446   gtk_tool_palette_size_request (widget, &requisition);
447
448   *minimum = *natural = requisition.width;
449 }
450
451 static void
452 gtk_tool_palette_get_preferred_height (GtkWidget *widget,
453                                        gint      *minimum,
454                                        gint      *natural)
455 {
456   GtkRequisition requisition;
457
458   gtk_tool_palette_size_request (widget, &requisition);
459
460   *minimum = *natural = requisition.height;
461 }
462
463
464 static void
465 gtk_tool_palette_size_allocate (GtkWidget     *widget,
466                                 GtkAllocation *allocation)
467 {
468   GtkToolPalette *palette = GTK_TOOL_PALETTE (widget);
469   GtkAdjustment *adjustment = NULL;
470   GtkAllocation child_allocation;
471
472   gint n_expand_groups = 0;
473   gint remaining_space = 0;
474   gint expand_space = 0;
475
476   gint total_size, page_size;
477   gint offset = 0;
478   guint i;
479   guint border_width;
480
481   gint min_offset = -1, max_offset = -1;
482
483   gint x;
484
485   gint *group_sizes = g_newa (gint, palette->priv->groups->len);
486   GtkTextDirection direction;
487
488   border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
489   direction = gtk_widget_get_direction (widget);
490
491   GTK_WIDGET_CLASS (gtk_tool_palette_parent_class)->size_allocate (widget, allocation);
492
493   if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
494     {
495       adjustment = palette->priv->vadjustment;
496       page_size = allocation->height;
497     }
498   else
499     {
500       adjustment = palette->priv->hadjustment;
501       page_size = allocation->width;
502     }
503
504   if (adjustment)
505     offset = gtk_adjustment_get_value (adjustment);
506   if (GTK_ORIENTATION_HORIZONTAL == palette->priv->orientation &&
507       GTK_TEXT_DIR_RTL == direction)
508     offset = -offset;
509
510   if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
511     child_allocation.width = allocation->width - border_width * 2;
512   else
513     child_allocation.height = allocation->height - border_width * 2;
514
515   if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
516     remaining_space = allocation->height;
517   else
518     remaining_space = allocation->width;
519
520   /* figure out the required size of all groups to be able to distribute the
521    * remaining space on allocation
522    */
523   for (i = 0; i < palette->priv->groups->len; ++i)
524     {
525       GtkToolItemGroupInfo *group = g_ptr_array_index (palette->priv->groups, i);
526       gint size;
527
528       group_sizes[i] = 0;
529
530       if (!group->widget)
531         continue;
532
533       widget = GTK_WIDGET (group->widget);
534
535       if (gtk_tool_item_group_get_n_items (group->widget))
536         {
537           if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
538             size = _gtk_tool_item_group_get_height_for_width (group->widget, child_allocation.width);
539           else
540             size = _gtk_tool_item_group_get_width_for_height (group->widget, child_allocation.height);
541
542           if (group->expand && !gtk_tool_item_group_get_collapsed (group->widget))
543             n_expand_groups += 1;
544         }
545       else
546         size = 0;
547
548       remaining_space -= size;
549       group_sizes[i] = size;
550
551       /* if the widget is currently expanding an offset which allows to
552        * display as much of the widget as possible is calculated
553        */
554       if (widget == palette->priv->expanding_child)
555         {
556           gint limit =
557             GTK_ORIENTATION_VERTICAL == palette->priv->orientation ?
558             child_allocation.width : child_allocation.height;
559
560           gint real_size;
561           guint j;
562
563           min_offset = 0;
564
565           for (j = 0; j < i; ++j)
566             min_offset += group_sizes[j];
567
568           max_offset = min_offset + group_sizes[i];
569
570           real_size = _gtk_tool_item_group_get_size_for_limit
571             (GTK_TOOL_ITEM_GROUP (widget), limit,
572              GTK_ORIENTATION_VERTICAL == palette->priv->orientation,
573              FALSE);
574
575           if (size == real_size)
576             palette->priv->expanding_child = NULL;
577         }
578     }
579
580   if (n_expand_groups > 0)
581     {
582       remaining_space = MAX (0, remaining_space);
583       expand_space = remaining_space / n_expand_groups;
584     }
585
586   if (max_offset != -1)
587     {
588       gint limit =
589         GTK_ORIENTATION_VERTICAL == palette->priv->orientation ?
590         allocation->height : allocation->width;
591
592       offset = MIN (MAX (offset, max_offset - limit), min_offset);
593     }
594
595   if (remaining_space > 0)
596     offset = 0;
597
598   x = border_width;
599   child_allocation.y = border_width;
600
601   if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
602     child_allocation.y -= offset;
603   else
604     x -= offset;
605
606   /* allocate all groups at the calculated positions */
607   for (i = 0; i < palette->priv->groups->len; ++i)
608     {
609       GtkToolItemGroupInfo *group = g_ptr_array_index (palette->priv->groups, i);
610       GtkWidget *widget;
611
612       if (!group->widget)
613         continue;
614
615       widget = GTK_WIDGET (group->widget);
616
617       if (gtk_tool_item_group_get_n_items (group->widget))
618         {
619           gint size = group_sizes[i];
620
621           if (group->expand && !gtk_tool_item_group_get_collapsed (group->widget))
622             {
623               size += MIN (expand_space, remaining_space);
624               remaining_space -= expand_space;
625             }
626
627           if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
628             child_allocation.height = size;
629           else
630             child_allocation.width = size;
631
632           if (GTK_ORIENTATION_HORIZONTAL == palette->priv->orientation &&
633               GTK_TEXT_DIR_RTL == direction)
634             child_allocation.x = allocation->width - x - child_allocation.width;
635           else
636             child_allocation.x = x;
637
638           gtk_widget_size_allocate (widget, &child_allocation);
639           gtk_widget_show (widget);
640
641           if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
642             child_allocation.y += child_allocation.height;
643           else
644             x += child_allocation.width;
645         }
646       else
647         gtk_widget_hide (widget);
648     }
649
650   if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation)
651     {
652       child_allocation.y += border_width;
653       child_allocation.y += offset;
654
655       total_size = child_allocation.y;
656     }
657   else
658     {
659       x += border_width;
660       x += offset;
661
662       total_size = x;
663     }
664
665   /* update the scrollbar to match the displayed adjustment */
666   if (adjustment)
667     {
668       gdouble lower, upper;
669
670       total_size = MAX (0, total_size);
671       page_size = MIN (total_size, page_size);
672
673       if (GTK_ORIENTATION_VERTICAL == palette->priv->orientation ||
674           GTK_TEXT_DIR_LTR == direction)
675         {
676           lower = 0;
677           upper = total_size;
678         }
679       else
680         {
681           lower = page_size - total_size;
682           upper = page_size;
683
684           offset = -offset;
685         }
686
687       gtk_adjustment_configure (adjustment,
688                                 offset,
689                                 lower,
690                                 upper,
691                                 page_size * 0.1,
692                                 page_size * 0.9,
693                                 page_size);
694     }
695 }
696
697 static void
698 gtk_tool_palette_realize (GtkWidget *widget)
699 {
700   GtkAllocation allocation;
701   GdkWindow *window;
702   GdkWindowAttr attributes;
703   gint attributes_mask;
704   guint border_width;
705
706   gtk_widget_set_realized (widget, TRUE);
707
708   border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
709
710   gtk_widget_get_allocation (widget, &allocation);
711
712   attributes.window_type = GDK_WINDOW_CHILD;
713   attributes.x = allocation.x + border_width;
714   attributes.y = allocation.y + border_width;
715   attributes.width = allocation.width - border_width * 2;
716   attributes.height = allocation.height - border_width * 2;
717   attributes.wclass = GDK_INPUT_OUTPUT;
718   attributes.visual = gtk_widget_get_visual (widget);
719   attributes.event_mask = gtk_widget_get_events (widget)
720                          | GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK
721                          | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
722                          | GDK_BUTTON_MOTION_MASK;
723   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
724
725   window = gdk_window_new (gtk_widget_get_parent_window (widget),
726                            &attributes, attributes_mask);
727   gtk_widget_set_window (widget, window);
728   gdk_window_set_user_data (window, widget);
729
730   gtk_style_context_set_background (gtk_widget_get_style_context (widget),
731                                     window);
732
733   gtk_container_forall (GTK_CONTAINER (widget),
734                         (GtkCallback) gtk_widget_set_parent_window,
735                         window);
736
737   gtk_widget_queue_resize_no_redraw (widget);
738 }
739
740 static void
741 gtk_tool_palette_adjustment_value_changed (GtkAdjustment *adjustment,
742                                            gpointer       data)
743 {
744   GtkAllocation allocation;
745   GtkWidget *widget = GTK_WIDGET (data);
746
747   gtk_widget_get_allocation (widget, &allocation);
748   gtk_tool_palette_size_allocate (widget, &allocation);
749 }
750
751 static void
752 gtk_tool_palette_add (GtkContainer *container,
753                       GtkWidget    *child)
754 {
755   GtkToolPalette *palette;
756   GtkToolItemGroupInfo *info = g_new0(GtkToolItemGroupInfo, 1);
757
758   g_return_if_fail (GTK_IS_TOOL_PALETTE (container));
759   g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (child));
760
761   palette = GTK_TOOL_PALETTE (container);
762
763   g_ptr_array_add (palette->priv->groups, info);
764   info->pos = palette->priv->groups->len - 1;
765   info->widget = g_object_ref_sink (child);
766
767   gtk_widget_set_parent (child, GTK_WIDGET (palette));
768 }
769
770 static void
771 gtk_tool_palette_remove (GtkContainer *container,
772                          GtkWidget    *child)
773 {
774   GtkToolPalette *palette;
775   guint i;
776
777   g_return_if_fail (GTK_IS_TOOL_PALETTE (container));
778   palette = GTK_TOOL_PALETTE (container);
779
780   for (i = 0; i < palette->priv->groups->len; ++i)
781     {
782       GtkToolItemGroupInfo *info = g_ptr_array_index (palette->priv->groups, i);
783       if (GTK_WIDGET(info->widget) == child)
784         {
785           g_object_unref (child);
786           gtk_widget_unparent (child);
787
788           g_ptr_array_remove_index (palette->priv->groups, i);
789         }
790     }
791 }
792
793 static void
794 gtk_tool_palette_forall (GtkContainer *container,
795                          gboolean      internals,
796                          GtkCallback   callback,
797                          gpointer      callback_data)
798 {
799   GtkToolPalette *palette = GTK_TOOL_PALETTE (container);
800   guint i, len;
801
802   for (i = 0; i < palette->priv->groups->len; ++i)
803     {
804       GtkToolItemGroupInfo *info = g_ptr_array_index (palette->priv->groups, i);
805
806       len = palette->priv->groups->len;
807
808       if (info->widget)
809         callback (GTK_WIDGET (info->widget),
810                   callback_data);
811
812       /* At destroy time, 'callback' results in removing a widget,
813        * here we just reset the current index to account for the removed widget. */
814       i -= (len - palette->priv->groups->len);
815     }
816 }
817
818 static GType
819 gtk_tool_palette_child_type (GtkContainer *container)
820 {
821   return GTK_TYPE_TOOL_ITEM_GROUP;
822 }
823
824 static void
825 gtk_tool_palette_set_child_property (GtkContainer *container,
826                                      GtkWidget    *child,
827                                      guint         prop_id,
828                                      const GValue *value,
829                                      GParamSpec   *pspec)
830 {
831   GtkToolPalette *palette = GTK_TOOL_PALETTE (container);
832
833   switch (prop_id)
834     {
835       case CHILD_PROP_EXCLUSIVE:
836         gtk_tool_palette_set_exclusive (palette, GTK_TOOL_ITEM_GROUP (child), 
837           g_value_get_boolean (value));
838         break;
839
840       case CHILD_PROP_EXPAND:
841         gtk_tool_palette_set_expand (palette, GTK_TOOL_ITEM_GROUP (child), 
842           g_value_get_boolean (value));
843         break;
844
845       default:
846         GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, prop_id, pspec);
847         break;
848     }
849 }
850
851 static void
852 gtk_tool_palette_get_child_property (GtkContainer *container,
853                                      GtkWidget    *child,
854                                      guint         prop_id,
855                                      GValue       *value,
856                                      GParamSpec   *pspec)
857 {
858   GtkToolPalette *palette = GTK_TOOL_PALETTE (container);
859
860   switch (prop_id)
861     {
862       case CHILD_PROP_EXCLUSIVE:
863         g_value_set_boolean (value, 
864           gtk_tool_palette_get_exclusive (palette, GTK_TOOL_ITEM_GROUP (child)));
865         break;
866
867       case CHILD_PROP_EXPAND:
868         g_value_set_boolean (value, 
869           gtk_tool_palette_get_expand (palette, GTK_TOOL_ITEM_GROUP (child)));
870         break;
871
872       default:
873         GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, prop_id, pspec);
874         break;
875     }
876 }
877
878 static void
879 style_change_notify (GtkToolPalette *palette)
880 {
881   GtkToolPalettePrivate* priv = palette->priv;
882
883   if (!priv->style_set)
884     {
885       /* pretend it was set, then unset, thus reverting to new default */
886       priv->style_set = TRUE;
887       gtk_tool_palette_unset_style (palette);
888     }
889 }
890
891 static void
892 icon_size_change_notify (GtkToolPalette *palette)
893 {
894   GtkToolPalettePrivate* priv = palette->priv;
895
896   if (!priv->icon_size_set)
897     {
898       /* pretend it was set, then unset, thus reverting to new default */
899       priv->icon_size_set = TRUE;
900       gtk_tool_palette_unset_icon_size (palette);
901     }
902 }
903
904 static void
905 gtk_tool_palette_settings_change_notify (GtkSettings      *settings,
906                                          const GParamSpec *pspec,
907                                          GtkToolPalette   *palette)
908 {
909   if (strcmp (pspec->name, "gtk-toolbar-style") == 0)
910     style_change_notify (palette);
911   else if (strcmp (pspec->name, "gtk-toolbar-icon-size") == 0)
912     icon_size_change_notify (palette);
913 }
914
915 static void
916 gtk_tool_palette_screen_changed (GtkWidget *widget,
917                                  GdkScreen *previous_screen)
918 {
919   GtkToolPalette *palette = GTK_TOOL_PALETTE (widget);
920   GtkToolPalettePrivate* priv = palette->priv;
921   GtkSettings *old_settings = priv->settings;
922   GtkSettings *settings;
923
924   if (gtk_widget_has_screen (GTK_WIDGET (palette)))
925     settings = gtk_widget_get_settings (GTK_WIDGET (palette));
926   else
927     settings = NULL;
928
929   if (settings == old_settings)
930     return;
931
932   if (old_settings)
933   {
934     g_signal_handler_disconnect (old_settings, priv->settings_connection);
935     g_object_unref (old_settings);
936   }
937
938   if (settings)
939   {
940     priv->settings_connection =
941       g_signal_connect (settings, "notify",
942                         G_CALLBACK (gtk_tool_palette_settings_change_notify),
943                         palette);
944     priv->settings = g_object_ref (settings);
945   }
946   else
947     priv->settings = NULL;
948
949   gtk_tool_palette_reconfigured (palette);
950 }
951
952
953 static void
954 gtk_tool_palette_class_init (GtkToolPaletteClass *cls)
955 {
956   GObjectClass      *oclass   = G_OBJECT_CLASS (cls);
957   GtkWidgetClass    *wclass   = GTK_WIDGET_CLASS (cls);
958   GtkContainerClass *cclass   = GTK_CONTAINER_CLASS (cls);
959
960   oclass->set_property        = gtk_tool_palette_set_property;
961   oclass->get_property        = gtk_tool_palette_get_property;
962   oclass->dispose             = gtk_tool_palette_dispose;
963   oclass->finalize            = gtk_tool_palette_finalize;
964
965   wclass->get_preferred_width = gtk_tool_palette_get_preferred_width;
966   wclass->get_preferred_height= gtk_tool_palette_get_preferred_height;
967   wclass->size_allocate       = gtk_tool_palette_size_allocate;
968   wclass->realize             = gtk_tool_palette_realize;
969
970   cclass->add                 = gtk_tool_palette_add;
971   cclass->remove              = gtk_tool_palette_remove;
972   cclass->forall              = gtk_tool_palette_forall;
973   cclass->child_type          = gtk_tool_palette_child_type;
974   cclass->set_child_property  = gtk_tool_palette_set_child_property;
975   cclass->get_child_property  = gtk_tool_palette_get_child_property;
976
977   /* Handle screen-changed so we can update our GtkSettings.
978    */
979   wclass->screen_changed      = gtk_tool_palette_screen_changed;
980
981   g_object_class_override_property (oclass, PROP_ORIENTATION,    "orientation");
982
983   g_object_class_override_property (oclass, PROP_HADJUSTMENT,    "hadjustment");
984   g_object_class_override_property (oclass, PROP_VADJUSTMENT,    "vadjustment");
985   g_object_class_override_property (oclass, PROP_HSCROLL_POLICY, "hscroll-policy");
986   g_object_class_override_property (oclass, PROP_VSCROLL_POLICY, "vscroll-policy");
987
988   /**
989    * GtkToolPalette:icon-size:
990    *
991    * The size of the icons in a tool palette is normally determined by
992    * the #GtkSettings:gtk-toolbar-icon-size setting. When this property is set,
993    * it overrides the setting.
994    *
995    * This should only be used for special-purpose tool palettes, normal
996    * application tool palettes should respect the user preferences for the
997    * size of icons.
998    *
999    * Since: 2.20
1000    */
1001   g_object_class_install_property (oclass,
1002                                    PROP_ICON_SIZE,
1003                                    g_param_spec_enum ("icon-size",
1004                                                       P_("Icon size"),
1005                                                       P_("Size of icons in this tool palette"),
1006                                                       GTK_TYPE_ICON_SIZE,
1007                                                       DEFAULT_ICON_SIZE,
1008                                                       GTK_PARAM_READWRITE));
1009
1010   /**
1011    * GtkToolPalette:icon-size-set:
1012    *
1013    * Is %TRUE if the #GtkToolPalette:icon-size property has been set.
1014    *
1015    * Since: 2.20
1016    */
1017   g_object_class_install_property (oclass,
1018                                    PROP_ICON_SIZE_SET,
1019                                    g_param_spec_boolean ("icon-size-set",
1020                                                       P_("Icon size set"),
1021                                                       P_("Whether the icon-size property has been set"),
1022                                                       FALSE,
1023                                                       GTK_PARAM_READWRITE));
1024
1025   /**
1026    * GtkToolPalette:toolbar-style:
1027    *
1028    * The style of items in the tool palette.
1029    *
1030    * Since: 2.20
1031    */
1032   g_object_class_install_property (oclass, PROP_TOOLBAR_STYLE,
1033                                    g_param_spec_enum ("toolbar-style",
1034                                                       P_("Toolbar Style"),
1035                                                       P_("Style of items in the tool palette"),
1036                                                       GTK_TYPE_TOOLBAR_STYLE,
1037                                                       DEFAULT_TOOLBAR_STYLE,
1038                                                       GTK_PARAM_READWRITE));
1039
1040
1041   /**
1042    * GtkToolPalette:exclusive:
1043    *
1044    * Whether the item group should be the only one that is expanded
1045    * at a given time.
1046    *
1047    * Since: 2.20
1048    */
1049   gtk_container_class_install_child_property (cclass, CHILD_PROP_EXCLUSIVE,
1050                                               g_param_spec_boolean ("exclusive",
1051                                                                     P_("Exclusive"),
1052                                                                     P_("Whether the item group should be the only expanded at a given time"),
1053                                                                     DEFAULT_CHILD_EXCLUSIVE,
1054                                                                     GTK_PARAM_READWRITE));
1055
1056   /**
1057    * GtkToolPalette:expand:
1058    *
1059    * Whether the item group should receive extra space when the palette grows.
1060    * at a given time.
1061    *
1062    * Since: 2.20
1063    */
1064   gtk_container_class_install_child_property (cclass, CHILD_PROP_EXPAND,
1065                                               g_param_spec_boolean ("expand",
1066                                                                     P_("Expand"),
1067                                                                     P_("Whether the item group should receive extra space when the palette grows"),
1068                                                                     DEFAULT_CHILD_EXPAND,
1069                                                                     GTK_PARAM_READWRITE));
1070
1071   g_type_class_add_private (cls, sizeof (GtkToolPalettePrivate));
1072
1073   dnd_target_atom_item = gdk_atom_intern_static_string (dnd_targets[0].target);
1074   dnd_target_atom_group = gdk_atom_intern_static_string (dnd_targets[1].target);
1075 }
1076
1077 /**
1078  * gtk_tool_palette_new:
1079  *
1080  * Creates a new tool palette.
1081  *
1082  * Returns: a new #GtkToolPalette
1083  *
1084  * Since: 2.20
1085  */
1086 GtkWidget*
1087 gtk_tool_palette_new (void)
1088 {
1089   return g_object_new (GTK_TYPE_TOOL_PALETTE, NULL);
1090 }
1091
1092 /**
1093  * gtk_tool_palette_set_icon_size:
1094  * @palette: a #GtkToolPalette
1095  * @icon_size: (type int): the #GtkIconSize that icons in the tool
1096  *     palette shall have
1097  *
1098  * Sets the size of icons in the tool palette.
1099  *
1100  * Since: 2.20
1101  */
1102 void
1103 gtk_tool_palette_set_icon_size (GtkToolPalette *palette,
1104                                 GtkIconSize     icon_size)
1105 {
1106   GtkToolPalettePrivate *priv;
1107
1108   g_return_if_fail (GTK_IS_TOOL_PALETTE (palette));
1109   g_return_if_fail (icon_size != GTK_ICON_SIZE_INVALID);
1110
1111   priv = palette->priv;
1112
1113   if (!priv->icon_size_set)
1114     {
1115       priv->icon_size_set = TRUE;
1116       g_object_notify (G_OBJECT (palette), "icon-size-set");
1117     }
1118
1119   if (priv->icon_size == icon_size)
1120     return;
1121
1122   priv->icon_size = icon_size;
1123   g_object_notify (G_OBJECT (palette), "icon-size");
1124
1125   gtk_tool_palette_reconfigured (palette);
1126
1127   gtk_widget_queue_resize (GTK_WIDGET (palette));
1128 }
1129
1130 static GtkSettings *
1131 toolpalette_get_settings (GtkToolPalette *palette)
1132 {
1133   GtkToolPalettePrivate *priv = palette->priv;
1134   return priv->settings;
1135 }
1136
1137 /**
1138  * gtk_tool_palette_unset_icon_size:
1139  * @palette: a #GtkToolPalette
1140  *
1141  * Unsets the tool palette icon size set with gtk_tool_palette_set_icon_size(),
1142  * so that user preferences will be used to determine the icon size.
1143  *
1144  * Since: 2.20
1145  */
1146 void
1147 gtk_tool_palette_unset_icon_size (GtkToolPalette *palette)
1148 {
1149   GtkToolPalettePrivate* priv = palette->priv;
1150   GtkIconSize size;
1151
1152   g_return_if_fail (GTK_IS_TOOL_PALETTE (palette));
1153
1154   if (palette->priv->icon_size_set)
1155     {
1156       GtkSettings *settings = toolpalette_get_settings (palette);
1157
1158       if (settings)
1159         {
1160           g_object_get (settings,
1161             "gtk-toolbar-icon-size", &size,
1162             NULL);
1163         }
1164       else
1165         size = DEFAULT_ICON_SIZE;
1166
1167       if (size != palette->priv->icon_size)
1168       {
1169         gtk_tool_palette_set_icon_size (palette, size);
1170         g_object_notify (G_OBJECT (palette), "icon-size");
1171             }
1172
1173       priv->icon_size_set = FALSE;
1174       g_object_notify (G_OBJECT (palette), "icon-size-set");
1175     }
1176 }
1177
1178 /* Set the "toolbar-style" property and do appropriate things.
1179  * GtkToolbar does this by emitting a signal instead of just
1180  * calling a function...
1181  */
1182 static void
1183 gtk_tool_palette_change_style (GtkToolPalette  *palette,
1184                                GtkToolbarStyle  style)
1185 {
1186   GtkToolPalettePrivate* priv = palette->priv;
1187
1188   if (priv->style != style)
1189     {
1190       priv->style = style;
1191
1192       gtk_tool_palette_reconfigured (palette);
1193
1194       gtk_widget_queue_resize (GTK_WIDGET (palette));
1195       g_object_notify (G_OBJECT (palette), "toolbar-style");
1196     }
1197 }
1198
1199
1200 /**
1201  * gtk_tool_palette_set_style:
1202  * @palette: a #GtkToolPalette
1203  * @style: the #GtkToolbarStyle that items in the tool palette shall have
1204  *
1205  * Sets the style (text, icons or both) of items in the tool palette.
1206  *
1207  * Since: 2.20
1208  */
1209 void
1210 gtk_tool_palette_set_style (GtkToolPalette  *palette,
1211                             GtkToolbarStyle  style)
1212 {
1213   g_return_if_fail (GTK_IS_TOOL_PALETTE (palette));
1214
1215   palette->priv->style_set = TRUE;
1216   gtk_tool_palette_change_style (palette, style);
1217 }
1218
1219
1220 /**
1221  * gtk_tool_palette_unset_style:
1222  * @palette: a #GtkToolPalette
1223  *
1224  * Unsets a toolbar style set with gtk_tool_palette_set_style(),
1225  * so that user preferences will be used to determine the toolbar style.
1226  *
1227  * Since: 2.20
1228  */
1229 void
1230 gtk_tool_palette_unset_style (GtkToolPalette *palette)
1231 {
1232   GtkToolPalettePrivate* priv = palette->priv;
1233   GtkToolbarStyle style;
1234
1235   g_return_if_fail (GTK_IS_TOOL_PALETTE (palette));
1236
1237   if (priv->style_set)
1238     {
1239       GtkSettings *settings = toolpalette_get_settings (palette);
1240
1241       if (settings)
1242         g_object_get (settings,
1243                       "gtk-toolbar-style", &style,
1244                       NULL);
1245       else
1246         style = DEFAULT_TOOLBAR_STYLE;
1247
1248       if (style != priv->style)
1249         gtk_tool_palette_change_style (palette, style);
1250
1251       priv->style_set = FALSE;
1252     }
1253 }
1254
1255 /**
1256  * gtk_tool_palette_get_icon_size:
1257  * @palette: a #GtkToolPalette
1258  *
1259  * Gets the size of icons in the tool palette.
1260  * See gtk_tool_palette_set_icon_size().
1261  *
1262  * Returns: (type int): the #GtkIconSize of icons in the tool palette
1263  *
1264  * Since: 2.20
1265  */
1266 GtkIconSize
1267 gtk_tool_palette_get_icon_size (GtkToolPalette *palette)
1268 {
1269   g_return_val_if_fail (GTK_IS_TOOL_PALETTE (palette), DEFAULT_ICON_SIZE);
1270
1271   return palette->priv->icon_size;
1272 }
1273
1274 /**
1275  * gtk_tool_palette_get_style:
1276  * @palette: a #GtkToolPalette
1277  *
1278  * Gets the style (icons, text or both) of items in the tool palette.
1279  *
1280  * Returns: the #GtkToolbarStyle of items in the tool palette.
1281  *
1282  * Since: 2.20
1283  */
1284 GtkToolbarStyle
1285 gtk_tool_palette_get_style (GtkToolPalette *palette)
1286 {
1287   g_return_val_if_fail (GTK_IS_TOOL_PALETTE (palette), DEFAULT_TOOLBAR_STYLE);
1288
1289   return palette->priv->style;
1290 }
1291
1292 gint
1293 _gtk_tool_palette_compare_groups (gconstpointer a,
1294                                   gconstpointer b)
1295 {
1296   const GtkToolItemGroupInfo *group_a = a;
1297   const GtkToolItemGroupInfo *group_b = b;
1298
1299   return group_a->pos - group_b->pos;
1300 }
1301
1302 /**
1303  * gtk_tool_palette_set_group_position:
1304  * @palette: a #GtkToolPalette
1305  * @group: a #GtkToolItemGroup which is a child of palette
1306  * @position: a new index for group
1307  *
1308  * Sets the position of the group as an index of the tool palette.
1309  * If position is 0 the group will become the first child, if position is
1310  * -1 it will become the last child.
1311  *
1312  * Since: 2.20
1313  */
1314 void
1315 gtk_tool_palette_set_group_position (GtkToolPalette   *palette,
1316                                      GtkToolItemGroup *group,
1317                                      gint             position)
1318 {
1319   GtkToolItemGroupInfo *group_new;
1320   GtkToolItemGroupInfo *group_old;
1321   gint old_position;
1322
1323   g_return_if_fail (GTK_IS_TOOL_PALETTE (palette));
1324   g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (group));
1325   g_return_if_fail (position >= -1);
1326
1327   if (-1 == position)
1328     position = palette->priv->groups->len - 1;
1329
1330   g_return_if_fail ((guint) position < palette->priv->groups->len);
1331
1332   group_new = g_ptr_array_index (palette->priv->groups, position);
1333
1334   if (GTK_TOOL_ITEM_GROUP (group) == group_new->widget)
1335     return;
1336
1337   old_position = gtk_tool_palette_get_group_position (palette, group);
1338   g_return_if_fail (old_position >= 0);
1339
1340   group_old = g_ptr_array_index (palette->priv->groups, old_position);
1341
1342   group_new->pos = position;
1343   group_old->pos = old_position;
1344
1345   g_ptr_array_sort (palette->priv->groups, _gtk_tool_palette_compare_groups);
1346
1347   gtk_widget_queue_resize (GTK_WIDGET (palette));
1348 }
1349
1350 static void
1351 gtk_tool_palette_group_notify_collapsed (GtkToolItemGroup *group,
1352                                          GParamSpec       *pspec,
1353                                          gpointer          data)
1354 {
1355   GtkToolPalette *palette = GTK_TOOL_PALETTE (data);
1356   guint i;
1357
1358   if (gtk_tool_item_group_get_collapsed (group))
1359     return;
1360
1361   for (i = 0; i < palette->priv->groups->len; ++i)
1362     {
1363       GtkToolItemGroupInfo *info = g_ptr_array_index (palette->priv->groups, i);
1364       GtkToolItemGroup *current_group = info->widget;
1365
1366       if (current_group && current_group != group)
1367         gtk_tool_item_group_set_collapsed (current_group, TRUE);
1368     }
1369 }
1370
1371 /**
1372  * gtk_tool_palette_set_exclusive:
1373  * @palette: a #GtkToolPalette
1374  * @group: a #GtkToolItemGroup which is a child of palette
1375  * @exclusive: whether the group should be exclusive or not
1376  *
1377  * Sets whether the group should be exclusive or not.
1378  * If an exclusive group is expanded all other groups are collapsed.
1379  *
1380  * Since: 2.20
1381  */
1382 void
1383 gtk_tool_palette_set_exclusive (GtkToolPalette   *palette,
1384                                 GtkToolItemGroup *group,
1385                                 gboolean          exclusive)
1386 {
1387   GtkToolItemGroupInfo *group_info;
1388   gint position;
1389
1390   g_return_if_fail (GTK_IS_TOOL_PALETTE (palette));
1391   g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (group));
1392
1393   position = gtk_tool_palette_get_group_position (palette, group);
1394   g_return_if_fail (position >= 0);
1395
1396   group_info = g_ptr_array_index (palette->priv->groups, position);
1397
1398   if (exclusive == group_info->exclusive)
1399     return;
1400
1401   group_info->exclusive = exclusive;
1402
1403   if (group_info->exclusive != (0 != group_info->notify_collapsed))
1404     {
1405       if (group_info->exclusive)
1406         {
1407           group_info->notify_collapsed =
1408             g_signal_connect (group, "notify::collapsed",
1409                               G_CALLBACK (gtk_tool_palette_group_notify_collapsed),
1410                               palette);
1411         }
1412       else
1413         {
1414           g_signal_handler_disconnect (group, group_info->notify_collapsed);
1415           group_info->notify_collapsed = 0;
1416         }
1417     }
1418
1419   gtk_tool_palette_group_notify_collapsed (group_info->widget, NULL, palette);
1420   gtk_widget_child_notify (GTK_WIDGET (group), "exclusive");
1421 }
1422
1423 /**
1424  * gtk_tool_palette_set_expand:
1425  * @palette: a #GtkToolPalette
1426  * @group: a #GtkToolItemGroup which is a child of palette
1427  * @expand: whether the group should be given extra space
1428  *
1429  * Sets whether the group should be given extra space.
1430  *
1431  * Since: 2.20
1432  */
1433 void
1434 gtk_tool_palette_set_expand (GtkToolPalette   *palette,
1435                              GtkToolItemGroup *group,
1436                              gboolean        expand)
1437 {
1438   GtkToolItemGroupInfo *group_info;
1439   gint position;
1440
1441   g_return_if_fail (GTK_IS_TOOL_PALETTE (palette));
1442   g_return_if_fail (GTK_IS_TOOL_ITEM_GROUP (group));
1443
1444   position = gtk_tool_palette_get_group_position (palette, group);
1445   g_return_if_fail (position >= 0);
1446
1447   group_info = g_ptr_array_index (palette->priv->groups, position);
1448
1449   if (expand != group_info->expand)
1450     {
1451       group_info->expand = expand;
1452       gtk_widget_queue_resize (GTK_WIDGET (palette));
1453       gtk_widget_child_notify (GTK_WIDGET (group), "expand");
1454     }
1455 }
1456
1457 /**
1458  * gtk_tool_palette_get_group_position:
1459  * @palette: a #GtkToolPalette
1460  * @group: a #GtkToolItemGroup
1461  *
1462  * Gets the position of @group in @palette as index.
1463  * See gtk_tool_palette_set_group_position().
1464  *
1465  * Returns: the index of group or -1 if @group is not a child of @palette
1466  *
1467  * Since: 2.20
1468  */
1469 gint
1470 gtk_tool_palette_get_group_position (GtkToolPalette   *palette,
1471                                      GtkToolItemGroup *group)
1472 {
1473   guint i;
1474
1475   g_return_val_if_fail (GTK_IS_TOOL_PALETTE (palette), -1);
1476   g_return_val_if_fail (GTK_IS_TOOL_ITEM_GROUP (group), -1);
1477
1478   for (i = 0; i < palette->priv->groups->len; ++i)
1479     {
1480       GtkToolItemGroupInfo *info = g_ptr_array_index (palette->priv->groups, i);
1481       if ((gpointer) group == info->widget)
1482         return i;
1483     }
1484
1485   return -1;
1486 }
1487
1488 /**
1489  * gtk_tool_palette_get_exclusive:
1490  * @palette: a #GtkToolPalette
1491  * @group: a #GtkToolItemGroup which is a child of palette
1492  *
1493  * Gets whether @group is exclusive or not.
1494  * See gtk_tool_palette_set_exclusive().
1495  *
1496  * Returns: %TRUE if @group is exclusive
1497  *
1498  * Since: 2.20
1499  */
1500 gboolean
1501 gtk_tool_palette_get_exclusive (GtkToolPalette   *palette,
1502                                 GtkToolItemGroup *group)
1503 {
1504   gint position;
1505   GtkToolItemGroupInfo *info;
1506
1507   g_return_val_if_fail (GTK_IS_TOOL_PALETTE (palette), DEFAULT_CHILD_EXCLUSIVE);
1508   g_return_val_if_fail (GTK_IS_TOOL_ITEM_GROUP (group), DEFAULT_CHILD_EXCLUSIVE);
1509
1510   position = gtk_tool_palette_get_group_position (palette, group);
1511   g_return_val_if_fail (position >= 0, DEFAULT_CHILD_EXCLUSIVE);
1512
1513   info = g_ptr_array_index (palette->priv->groups, position);
1514
1515   return info->exclusive;
1516 }
1517
1518 /**
1519  * gtk_tool_palette_get_expand:
1520  * @palette: a #GtkToolPalette
1521  * @group: a #GtkToolItemGroup which is a child of palette
1522  *
1523  * Gets whether group should be given extra space.
1524  * See gtk_tool_palette_set_expand().
1525  *
1526  * Returns: %TRUE if group should be given extra space, %FALSE otherwise
1527  *
1528  * Since: 2.20
1529  */
1530 gboolean
1531 gtk_tool_palette_get_expand (GtkToolPalette   *palette,
1532                              GtkToolItemGroup *group)
1533 {
1534   gint position;
1535   GtkToolItemGroupInfo *info;
1536
1537   g_return_val_if_fail (GTK_IS_TOOL_PALETTE (palette), DEFAULT_CHILD_EXPAND);
1538   g_return_val_if_fail (GTK_IS_TOOL_ITEM_GROUP (group), DEFAULT_CHILD_EXPAND);
1539
1540   position = gtk_tool_palette_get_group_position (palette, group);
1541   g_return_val_if_fail (position >= 0, DEFAULT_CHILD_EXPAND);
1542
1543   info = g_ptr_array_index (palette->priv->groups, position);
1544
1545   return info->expand;
1546 }
1547
1548 /**
1549  * gtk_tool_palette_get_drop_item:
1550  * @palette: a #GtkToolPalette
1551  * @x: the x position
1552  * @y: the y position
1553  *
1554  * Gets the item at position (x, y).
1555  * See gtk_tool_palette_get_drop_group().
1556  *
1557  * Returns: (transfer none): the #GtkToolItem at position or %NULL if there is no such item
1558  *
1559  * Since: 2.20
1560  */
1561 GtkToolItem*
1562 gtk_tool_palette_get_drop_item (GtkToolPalette *palette,
1563                                 gint            x,
1564                                 gint            y)
1565 {
1566   GtkAllocation allocation;
1567   GtkToolItemGroup *group = gtk_tool_palette_get_drop_group (palette, x, y);
1568   GtkWidget *widget = GTK_WIDGET (group);
1569
1570   if (group)
1571     {
1572       gtk_widget_get_allocation (widget, &allocation);
1573       return gtk_tool_item_group_get_drop_item (group,
1574                                                 x - allocation.x,
1575                                                 y - allocation.y);
1576     }
1577
1578   return NULL;
1579 }
1580
1581 /**
1582  * gtk_tool_palette_get_drop_group:
1583  * @palette: a #GtkToolPalette
1584  * @x: the x position
1585  * @y: the y position
1586  *
1587  * Gets the group at position (x, y).
1588  *
1589  * Returns: (transfer none): the #GtkToolItemGroup at position or %NULL
1590  *     if there is no such group
1591  *
1592  * Since: 2.20
1593  */
1594 GtkToolItemGroup*
1595 gtk_tool_palette_get_drop_group (GtkToolPalette *palette,
1596                                  gint            x,
1597                                  gint            y)
1598 {
1599   GtkAllocation allocation;
1600   guint i;
1601
1602   g_return_val_if_fail (GTK_IS_TOOL_PALETTE (palette), NULL);
1603
1604   gtk_widget_get_allocation (GTK_WIDGET (palette), &allocation);
1605
1606   g_return_val_if_fail (x >= 0 && x < allocation.width, NULL);
1607   g_return_val_if_fail (y >= 0 && y < allocation.height, NULL);
1608
1609   for (i = 0; i < palette->priv->groups->len; ++i)
1610     {
1611       GtkToolItemGroupInfo *group = g_ptr_array_index (palette->priv->groups, i);
1612       GtkWidget *widget;
1613       gint x0, y0;
1614
1615       if (!group->widget)
1616         continue;
1617
1618       widget = GTK_WIDGET (group->widget);
1619       gtk_widget_get_allocation (widget, &allocation);
1620
1621       x0 = x - allocation.x;
1622       y0 = y - allocation.y;
1623
1624       if (x0 >= 0 && x0 < allocation.width &&
1625           y0 >= 0 && y0 < allocation.height)
1626         return GTK_TOOL_ITEM_GROUP (widget);
1627     }
1628
1629   return NULL;
1630 }
1631
1632 /**
1633  * gtk_tool_palette_get_drag_item:
1634  * @palette: a #GtkToolPalette
1635  * @selection: a #GtkSelectionData
1636  *
1637  * Get the dragged item from the selection.
1638  * This could be a #GtkToolItem or a #GtkToolItemGroup.
1639  *
1640  * Returns: (transfer none): the dragged item in selection
1641  *
1642  * Since: 2.20
1643  */
1644 GtkWidget*
1645 gtk_tool_palette_get_drag_item (GtkToolPalette         *palette,
1646                                 const GtkSelectionData *selection)
1647 {
1648   GtkToolPaletteDragData *data;
1649   GdkAtom target;
1650
1651   g_return_val_if_fail (GTK_IS_TOOL_PALETTE (palette), NULL);
1652   g_return_val_if_fail (NULL != selection, NULL);
1653
1654   g_return_val_if_fail (gtk_selection_data_get_format (selection) == 8, NULL);
1655   g_return_val_if_fail (gtk_selection_data_get_length (selection) == sizeof (GtkToolPaletteDragData), NULL);
1656   target = gtk_selection_data_get_target (selection);
1657   g_return_val_if_fail (target == dnd_target_atom_item ||
1658                         target == dnd_target_atom_group,
1659                         NULL);
1660
1661   data = (GtkToolPaletteDragData*) gtk_selection_data_get_data (selection);
1662
1663   g_return_val_if_fail (data->palette == palette, NULL);
1664
1665   if (dnd_target_atom_item == target)
1666     g_return_val_if_fail (GTK_IS_TOOL_ITEM (data->item), NULL);
1667   else if (dnd_target_atom_group == target)
1668     g_return_val_if_fail (GTK_IS_TOOL_ITEM_GROUP (data->item), NULL);
1669
1670   return data->item;
1671 }
1672
1673 /**
1674  * gtk_tool_palette_set_drag_source:
1675  * @palette: a #GtkToolPalette
1676  * @targets: the #GtkToolPaletteDragTargets
1677  *     which the widget should support
1678  *
1679  * Sets the tool palette as a drag source.
1680  * Enables all groups and items in the tool palette as drag sources
1681  * on button 1 and button 3 press with copy and move actions.
1682  * See gtk_drag_source_set().
1683  *
1684  * Since: 2.20
1685  */
1686 void
1687 gtk_tool_palette_set_drag_source (GtkToolPalette            *palette,
1688                                   GtkToolPaletteDragTargets  targets)
1689 {
1690   guint i;
1691
1692   g_return_if_fail (GTK_IS_TOOL_PALETTE (palette));
1693
1694   if ((palette->priv->drag_source & targets) == targets)
1695     return;
1696
1697   palette->priv->drag_source |= targets;
1698
1699   for (i = 0; i < palette->priv->groups->len; ++i)
1700     {
1701       GtkToolItemGroupInfo *info = g_ptr_array_index (palette->priv->groups, i);
1702       if (info->widget)
1703         gtk_container_forall (GTK_CONTAINER (info->widget),
1704                               _gtk_tool_palette_child_set_drag_source,
1705                               palette);
1706     }
1707 }
1708
1709 /**
1710  * gtk_tool_palette_add_drag_dest:
1711  * @palette: a #GtkToolPalette
1712  * @widget: a #GtkWidget which should be a drag destination for @palette
1713  * @flags: the flags that specify what actions GTK+ should take for drops
1714  *     on that widget
1715  * @targets: the #GtkToolPaletteDragTargets which the widget
1716  *     should support
1717  * @actions: the #GdkDragAction<!-- -->s which the widget should suppport
1718  *
1719  * Sets @palette as drag source (see gtk_tool_palette_set_drag_source())
1720  * and sets @widget as a drag destination for drags from @palette.
1721  * See gtk_drag_dest_set().
1722  *
1723  * Since: 2.20
1724  */
1725 void
1726 gtk_tool_palette_add_drag_dest (GtkToolPalette            *palette,
1727                                 GtkWidget                 *widget,
1728                                 GtkDestDefaults            flags,
1729                                 GtkToolPaletteDragTargets  targets,
1730                                 GdkDragAction              actions)
1731 {
1732   GtkTargetEntry entries[G_N_ELEMENTS (dnd_targets)];
1733   gint n_entries = 0;
1734
1735   g_return_if_fail (GTK_IS_TOOL_PALETTE (palette));
1736   g_return_if_fail (GTK_IS_WIDGET (widget));
1737
1738   gtk_tool_palette_set_drag_source (palette,
1739                                     targets);
1740
1741   if (targets & GTK_TOOL_PALETTE_DRAG_ITEMS)
1742     entries[n_entries++] = dnd_targets[0];
1743   if (targets & GTK_TOOL_PALETTE_DRAG_GROUPS)
1744     entries[n_entries++] = dnd_targets[1];
1745
1746   gtk_drag_dest_set (widget, flags, entries, n_entries, actions);
1747 }
1748
1749 void
1750 _gtk_tool_palette_get_item_size (GtkToolPalette *palette,
1751                                  GtkRequisition *item_size,
1752                                  gboolean        homogeneous_only,
1753                                  gint           *requested_rows)
1754 {
1755   GtkRequisition max_requisition;
1756   gint max_rows;
1757   guint i;
1758
1759   g_return_if_fail (GTK_IS_TOOL_PALETTE (palette));
1760   g_return_if_fail (NULL != item_size);
1761
1762   max_requisition.width = 0;
1763   max_requisition.height = 0;
1764   max_rows = 0;
1765
1766   /* iterate over all groups and calculate the max item_size and max row request */
1767   for (i = 0; i < palette->priv->groups->len; ++i)
1768     {
1769       GtkRequisition requisition;
1770       gint rows;
1771       GtkToolItemGroupInfo *group = g_ptr_array_index (palette->priv->groups, i);
1772
1773       if (!group->widget)
1774         continue;
1775
1776       _gtk_tool_item_group_item_size_request (group->widget, &requisition, homogeneous_only, &rows);
1777
1778       max_requisition.width = MAX (max_requisition.width, requisition.width);
1779       max_requisition.height = MAX (max_requisition.height, requisition.height);
1780       max_rows = MAX (max_rows, rows);
1781     }
1782
1783   *item_size = max_requisition;
1784   if (requested_rows)
1785     *requested_rows = max_rows;
1786 }
1787
1788 static void
1789 gtk_tool_palette_item_drag_data_get (GtkWidget        *widget,
1790                                      GdkDragContext   *context,
1791                                      GtkSelectionData *selection,
1792                                      guint             info,
1793                                      guint             time,
1794                                      gpointer          data)
1795 {
1796   GtkToolPaletteDragData drag_data = { GTK_TOOL_PALETTE (data), NULL };
1797   GdkAtom target;
1798
1799   target = gtk_selection_data_get_target (selection);
1800
1801   if (target == dnd_target_atom_item)
1802     drag_data.item = gtk_widget_get_ancestor (widget, GTK_TYPE_TOOL_ITEM);
1803
1804   if (drag_data.item)
1805     gtk_selection_data_set (selection, target, 8,
1806                             (guchar*) &drag_data, sizeof (drag_data));
1807 }
1808
1809 static void
1810 gtk_tool_palette_child_drag_data_get (GtkWidget        *widget,
1811                                       GdkDragContext   *context,
1812                                       GtkSelectionData *selection,
1813                                       guint             info,
1814                                       guint             time,
1815                                       gpointer          data)
1816 {
1817   GtkToolPaletteDragData drag_data = { GTK_TOOL_PALETTE (data), NULL };
1818   GdkAtom target;
1819
1820   target = gtk_selection_data_get_target (selection);
1821
1822   if (target == dnd_target_atom_group)
1823     drag_data.item = gtk_widget_get_ancestor (widget, GTK_TYPE_TOOL_ITEM_GROUP);
1824
1825   if (drag_data.item)
1826     gtk_selection_data_set (selection, target, 8,
1827                             (guchar*) &drag_data, sizeof (drag_data));
1828 }
1829
1830 void
1831 _gtk_tool_palette_child_set_drag_source (GtkWidget *child,
1832                                          gpointer   data)
1833 {
1834   GtkToolPalette *palette = GTK_TOOL_PALETTE (data);
1835
1836   /* Check drag_source,
1837    * to work properly when called from gtk_tool_item_group_insert().
1838    */
1839   if (!palette->priv->drag_source)
1840     return;
1841
1842   if (GTK_IS_TOOL_ITEM (child) &&
1843       (palette->priv->drag_source & GTK_TOOL_PALETTE_DRAG_ITEMS))
1844     {
1845       /* Connect to child instead of the item itself,
1846        * to work arround bug 510377.
1847        */
1848       if (GTK_IS_TOOL_BUTTON (child))
1849         child = gtk_bin_get_child (GTK_BIN (child));
1850
1851       if (!child)
1852         return;
1853
1854       gtk_drag_source_set (child, GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
1855                            &dnd_targets[0], 1, GDK_ACTION_COPY | GDK_ACTION_MOVE);
1856
1857       g_signal_connect (child, "drag-data-get",
1858                         G_CALLBACK (gtk_tool_palette_item_drag_data_get),
1859                         palette);
1860     }
1861   else if (GTK_IS_BUTTON (child) &&
1862            (palette->priv->drag_source & GTK_TOOL_PALETTE_DRAG_GROUPS))
1863     {
1864       gtk_drag_source_set (child, GDK_BUTTON1_MASK | GDK_BUTTON3_MASK,
1865                            &dnd_targets[1], 1, GDK_ACTION_COPY | GDK_ACTION_MOVE);
1866
1867       g_signal_connect (child, "drag-data-get",
1868                         G_CALLBACK (gtk_tool_palette_child_drag_data_get),
1869                         palette);
1870     }
1871 }
1872
1873 /**
1874  * gtk_tool_palette_get_drag_target_item:
1875  *
1876  * Gets the target entry for a dragged #GtkToolItem.
1877  *
1878  * Returns: (transfer none): the #GtkTargetEntry for a dragged item.
1879  *
1880  * Since: 2.20
1881  */
1882 const GtkTargetEntry*
1883 gtk_tool_palette_get_drag_target_item (void)
1884 {
1885   return &dnd_targets[0];
1886 }
1887
1888 /**
1889  * gtk_tool_palette_get_drag_target_group:
1890  *
1891  * Get the target entry for a dragged #GtkToolItemGroup.
1892  *
1893  * Returns: (transfer none): the #GtkTargetEntry for a dragged group
1894  *
1895  * Since: 2.20
1896  */
1897 const GtkTargetEntry*
1898 gtk_tool_palette_get_drag_target_group (void)
1899 {
1900   return &dnd_targets[1];
1901 }
1902
1903 void
1904 _gtk_tool_palette_set_expanding_child (GtkToolPalette *palette,
1905                                        GtkWidget      *widget)
1906 {
1907   g_return_if_fail (GTK_IS_TOOL_PALETTE (palette));
1908   palette->priv->expanding_child = widget;
1909 }
1910
1911 /**
1912  * gtk_tool_palette_get_hadjustment:
1913  * @palette: a #GtkToolPalette
1914  *
1915  * Gets the horizontal adjustment of the tool palette.
1916  *
1917  * Returns: (transfer none): the horizontal adjustment of @palette
1918  *
1919  * Since: 2.20
1920  *
1921  * Deprecated: 3.0: Use gtk_scrollable_get_hadjustment()
1922  */
1923 GtkAdjustment*
1924 gtk_tool_palette_get_hadjustment (GtkToolPalette *palette)
1925 {
1926   g_return_val_if_fail (GTK_IS_TOOL_PALETTE (palette), NULL);
1927
1928   return palette->priv->hadjustment;
1929 }
1930
1931 static void
1932 gtk_tool_palette_set_hadjustment (GtkToolPalette *palette,
1933                                   GtkAdjustment  *adjustment)
1934 {
1935   GtkToolPalettePrivate *priv = palette->priv;
1936
1937   if (adjustment && priv->hadjustment == adjustment)
1938     return;
1939
1940   if (priv->hadjustment != NULL)
1941     {
1942       g_signal_handlers_disconnect_by_func (priv->hadjustment,
1943                                             gtk_tool_palette_adjustment_value_changed,
1944                                             palette);
1945       g_object_unref (priv->hadjustment);
1946     }
1947
1948   if (adjustment == NULL)
1949     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
1950                                      0.0, 0.0, 0.0);
1951
1952   g_signal_connect (adjustment, "value-changed",
1953                     G_CALLBACK (gtk_tool_palette_adjustment_value_changed),
1954                     palette);
1955   priv->hadjustment = g_object_ref_sink (adjustment);
1956   /* FIXME: Adjustment should probably have its values updated now */
1957   g_object_notify (G_OBJECT (palette), "hadjustment");
1958 }
1959
1960 /**
1961  * gtk_tool_palette_get_vadjustment:
1962  * @palette: a #GtkToolPalette
1963  *
1964  * Gets the vertical adjustment of the tool palette.
1965  *
1966  * Returns: (transfer none): the vertical adjustment of @palette
1967  *
1968  * Since: 2.20
1969  *
1970  * Deprecated: 3.0: Use gtk_scrollable_get_vadjustment()
1971  */
1972 GtkAdjustment*
1973 gtk_tool_palette_get_vadjustment (GtkToolPalette *palette)
1974 {
1975   g_return_val_if_fail (GTK_IS_TOOL_PALETTE (palette), NULL);
1976
1977   return palette->priv->vadjustment;
1978 }
1979
1980 static void
1981 gtk_tool_palette_set_vadjustment (GtkToolPalette *palette,
1982                                   GtkAdjustment  *adjustment)
1983 {
1984   GtkToolPalettePrivate *priv = palette->priv;
1985
1986   if (adjustment && priv->vadjustment == adjustment)
1987     return;
1988
1989   if (priv->vadjustment != NULL)
1990     {
1991       g_signal_handlers_disconnect_by_func (priv->vadjustment,
1992                                             gtk_tool_palette_adjustment_value_changed,
1993                                             palette);
1994       g_object_unref (priv->vadjustment);
1995     }
1996
1997   if (adjustment == NULL)
1998     adjustment = gtk_adjustment_new (0.0, 0.0, 0.0,
1999                                      0.0, 0.0, 0.0);
2000
2001   g_signal_connect (adjustment, "value-changed",
2002                     G_CALLBACK (gtk_tool_palette_adjustment_value_changed),
2003                     palette);
2004   priv->vadjustment = g_object_ref_sink (adjustment);
2005   /* FIXME: Adjustment should probably have its values updated now */
2006   g_object_notify (G_OBJECT (palette), "vadjustment");
2007 }
2008
2009 GtkSizeGroup *
2010 _gtk_tool_palette_get_size_group (GtkToolPalette *palette)
2011 {
2012   g_return_val_if_fail (GTK_IS_TOOL_PALETTE (palette), NULL);
2013
2014   return palette->priv->text_size_group;
2015 }