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