Code

Extensions. XAML export improvements.
[inkscape.git] / src / libgdl / gdl-dock-bar.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 
2  *
3  * This file is part of the GNOME Devtools Libraries.
4  *
5  * Copyright (C) 2003 Jeroen Zwartepoorte <jeroen@xs4all.nl>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include "gdl-i18n.h"
27 #include <stdlib.h>
28 #include <string.h>
30 #include "gdl-tools.h"
31 #include "gdl-dock.h"
32 #include "gdl-dock-master.h"
33 #include "gdl-dock-bar.h"
34 #include "libgdltypebuiltins.h"
36 enum {
37     PROP_0,
38     PROP_MASTER,
39     PROP_DOCKBAR_STYLE
40 };
42 /* ----- Private prototypes ----- */
44 static void  gdl_dock_bar_class_init      (GdlDockBarClass *klass);
45 static void  gdl_dock_bar_instance_init   (GdlDockBar      *dockbar);
47 static void  gdl_dock_bar_get_property    (GObject         *object,
48                                            guint            prop_id,
49                                            GValue          *value,
50                                            GParamSpec      *pspec);
51 static void  gdl_dock_bar_set_property    (GObject         *object,
52                                            guint            prop_id,
53                                            const GValue    *value,
54                                            GParamSpec      *pspec);
56 static void  gdl_dock_bar_destroy         (GtkObject       *object);
58 static void  gdl_dock_bar_attach          (GdlDockBar      *dockbar,
59                                            GdlDockMaster   *master);
60 static void gdl_dock_bar_remove_item      (GdlDockBar      *dockbar,
61                                            GdlDockItem     *item);
63 /* ----- Class variables and definitions ----- */
65 struct _GdlDockBarPrivate {
66     GdlDockMaster   *master;
67     GSList          *items;
68     GtkTooltips     *tooltips;
69     GtkOrientation   orientation;
70     GdlDockBarStyle  dockbar_style;
71 };
73 /* ----- Private functions ----- */
75 GDL_CLASS_BOILERPLATE (GdlDockBar, gdl_dock_bar, GtkBox, GTK_TYPE_BOX)
77 static void gdl_dock_bar_size_request (GtkWidget *widget,
78                                        GtkRequisition *requisition );
79 static void gdl_dock_bar_size_allocate (GtkWidget *widget,
80                                        GtkAllocation *allocation );
81 static void gdl_dock_bar_size_vrequest (GtkWidget *widget,
82                                        GtkRequisition *requisition );
83 static void gdl_dock_bar_size_vallocate (GtkWidget *widget,
84                                        GtkAllocation *allocation );
85 static void gdl_dock_bar_size_hrequest (GtkWidget *widget,
86                                        GtkRequisition *requisition );
87 static void gdl_dock_bar_size_hallocate (GtkWidget *widget,
88                                        GtkAllocation *allocation );
89 static void update_dock_items (GdlDockBar *dockbar, gboolean full_update);
91 void
92 gdl_dock_bar_class_init (GdlDockBarClass *klass)
93 {
94     GObjectClass       *g_object_class;
95     GtkObjectClass     *gtk_object_class;
96     GtkWidgetClass     *widget_class;
97     
98     g_object_class = G_OBJECT_CLASS (klass);
99     gtk_object_class = GTK_OBJECT_CLASS (klass);
101     g_object_class->get_property = gdl_dock_bar_get_property;
102     g_object_class->set_property = gdl_dock_bar_set_property;
104     gtk_object_class->destroy = gdl_dock_bar_destroy;
106     g_object_class_install_property (
107         g_object_class, PROP_MASTER,
108         g_param_spec_object ("master", _("Master"),
109                              _("GdlDockMaster object which the dockbar widget "
110                                "is attached to"),
111                              GDL_TYPE_DOCK_MASTER, 
112                              G_PARAM_READWRITE));
114     g_object_class_install_property (
115         g_object_class, PROP_DOCKBAR_STYLE,
116         g_param_spec_enum ("dockbar-style", _("Dockbar style"),
117                            _("Dockbar style to show items on it"),
118                            GDL_TYPE_DOCK_BAR_STYLE,
119                            GDL_DOCK_BAR_BOTH,
120                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
122     widget_class = GTK_WIDGET_CLASS (klass);
123     widget_class->size_request = gdl_dock_bar_size_request;
124     widget_class->size_allocate = gdl_dock_bar_size_allocate;
127 static void
128 gdl_dock_bar_instance_init (GdlDockBar *dockbar)
130     dockbar->_priv = g_new0 (GdlDockBarPrivate, 1);
131     dockbar->_priv->master = NULL;
132     dockbar->_priv->items = NULL;
133     dockbar->_priv->tooltips = gtk_tooltips_new ();
134     dockbar->_priv->orientation = GTK_ORIENTATION_VERTICAL;
135     dockbar->_priv->dockbar_style = GDL_DOCK_BAR_BOTH;
136     g_object_ref (dockbar->_priv->tooltips);
137     gtk_object_sink (GTK_OBJECT (dockbar->_priv->tooltips));
140 static void
141 gdl_dock_bar_get_property (GObject         *object,
142                            guint            prop_id,
143                            GValue          *value,
144                            GParamSpec      *pspec)
146     GdlDockBar *dockbar = GDL_DOCK_BAR (object);
148     switch (prop_id) {
149         case PROP_MASTER:
150             g_value_set_object (value, dockbar->_priv->master);
151             break;
152         case PROP_DOCKBAR_STYLE:
153             g_value_set_enum (value, dockbar->_priv->dockbar_style);
154             break;
155         default:
156             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
157     };
160 static void
161 gdl_dock_bar_set_property (GObject         *object,
162                            guint            prop_id,
163                            const GValue    *value,
164                            GParamSpec      *pspec)
166     GdlDockBar *dockbar = GDL_DOCK_BAR (object);
168     switch (prop_id) {
169         case PROP_MASTER:
170             gdl_dock_bar_attach (dockbar, g_value_get_object (value));
171             break;
172         case PROP_DOCKBAR_STYLE:
173             dockbar->_priv->dockbar_style = g_value_get_enum (value);
174             update_dock_items (dockbar, TRUE);
175             break;
176         default:
177             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
178     };
181 static void
182 on_dock_item_foreach_disconnect (GdlDockItem *item, GdlDockBar *dock_bar)
184     g_signal_handlers_disconnect_by_func (item, gdl_dock_bar_remove_item,
185                                           dock_bar);
188 static void
189 gdl_dock_bar_destroy (GtkObject *object)
191     GdlDockBar *dockbar = GDL_DOCK_BAR (object);
193     if (dockbar->_priv) {
194         GdlDockBarPrivate *priv = dockbar->_priv;
196         if (priv->items) {
197             g_slist_foreach (priv->items,
198                              (GFunc) on_dock_item_foreach_disconnect,
199                              object);
200             g_slist_free (priv->items);
201         }
202         
203         if (priv->master) {
204             g_signal_handlers_disconnect_matched (priv->master,
205                                                   G_SIGNAL_MATCH_DATA,
206                                                   0, 0, NULL, NULL, dockbar);
207             g_object_unref (priv->master);
208             priv->master = NULL;
209         }
211         if (priv->tooltips) {
212             g_object_unref (priv->tooltips);
213             priv->tooltips = NULL;
214         }
215         
216         dockbar->_priv = NULL;
218         g_free (priv);
219     }
220     
221     GDL_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object));
224 static void
225 gdl_dock_bar_remove_item (GdlDockBar  *dockbar,
226                           GdlDockItem *item)
228     GdlDockBarPrivate *priv;
229     GtkWidget *button;
231     g_return_if_fail (GDL_IS_DOCK_BAR (dockbar));
232     g_return_if_fail (GDL_IS_DOCK_ITEM (item));
234     priv = dockbar->_priv;
236     if (g_slist_index (priv->items, item) == -1) {
237         g_warning ("Item has not been added to the dockbar");
238         return;
239     }
240     
241     priv->items = g_slist_remove (priv->items, item);
242     
243     button = g_object_get_data (G_OBJECT (item), "GdlDockBarButton");
244     g_assert (button != NULL);
245     gtk_container_remove (GTK_CONTAINER (dockbar), button);
246     g_object_set_data (G_OBJECT (item), "GdlDockBarButton", NULL);
247     g_signal_handlers_disconnect_by_func (item,
248                                           G_CALLBACK (gdl_dock_bar_remove_item),
249                                           dockbar);
252 static void
253 gdl_dock_bar_item_clicked (GtkWidget   *button,
254                            GdlDockItem *item)
256     GdlDockBar *dockbar;
257     GdlDockObject *controller;
259     g_return_if_fail (item != NULL);
260     
261     dockbar = g_object_get_data (G_OBJECT (item), "GdlDockBar");
262     g_assert (dockbar != NULL);
263     g_object_set_data (G_OBJECT (item), "GdlDockBar", NULL);
265     controller = gdl_dock_master_get_controller (GDL_DOCK_OBJECT_GET_MASTER (item));
267     GDL_DOCK_OBJECT_UNSET_FLAGS (item, GDL_DOCK_ICONIFIED);
268     gdl_dock_item_show_item (item);
269     gdl_dock_bar_remove_item (dockbar, item);
270     gtk_widget_queue_resize (GTK_WIDGET (controller));
273 static void
274 gdl_dock_bar_add_item (GdlDockBar  *dockbar,
275                        GdlDockItem *item)
277     GdlDockBarPrivate *priv;
278     GtkWidget *button;
279     gchar *stock_id;
280     gchar *name;
281     GdkPixbuf *pixbuf_icon;
282     GtkWidget *image, *box, *label;
284     g_return_if_fail (GDL_IS_DOCK_BAR (dockbar));
285     g_return_if_fail (GDL_IS_DOCK_ITEM (item));
287     priv = dockbar->_priv;
289     if (g_slist_index (priv->items, item) != -1) {
290         g_warning ("Item has already been added to the dockbar");
291         return;
292     }
294     priv->items = g_slist_append (priv->items, item);
295     
296     /* Create a button for the item. */
297     button = gtk_button_new ();
298     gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
299     
300     if (dockbar->_priv->orientation == GTK_ORIENTATION_HORIZONTAL)
301         box = gtk_hbox_new (FALSE, 0);
302     else
303         box = gtk_vbox_new (FALSE, 0);
304     
305     g_object_get (item, "stock-id", &stock_id, "pixbuf-icon", &pixbuf_icon,
306                   "long-name", &name, NULL);
308     if (dockbar->_priv->dockbar_style == GDL_DOCK_BAR_TEXT ||
309         dockbar->_priv->dockbar_style == GDL_DOCK_BAR_BOTH) {
310         label = gtk_label_new (name);
311         if (dockbar->_priv->orientation == GTK_ORIENTATION_VERTICAL)
312             gtk_label_set_angle (GTK_LABEL (label), 90);
313         gtk_box_pack_start_defaults (GTK_BOX (box), label);
314     }
315     
316     /* FIXME: For now AUTO behaves same as BOTH */
317     
318     if (dockbar->_priv->dockbar_style == GDL_DOCK_BAR_ICONS ||
319         dockbar->_priv->dockbar_style == GDL_DOCK_BAR_BOTH ||
320         dockbar->_priv->dockbar_style == GDL_DOCK_BAR_AUTO) {
321         if (stock_id) {
322             image = gtk_image_new_from_stock (stock_id,
323                                               GTK_ICON_SIZE_SMALL_TOOLBAR);
324             g_free (stock_id);
325         } else if (pixbuf_icon) {
326             image = gtk_image_new_from_pixbuf (pixbuf_icon);
327         } else {
328             image = gtk_image_new_from_stock (GTK_STOCK_NEW,
329                                               GTK_ICON_SIZE_SMALL_TOOLBAR);
330         }
331         gtk_box_pack_start_defaults (GTK_BOX (box), image);
332     }
333     
334     gtk_container_add (GTK_CONTAINER (button), box);
335     gtk_box_pack_start (GTK_BOX (dockbar), button, FALSE, FALSE, 0);
337     gtk_tooltips_set_tip (priv->tooltips, button, name, name);
338     g_free (name);
340     g_object_set_data (G_OBJECT (item), "GdlDockBar", dockbar);
341     g_object_set_data (G_OBJECT (item), "GdlDockBarButton", button);
342     g_signal_connect (G_OBJECT (button), "clicked",
343                       G_CALLBACK (gdl_dock_bar_item_clicked), item);
345     gtk_widget_show_all (button);
346     
347     /* Set up destroy notify */
348     g_signal_connect_swapped (item, "destroy",
349                               G_CALLBACK (gdl_dock_bar_remove_item),
350                               dockbar);
353 static void
354 build_list (GdlDockObject *object, GList **list)
356     /* add only items, not toplevels */
357     if (GDL_IS_DOCK_ITEM (object))
358         *list = g_list_prepend (*list, object);
361 static void
362 update_dock_items (GdlDockBar *dockbar, gboolean full_update)
364     GdlDockMaster *master;
365     GList *items, *l;
367     g_return_if_fail (dockbar != NULL);
368     
369     if (!dockbar->_priv->master)
370         return;
372     master = dockbar->_priv->master;
373     
374     /* build items list */
375     items = NULL;
376     gdl_dock_master_foreach (master, (GFunc) build_list, &items);
377     
378     if (!full_update) {
379         for (l = items; l != NULL; l = l->next) {
380             GdlDockItem *item = GDL_DOCK_ITEM (l->data);
381             
382             if (g_slist_index (dockbar->_priv->items, item) != -1 &&
383                 !GDL_DOCK_ITEM_ICONIFIED (item))
384                 gdl_dock_bar_remove_item (dockbar, item);
385             else if (g_slist_index (dockbar->_priv->items, item) == -1 &&
386                 GDL_DOCK_ITEM_ICONIFIED (item))
387                 gdl_dock_bar_add_item (dockbar, item);
388         }
389     } else {
390         for (l = items; l != NULL; l = l->next) {
391             GdlDockItem *item = GDL_DOCK_ITEM (l->data);
392             
393             if (g_slist_index (dockbar->_priv->items, item) != -1)
394                 gdl_dock_bar_remove_item (dockbar, item);
395             if (GDL_DOCK_ITEM_ICONIFIED (item))
396                 gdl_dock_bar_add_item (dockbar, item);
397         }
398     }
399     g_list_free (items);
402 static void
403 gdl_dock_bar_layout_changed_cb (GdlDockMaster *master,
404                                 GdlDockBar    *dockbar)
406     update_dock_items (dockbar, FALSE);
409 static void
410 gdl_dock_bar_attach (GdlDockBar    *dockbar,
411                      GdlDockMaster *master)
413     g_return_if_fail (dockbar != NULL);
414     g_return_if_fail (master == NULL || GDL_IS_DOCK_MASTER (master));
415     
416     if (dockbar->_priv->master) {
417         g_signal_handlers_disconnect_matched (dockbar->_priv->master,
418                                               G_SIGNAL_MATCH_DATA,
419                                               0, 0, NULL, NULL, dockbar);
420         g_object_unref (dockbar->_priv->master);
421     }
422     
423     dockbar->_priv->master = master;
424     if (dockbar->_priv->master) {
425         g_object_ref (dockbar->_priv->master);
426         g_signal_connect (dockbar->_priv->master, "layout-changed",
427                           G_CALLBACK (gdl_dock_bar_layout_changed_cb),
428                           dockbar);
429     }
431     update_dock_items (dockbar, FALSE);
434 static void gdl_dock_bar_size_request (GtkWidget *widget,
435                                        GtkRequisition *requisition )
437     GdlDockBar *dockbar;
439     dockbar = GDL_DOCK_BAR (widget);
440     
441     /* default to vertical for unknown values */
442     switch (dockbar->_priv->orientation) {
443         case GTK_ORIENTATION_HORIZONTAL:
444                 gdl_dock_bar_size_hrequest (widget, requisition);
445                 break;
446         case GTK_ORIENTATION_VERTICAL:
447         default:
448                 gdl_dock_bar_size_vrequest (widget, requisition);
449                 break;
450     }
453 static void gdl_dock_bar_size_allocate (GtkWidget *widget,
454                                        GtkAllocation *allocation )
456     GdlDockBar *dockbar;
458     dockbar = GDL_DOCK_BAR (widget);
459     
460     /* default to vertical for unknown values */
461     switch (dockbar->_priv->orientation) {
462         case GTK_ORIENTATION_HORIZONTAL:
463                 gdl_dock_bar_size_hallocate (widget, allocation);
464                 break;
465         case GTK_ORIENTATION_VERTICAL:
466         default:
467                 gdl_dock_bar_size_vallocate (widget, allocation);
468                 break;
469     }
472 static void gdl_dock_bar_size_vrequest (GtkWidget *widget,
473                                        GtkRequisition *requisition )
475   GtkBox *box;
476   GtkBoxChild *child;
477   GtkRequisition child_requisition;
478   GList *children;
479   gint nvis_children;
480   gint height;
482   box = GTK_BOX (widget);
483   requisition->width = 0;
484   requisition->height = 0;
485   nvis_children = 0;
487   children = box->children;
488   while (children)
489     {
490       child = children->data;
491       children = children->next;
493       if (GTK_WIDGET_VISIBLE (child->widget))
494         {
495           gtk_widget_size_request (child->widget, &child_requisition);
497           if (box->homogeneous)
498             {
499               height = child_requisition.height + child->padding * 2;
500               requisition->height = MAX (requisition->height, height);
501             }
502           else
503             {
504               requisition->height += child_requisition.height + child->padding * 2;
505             }
507           requisition->width = MAX (requisition->width, child_requisition.width);
509           nvis_children += 1;
510         }
511     }
513   if (nvis_children > 0)
514     {
515       if (box->homogeneous)
516         requisition->height *= nvis_children;
517       requisition->height += (nvis_children - 1) * box->spacing;
518     }
520   requisition->width += GTK_CONTAINER (box)->border_width * 2;
521   requisition->height += GTK_CONTAINER (box)->border_width * 2;
525 static void gdl_dock_bar_size_vallocate (GtkWidget     *widget,
526                         GtkAllocation *allocation)
528   GtkBox *box;
529   GtkBoxChild *child;
530   GList *children;
531   GtkAllocation child_allocation;
532   gint nvis_children;
533   gint nexpand_children;
534   gint child_height;
535   gint height;
536   gint extra;
537   gint y;
539   box = GTK_BOX (widget);
540   widget->allocation = *allocation;
542   nvis_children = 0;
543   nexpand_children = 0;
544   children = box->children;
546   while (children)
547     {
548       child = children->data;
549       children = children->next;
551       if (GTK_WIDGET_VISIBLE (child->widget))
552         {
553           nvis_children += 1;
554           if (child->expand)
555             nexpand_children += 1;
556         }
557     }
559   if (nvis_children > 0)
560     {
561       if (box->homogeneous)
562         {
563           height = (allocation->height -
564                    GTK_CONTAINER (box)->border_width * 2 -
565                    (nvis_children - 1) * box->spacing);
566           extra = height / nvis_children;
567         }
568       else if (nexpand_children > 0)
569         {
570           height = (gint) allocation->height - (gint) widget->requisition.height;
571           extra = height / nexpand_children;
572         }
573       else
574         {
575           height = 0;
576           extra = 0;
577         }
579       y = allocation->y + GTK_CONTAINER (box)->border_width;
580       child_allocation.x = allocation->x + GTK_CONTAINER (box)->border_width;
581       child_allocation.width = MAX (1, (gint) allocation->width - (gint) GTK_CONTAINER (box)->border_width * 2);
583       children = box->children;
584       while (children)
585         {
586           child = children->data;
587           children = children->next;
589           if ((child->pack == GTK_PACK_START) && GTK_WIDGET_VISIBLE (child->widget))
590             {
591               if (box->homogeneous)
592                 {
593                   if (nvis_children == 1)
594                     child_height = height;
595                   else
596                     child_height = extra;
598                   nvis_children -= 1;
599                   height -= extra;
600                 }
601               else
602                 {
603                   GtkRequisition child_requisition;
605                   gtk_widget_get_child_requisition (child->widget, &child_requisition);
606                   child_height = child_requisition.height + child->padding * 2;
608                   if (child->expand)
609                     {
610                       if (nexpand_children == 1)
611                         child_height += height;
612                       else
613                         child_height += extra;
615                       nexpand_children -= 1;
616                       height -= extra;
617                     }
618                 }
620               if (child->fill)
621                 {
622                   child_allocation.height = MAX (1, child_height - (gint)child->padding * 2);
623                   child_allocation.y = y + child->padding;
624                 }
625               else
626                 {
627                   GtkRequisition child_requisition;
629                   gtk_widget_get_child_requisition (child->widget, &child_requisition);
630                   child_allocation.height = child_requisition.height;
631                   child_allocation.y = y + (child_height - child_allocation.height) / 2;
632                 }
634               gtk_widget_size_allocate (child->widget, &child_allocation);
636               y += child_height + box->spacing;
637             }
638         }
640       y = allocation->y + allocation->height - GTK_CONTAINER (box)->border_width;
642       children = box->children;
643       while (children)
644         {
645           child = children->data;
646           children = children->next;
648           if ((child->pack == GTK_PACK_END) && GTK_WIDGET_VISIBLE (child->widget))
649             {
650               GtkRequisition child_requisition;
651               gtk_widget_get_child_requisition (child->widget, &child_requisition);
653               if (box->homogeneous)
654                 {
655                   if (nvis_children == 1)
656                     child_height = height;
657                   else
658                     child_height = extra;
660                   nvis_children -= 1;
661                   height -= extra;
662                 }
663               else
664                 {
665                   child_height = child_requisition.height + child->padding * 2;
667                   if (child->expand)
668                     {
669                       if (nexpand_children == 1)
670                         child_height += height;
671                       else
672                         child_height += extra;
674                       nexpand_children -= 1;
675                       height -= extra;
676                     }
677                 }
679               if (child->fill)
680                 {
681                   child_allocation.height = MAX (1, child_height - (gint)child->padding * 2);
682                   child_allocation.y = y + child->padding - child_height;
683                 }
684               else
685                 {
686                   child_allocation.height = child_requisition.height;
687                   child_allocation.y = y + (child_height - child_allocation.height) / 2 - child_height;
688                 }
690               gtk_widget_size_allocate (child->widget, &child_allocation);
692               y -= (child_height + box->spacing);
693             }
694         }
695     }
698 static void gdl_dock_bar_size_hrequest (GtkWidget *widget,
699                                        GtkRequisition *requisition )
701   GtkBox *box;
702   GtkBoxChild *child;
703   GList *children;
704   gint nvis_children;
705   gint width;
707   box = GTK_BOX (widget);
708   requisition->width = 0;
709   requisition->height = 0;
710   nvis_children = 0;
712   children = box->children;
713   while (children)
714     {
715       child = children->data;
716       children = children->next;
718       if (GTK_WIDGET_VISIBLE (child->widget))
719         {
720           GtkRequisition child_requisition;
722           gtk_widget_size_request (child->widget, &child_requisition);
724           if (box->homogeneous)
725             {
726               width = child_requisition.width + child->padding * 2;
727               requisition->width = MAX (requisition->width, width);
728             }
729           else
730             {
731               requisition->width += child_requisition.width + child->padding * 2;
732             }
734           requisition->height = MAX (requisition->height, child_requisition.height);
736           nvis_children += 1;
737         }
738     }
740   if (nvis_children > 0)
741     {
742       if (box->homogeneous)
743         requisition->width *= nvis_children;
744       requisition->width += (nvis_children - 1) * box->spacing;
745     }
747   requisition->width += GTK_CONTAINER (box)->border_width * 2;
748   requisition->height += GTK_CONTAINER (box)->border_width * 2;
751 static void gdl_dock_bar_size_hallocate (GtkWidget     *widget,
752                         GtkAllocation *allocation)
754  GtkBox *box;
755   GtkBoxChild *child;
756   GList *children;
757   GtkAllocation child_allocation;
758   gint nvis_children;
759   gint nexpand_children;
760   gint child_width;
761   gint width;
762   gint extra;
763   gint x;
764   GtkTextDirection direction;
766   box = GTK_BOX (widget);
767   widget->allocation = *allocation;
769   direction = gtk_widget_get_direction (widget);
770   
771   nvis_children = 0;
772   nexpand_children = 0;
773   children = box->children;
775   while (children)
776     {
777       child = children->data;
778       children = children->next;
780       if (GTK_WIDGET_VISIBLE (child->widget))
781         {
782           nvis_children += 1;
783           if (child->expand)
784             nexpand_children += 1;
785         }
786     }
788   if (nvis_children > 0)
789     {
790       if (box->homogeneous)
791         {
792           width = (allocation->width -
793                    GTK_CONTAINER (box)->border_width * 2 -
794                    (nvis_children - 1) * box->spacing);
795           extra = width / nvis_children;
796         }
797       else if (nexpand_children > 0)
798         {
799           width = (gint) allocation->width - (gint) widget->requisition.width;
800           extra = width / nexpand_children;
801         }
802       else
803         {
804           width = 0;
805           extra = 0;
806         }
808       x = allocation->x + GTK_CONTAINER (box)->border_width;
809       child_allocation.y = allocation->y + GTK_CONTAINER (box)->border_width;
810       child_allocation.height = MAX (1, (gint) allocation->height - (gint) GTK_CONTAINER (box)->border_width * 2);
812       children = box->children;
813       while (children)
814         {
815           child = children->data;
816           children = children->next;
818           if ((child->pack == GTK_PACK_START) && GTK_WIDGET_VISIBLE (child->widget))
819             {
820               if (box->homogeneous)
821                 {
822                   if (nvis_children == 1)
823                     child_width = width;
824                   else
825                     child_width = extra;
827                   nvis_children -= 1;
828                   width -= extra;
829                 }
830               else
831                 {
832                   GtkRequisition child_requisition;
834                   gtk_widget_get_child_requisition (child->widget, &child_requisition);
836                   child_width = child_requisition.width + child->padding * 2;
838                   if (child->expand)
839                     {
840                       if (nexpand_children == 1)
841                         child_width += width;
842                       else
843                         child_width += extra;
845                       nexpand_children -= 1;
846                       width -= extra;
847                     }
848                 }
850               if (child->fill)
851                 {
852                   child_allocation.width = MAX (1, (gint) child_width - (gint) child->padding * 2);
853                   child_allocation.x = x + child->padding;
854                 }
855               else
856                 {
857                   GtkRequisition child_requisition;
859                   gtk_widget_get_child_requisition (child->widget, &child_requisition);
860                   child_allocation.width = child_requisition.width;
861                   child_allocation.x = x + (child_width - child_allocation.width) / 2;
862                 }
864               if (direction == GTK_TEXT_DIR_RTL)
865                 child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
867               gtk_widget_size_allocate (child->widget, &child_allocation);
869               x += child_width + box->spacing;
870             }
871         }
873       x = allocation->x + allocation->width - GTK_CONTAINER (box)->border_width;
875       children = box->children;
876       while (children)
877         {
878           child = children->data;
879           children = children->next;
881           if ((child->pack == GTK_PACK_END) && GTK_WIDGET_VISIBLE (child->widget))
882             {
883               GtkRequisition child_requisition;
884               gtk_widget_get_child_requisition (child->widget, &child_requisition);
886               if (box->homogeneous)
887                 {
888                   if (nvis_children == 1)
889                     child_width = width;
890                   else
891                     child_width = extra;
893                   nvis_children -= 1;
894                   width -= extra;
895                 }
896               else
897                 {
898                   child_width = child_requisition.width + child->padding * 2;
900                   if (child->expand)
901                     {
902                       if (nexpand_children == 1)
903                         child_width += width;
904                       else
905                         child_width += extra;
907                       nexpand_children -= 1;
908                       width -= extra;
909                     }
910                 }
912               if (child->fill)
913                 {
914                   child_allocation.width = MAX (1, (gint)child_width - (gint)child->padding * 2);
915                   child_allocation.x = x + child->padding - child_width;
916                 }
917               else
918                 {
919                   child_allocation.width = child_requisition.width;
920                   child_allocation.x = x + (child_width - child_allocation.width) / 2 - child_width;
921                 }
923               if (direction == GTK_TEXT_DIR_RTL)
924                 child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
926               gtk_widget_size_allocate (child->widget, &child_allocation);
928               x -= (child_width + box->spacing);
929             }
930         }
931     }
934 GtkWidget *
935 gdl_dock_bar_new (GdlDock *dock)
937     GdlDockMaster *master = NULL;
938     
939     /* get the master of the given dock */
940     if (dock)
941         master = GDL_DOCK_OBJECT_GET_MASTER (dock);
943     return g_object_new (GDL_TYPE_DOCK_BAR,
944                          "master", master, NULL);
947 GtkOrientation gdl_dock_bar_get_orientation (GdlDockBar *dockbar)
949     g_return_val_if_fail (GDL_IS_DOCK_BAR (dockbar),
950                           GTK_ORIENTATION_VERTICAL);
952     return dockbar->_priv->orientation;
955 void gdl_dock_bar_set_orientation (GdlDockBar *dockbar,
956                                      GtkOrientation orientation)
958     g_return_if_fail (GDL_IS_DOCK_BAR (dockbar));
960     dockbar->_priv->orientation = orientation;
962     gtk_widget_queue_resize (GTK_WIDGET (dockbar));
965 void gdl_dock_bar_set_style(GdlDockBar* dockbar,
966                             GdlDockBarStyle style)
968     g_object_set(G_OBJECT(dockbar), "dockbar-style", style, NULL);
971 GdlDockBarStyle gdl_dock_bar_get_style(GdlDockBar* dockbar)
973     GdlDockBarStyle style;
974     g_object_get(G_OBJECT(dockbar), "dockbar-style", &style, NULL);
975     return style;