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