1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 8 -*- */
2 /* gdl-switcher.c
3  *
4  * Copyright (C) 2003  Ettore Perazzoli,
5  *               2007  Naba Kumar
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 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  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  *
20  *
21  * Copied and adapted from ESidebar.[ch] from evolution
22  *
23  * Authors: Ettore Perazzoli <ettore@ximian.com>
24  *          Naba Kumar  <naba@gnome.org>
25  */
26 
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 
31 #include <glib/gi18n-lib.h>
32 #include "gdl-switcher.h"
33 #include "libgdlmarshal.h"
34 #include "libgdltypebuiltins.h"
35 
36 #include <gtk/gtk.h>
37 
38 /**
39  * SECTION:gdl-switcher
40  * @title: GdlSwitcher
41  * @short_description: An improved notebook widget.
42  * @stability: Unstable
43  * @see_also: #GdlDockNotebook
44  *
45  * A #GdlSwitcher widget is an improved version of the #GtkNotebook. The
46  * tab labels could have different style and could be layouted on several lines.
47  *
48  * It is used by the #GdlDockNotebook widget to dock other widgets.
49  */
50 
51 
52 static void gdl_switcher_set_property  (GObject            *object,
53                                         guint               prop_id,
54                                         const GValue       *value,
55                                         GParamSpec         *pspec);
56 static void gdl_switcher_get_property  (GObject            *object,
57                                         guint               prop_id,
58                                         GValue             *value,
59                                         GParamSpec         *pspec);
60 
61 static void gdl_switcher_add_button  (GdlSwitcher *switcher,
62                                       const gchar *label,
63                                       const gchar *tooltips,
64                                       const gchar *stock_id,
65                                       GdkPixbuf *pixbuf_icon,
66                                       gint switcher_id,
67                                       GtkWidget *page);
68 /* static void gdl_switcher_remove_button (GdlSwitcher *switcher, gint switcher_id); */
69 static void gdl_switcher_select_page (GdlSwitcher *switcher, gint switcher_id);
70 static void gdl_switcher_select_button (GdlSwitcher *switcher, gint switcher_id);
71 static void gdl_switcher_set_show_buttons (GdlSwitcher *switcher, gboolean show);
72 static void gdl_switcher_set_style (GdlSwitcher *switcher,
73                                     GdlSwitcherStyle switcher_style);
74 static GdlSwitcherStyle gdl_switcher_get_style (GdlSwitcher *switcher);
75 static void gdl_switcher_set_tab_pos (GdlSwitcher *switcher, GtkPositionType pos);
76 static void gdl_switcher_set_tab_reorderable (GdlSwitcher *switcher, gboolean reorderable);
77 static void gdl_switcher_update_lone_button_visibility (GdlSwitcher *switcher);
78 
79 enum {
80     PROP_0,
81     PROP_SWITCHER_STYLE,
82     PROP_TAB_POS,
83     PROP_TAB_REORDERABLE
84 };
85 
86 typedef struct {
87     GtkWidget *button_widget;
88     GtkWidget *label;
89     GtkWidget *icon;
90     GtkWidget *arrow;
91     GtkWidget *hbox;
92     GtkWidget *page;
93     int id;
94 } Button;
95 
96 struct _GdlSwitcherPrivate {
97     GdlSwitcherStyle switcher_style;
98     GdlSwitcherStyle toolbar_style;
99     GtkPositionType tab_pos;
100     gboolean tab_reorderable;
101 
102     gboolean show;
103     GSList *buttons;
104 
105     guint style_changed_id;
106     gint buttons_height_request;
107     gboolean in_toggle;
108 };
109 
110 struct _GdlSwitcherClassPrivate {
111     GtkCssProvider *css;
112 };
113 
G_DEFINE_TYPE_WITH_CODE(GdlSwitcher,gdl_switcher,GTK_TYPE_NOTEBOOK,g_type_add_class_private (g_define_type_id,sizeof (GdlSwitcherClassPrivate)))114 G_DEFINE_TYPE_WITH_CODE (GdlSwitcher, gdl_switcher, GTK_TYPE_NOTEBOOK,
115                          g_type_add_class_private (g_define_type_id, sizeof (GdlSwitcherClassPrivate)))
116 
117 #define INTERNAL_MODE(switcher)  (switcher->priv->switcher_style == \
118             GDL_SWITCHER_STYLE_TOOLBAR ? switcher->priv->toolbar_style : \
119             switcher->priv->switcher_style)
120 
121 #define H_PADDING 0
122 #define V_PADDING 0
123 #define V_SPACING 2
124 
125 /* Utility functions.  */
126 
127 static void
128 gdl_switcher_long_name_changed (GObject* object,
129                                 GParamSpec* spec,
130                                 gpointer user_data)
131 {
132     Button* button = user_data;
133     gchar* label;
134 
135     g_object_get (object, "long-name", &label, NULL);
136     gtk_label_set_text (GTK_LABEL (button->label), label);
137     g_free (label);
138 }
139 
140 static void
gdl_switcher_stock_id_changed(GObject * object,GParamSpec * spec,gpointer user_data)141 gdl_switcher_stock_id_changed (GObject* object,
142                                GParamSpec* spec,
143                                gpointer user_data)
144 {
145     Button* button = user_data;
146     gchar* id;
147 
148     g_object_get (object, "stock-id", &id, NULL);
149     gtk_image_set_from_stock (GTK_IMAGE(button->icon), id, GTK_ICON_SIZE_MENU);
150     g_free (id);
151 }
152 
153 static void
gdl_switcher_visible_changed(GObject * object,GParamSpec * spec,gpointer user_data)154 gdl_switcher_visible_changed (GObject* object,
155                                GParamSpec* spec,
156                                gpointer user_data)
157 {
158     Button* button = user_data;
159     GdlSwitcher* switcher;
160 
161     if (gtk_widget_get_visible (button->page))
162     {
163         gtk_widget_show_all (button->button_widget);
164     }
165     else
166     {
167         gtk_widget_hide (button->button_widget);
168     }
169     switcher = GDL_SWITCHER (gtk_widget_get_parent (button->button_widget));
170     gdl_switcher_update_lone_button_visibility (switcher);
171 }
172 
173 
174 static Button *
button_new(GtkWidget * button_widget,GtkWidget * label,GtkWidget * icon,GtkWidget * arrow,GtkWidget * hbox,int id,GtkWidget * page)175 button_new (GtkWidget *button_widget, GtkWidget *label, GtkWidget *icon,
176             GtkWidget *arrow, GtkWidget *hbox, int id, GtkWidget *page)
177 {
178     Button *button = g_new (Button, 1);
179 
180     button->button_widget = button_widget;
181     button->label = label;
182     button->icon = icon;
183     button->arrow = arrow;
184     button->hbox = hbox;
185     button->id = id;
186     button->page = page;
187 
188     g_signal_connect (page, "notify::long-name", G_CALLBACK (gdl_switcher_long_name_changed),
189                       button);
190     g_signal_connect (page, "notify::stock-id", G_CALLBACK (gdl_switcher_stock_id_changed),
191                       button);
192     g_signal_connect (page, "notify::visible", G_CALLBACK (gdl_switcher_visible_changed),
193                       button);
194 
195     g_object_ref (button_widget);
196     g_object_ref (label);
197     g_object_ref (icon);
198     g_object_ref (arrow);
199     g_object_ref (hbox);
200 
201     return button;
202 }
203 
204 static void
button_free(Button * button)205 button_free (Button *button)
206 {
207     g_signal_handlers_disconnect_by_func (button->page,
208                                           gdl_switcher_long_name_changed,
209                                           button);
210     g_signal_handlers_disconnect_by_func (button->page,
211                                           gdl_switcher_stock_id_changed,
212                                           button);
213     g_signal_handlers_disconnect_by_func (button->page,
214                                           gdl_switcher_visible_changed,
215                                           button);
216 
217     g_object_unref (button->button_widget);
218     g_object_unref (button->label);
219     g_object_unref (button->icon);
220     g_object_unref (button->hbox);
221     g_free (button);
222 }
223 
224 static gint
gdl_switcher_get_page_id(GtkWidget * widget)225 gdl_switcher_get_page_id (GtkWidget *widget)
226 {
227     static gint switcher_id_count = 0;
228     gint switcher_id;
229     switcher_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
230                                                       "__switcher_id"));
231     if (switcher_id <= 0) {
232         switcher_id = ++switcher_id_count;
233         g_object_set_data (G_OBJECT (widget), "__switcher_id",
234                            GINT_TO_POINTER (switcher_id));
235     }
236     return switcher_id;
237 }
238 
239 /* Hide switcher button if they are not needed (only one visible page)
240  * or show switcher button if there are two visible pages */
241 static void
gdl_switcher_update_lone_button_visibility(GdlSwitcher * switcher)242 gdl_switcher_update_lone_button_visibility (GdlSwitcher *switcher)
243 {
244     GSList *p;
245     GtkWidget *alone = NULL;
246 
247     for (p = switcher->priv->buttons; p != NULL; p = p->next) {
248         Button *button = p->data;
249 
250         if (gtk_widget_get_visible (button->page))
251         {
252             if (alone == NULL)
253             {
254                 alone = button->button_widget;
255             }
256             else
257             {
258                 gtk_widget_show (alone);
259                 gtk_widget_show (button->button_widget);
260                 alone = NULL;
261                 break;
262             }
263         }
264     }
265 
266     if (alone) gtk_widget_hide (alone);
267 }
268 
269 static void
update_buttons(GdlSwitcher * switcher,int new_selected_id)270 update_buttons (GdlSwitcher *switcher, int new_selected_id)
271 {
272     GSList *p;
273 
274     switcher->priv->in_toggle = TRUE;
275 
276     for (p = switcher->priv->buttons; p != NULL; p = p->next) {
277         Button *button = p->data;
278 
279         if (button->id == new_selected_id) {
280             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
281                                           (button->button_widget), TRUE);
282             gtk_widget_set_sensitive (button->arrow, TRUE);
283         } else {
284             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
285                                           (button->button_widget), FALSE);
286             gtk_widget_set_sensitive (button->arrow, FALSE);
287         }
288     }
289 
290     switcher->priv->in_toggle = FALSE;
291 }
292 
293 /* Callbacks.  */
294 
295 static void
button_toggled_callback(GtkToggleButton * toggle_button,GdlSwitcher * switcher)296 button_toggled_callback (GtkToggleButton *toggle_button,
297                          GdlSwitcher *switcher)
298 {
299     int id = 0;
300     gboolean is_active = FALSE;
301     GSList *p;
302 
303     if (switcher->priv->in_toggle)
304         return;
305 
306     switcher->priv->in_toggle = TRUE;
307 
308     if (gtk_toggle_button_get_active (toggle_button))
309         is_active = TRUE;
310 
311     for (p = switcher->priv->buttons; p != NULL; p = p->next) {
312         Button *button = p->data;
313 
314         if (button->button_widget != GTK_WIDGET (toggle_button)) {
315             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
316                                           (button->button_widget), FALSE);
317             gtk_widget_set_sensitive (button->arrow, FALSE);
318         } else {
319             gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
320                                           (button->button_widget), TRUE);
321             gtk_widget_set_sensitive (button->arrow, TRUE);
322             id = button->id;
323         }
324     }
325 
326     switcher->priv->in_toggle = FALSE;
327 
328     if (is_active)
329     {
330         gdl_switcher_select_page (switcher, id);
331     }
332 }
333 
334 static gboolean
delayed_resize_switcher(gpointer data)335 delayed_resize_switcher (gpointer data)
336 {
337     gtk_widget_queue_resize (GTK_WIDGET (data));
338     return FALSE;
339 }
340 
341 /* Returns -1 if layout didn't happen because a resize request was queued */
342 static int
layout_buttons(GdlSwitcher * switcher,GtkAllocation * allocation)343 layout_buttons (GdlSwitcher *switcher, GtkAllocation* allocation)
344 {
345     gint min_height, nat_height;
346     GdlSwitcherStyle switcher_style;
347     gboolean icons_only;
348     int num_btns;
349     int btns_per_row;
350     GSList **rows, *p;
351     Button *button;
352     int row_number;
353     int max_btn_width = 0, max_btn_height = 0;
354     int optimal_layout_width = 0;
355     int row_last;
356     int x, y;
357     int i;
358     int rows_count;
359     int last_buttons_height;
360 
361     last_buttons_height = switcher->priv->buttons_height_request;
362 
363     GTK_WIDGET_CLASS (gdl_switcher_parent_class)->get_preferred_height (GTK_WIDGET (switcher), &min_height, &nat_height);
364 
365     y = allocation->y + allocation->height - V_PADDING - 1;
366 
367     /* Return bottom of the area if there isn't any visible button */
368     for (p = switcher->priv->buttons; p != NULL; p = p->next) if (gtk_widget_get_visible (((Button *)p->data)->button_widget)) break;
369     if (p == NULL)
370         return y;
371 
372     switcher_style = INTERNAL_MODE (switcher);
373     icons_only = (switcher_style == GDL_SWITCHER_STYLE_ICON);
374 
375     /* Figure out the max width and height taking into account visible buttons */
376     optimal_layout_width = H_PADDING;
377     num_btns = 0;
378     for (p = switcher->priv->buttons; p != NULL; p = p->next) {
379         GtkRequisition requisition;
380 
381         button = p->data;
382         if (gtk_widget_get_visible (button->button_widget)) {
383             gtk_widget_get_preferred_size (GTK_WIDGET (button->button_widget),
384                                            &requisition, NULL);
385             optimal_layout_width += requisition.width + H_PADDING;
386             max_btn_height = MAX (max_btn_height, requisition.height);
387             max_btn_width = MAX (max_btn_width, requisition.width);
388             num_btns++;
389         }
390     }
391 
392     /* Figure out how many rows and columns we'll use. */
393     btns_per_row = allocation->width / (max_btn_width + H_PADDING);
394     /* Use at least one column */
395     if (btns_per_row == 0) btns_per_row = 1;
396 
397     /* If all the buttons could fit in the single row, have it so */
398     if (allocation->width >= optimal_layout_width)
399     {
400         btns_per_row = num_btns;
401     }
402     if (!icons_only) {
403         /* If using text buttons, we want to try to have a
404          * completely filled-in grid, but if we can't, we want
405          * the odd row to have just a single button.
406          */
407         while (num_btns % btns_per_row > 1)
408             btns_per_row--;
409     }
410 
411     rows_count = num_btns / btns_per_row;
412     if (num_btns % btns_per_row != 0)
413 	rows_count++;
414 
415     /* Assign visible buttons to rows */
416     rows = g_new0 (GSList *, rows_count);
417 
418     if (!icons_only && num_btns % btns_per_row != 0) {
419         p = switcher->priv->buttons;
420         for (; p != NULL; p = p->next) if (gtk_widget_get_visible (((Button *)p->data)->button_widget)) break;
421         button = p->data;
422         rows [0] = g_slist_append (rows [0], button->button_widget);
423 
424         p = p->next;
425         row_number = p ? 1 : 0;
426     } else {
427         p = switcher->priv->buttons;
428         row_number = 0;
429     }
430 
431     for (; p != NULL; p = p->next) {
432         button = p->data;
433 
434         if (gtk_widget_get_visible (button->button_widget)) {
435             if (g_slist_length (rows [row_number]) == btns_per_row)
436                 row_number ++;
437 
438             rows [row_number] = g_slist_append (rows [row_number],
439                                                 button->button_widget);
440         }
441     }
442 
443     row_last = row_number;
444 
445     /* If there are more than 1 row of buttons, save the current height
446      * requirement for subsequent size requests.
447      */
448     if (row_last > 0)
449     {
450         switcher->priv->buttons_height_request =
451             (row_last + 1) * (max_btn_height + V_PADDING) + 1;
452     } else { /* Otherwize clear it */
453         if (last_buttons_height >= 0) {
454 
455             switcher->priv->buttons_height_request = -1;
456         }
457     }
458 
459     /* If it turns out that we now require smaller height for the buttons
460      * than it was last time, make a resize request to ensure our
461      * size requisition is properly communicated to the parent (otherwise
462      * parent tend to keep assuming the older size).
463      */
464     if (last_buttons_height > switcher->priv->buttons_height_request)
465     {
466         g_idle_add (delayed_resize_switcher, switcher);
467         return -1;
468     }
469 
470     /* Layout the buttons. */
471     for (i = row_last; i >= 0; i --) {
472         int len, extra_width;
473 
474         y -= max_btn_height;
475 
476         /* Check for possible size over flow (taking into account client
477          * requisition
478          */
479         if (y < (allocation->y + min_height)) {
480             /* We have an overflow: Insufficient allocation */
481             if (last_buttons_height < switcher->priv->buttons_height_request) {
482                 /* Request for a new resize */
483                 g_idle_add (delayed_resize_switcher, switcher);
484 
485                 return -1;
486             }
487         }
488         x = H_PADDING + allocation->x;
489         len = g_slist_length (rows[i]);
490         if (switcher_style == GDL_SWITCHER_STYLE_TEXT ||
491             switcher_style == GDL_SWITCHER_STYLE_BOTH)
492             extra_width = (allocation->width - (len * max_btn_width )
493                            - (len * H_PADDING)) / len;
494         else
495             extra_width = 0;
496         for (p = rows [i]; p != NULL; p = p->next) {
497             GtkAllocation child_allocation;
498             GtkStyleContext *style_context;
499             GtkJunctionSides junction = 0;
500 
501             child_allocation.x = x;
502             child_allocation.y = y;
503             if (rows_count == 1 && row_number == 0)
504             {
505                 GtkRequisition child_requisition;
506                 gtk_widget_get_preferred_size (GTK_WIDGET (p->data),
507                                                &child_requisition, NULL);
508                 child_allocation.width = child_requisition.width;
509             }
510             else
511             {
512                 child_allocation.width = max_btn_width + extra_width;
513             }
514             child_allocation.height = max_btn_height;
515 
516             style_context = gtk_widget_get_style_context (GTK_WIDGET (p->data));
517 
518             if (row_last) {
519                 if (i) {
520                     junction |= GTK_JUNCTION_TOP;
521                 }
522                 if (i != row_last) {
523                     junction |= GTK_JUNCTION_BOTTOM;
524                 }
525             }
526 
527             if (p->next) {
528                 junction |= GTK_JUNCTION_RIGHT;
529             }
530 
531             if (p != rows [i]) {
532                 junction |= GTK_JUNCTION_LEFT;
533             }
534 
535             gtk_style_context_set_junction_sides (style_context, junction);
536 
537             gtk_widget_size_allocate (GTK_WIDGET (p->data), &child_allocation);
538 
539             x += child_allocation.width + H_PADDING;
540         }
541     }
542 
543     y -= V_SPACING;
544 
545     for (i = 0; i <= row_last; i ++)
546         g_slist_free (rows [i]);
547     g_free (rows);
548 
549     return y;
550 }
551 
552 static void
do_layout(GdlSwitcher * switcher,GtkAllocation * allocation)553 do_layout (GdlSwitcher *switcher, GtkAllocation* allocation)
554 {
555 
556     GtkAllocation child_allocation;
557     int y;
558 
559     if (switcher->priv->show) {
560         y = layout_buttons (switcher, allocation);
561         if (y < 0) /* Layout did not happen and a resize was requested */
562             return;
563     }
564     else
565         y = allocation->y + allocation->height;
566 
567     /* Place the parent widget.  */
568     child_allocation.x = allocation->x;
569     child_allocation.y = allocation->y;
570     child_allocation.width = allocation->width;
571     child_allocation.height = y - allocation->y;
572 
573     GTK_WIDGET_CLASS (gdl_switcher_parent_class)->size_allocate (GTK_WIDGET (switcher), &child_allocation);
574 }
575 
576 /* GtkContainer methods.  */
577 
578 static void
gdl_switcher_forall(GtkContainer * container,gboolean include_internals,GtkCallback callback,void * callback_data)579 gdl_switcher_forall (GtkContainer *container, gboolean include_internals,
580                      GtkCallback callback, void *callback_data)
581 {
582     GdlSwitcher *switcher =
583         GDL_SWITCHER (container);
584     GSList *p;
585 
586     GTK_CONTAINER_CLASS (gdl_switcher_parent_class)->forall (GTK_CONTAINER (switcher),
587                                                              include_internals,
588                                                              callback, callback_data);
589     if (include_internals) {
590         for (p = switcher->priv->buttons; p != NULL; p = p->next) {
591             GtkWidget *widget = ((Button *) p->data)->button_widget;
592             (* callback) (widget, callback_data);
593         }
594     }
595 }
596 
597 static void
gdl_switcher_remove(GtkContainer * container,GtkWidget * widget)598 gdl_switcher_remove (GtkContainer *container, GtkWidget *widget)
599 {
600     gint switcher_id;
601     GdlSwitcher *switcher =
602         GDL_SWITCHER (container);
603     GSList *p;
604 
605     switcher_id = gdl_switcher_get_page_id (widget);
606     for (p = switcher->priv->buttons; p != NULL; p = p->next) {
607         Button *b = (Button *) p->data;
608 
609         if (b->id == switcher_id) {
610             gtk_widget_unparent (b->button_widget);
611             switcher->priv->buttons =
612                 g_slist_remove_link (switcher->priv->buttons, p);
613             button_free (b);
614             gtk_widget_queue_resize (GTK_WIDGET (switcher));
615             break;
616         }
617     }
618     gdl_switcher_update_lone_button_visibility (switcher);
619     GTK_CONTAINER_CLASS (gdl_switcher_parent_class)->remove (GTK_CONTAINER (switcher), widget);
620 }
621 
622 /* GtkWidget methods.  */
623 
624 static void
gdl_switcher_get_preferred_width(GtkWidget * widget,gint * minimum,gint * natural)625 gdl_switcher_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural)
626 {
627     GdlSwitcher *switcher = GDL_SWITCHER (widget);
628     GSList *p;
629     gint button_height = 0;
630 
631     GTK_WIDGET_CLASS (gdl_switcher_parent_class)->get_preferred_width (GTK_WIDGET (switcher), minimum, natural);
632 
633     if (!switcher->priv->show)
634         return;
635 
636     for (p = switcher->priv->buttons; p != NULL; p = p->next) {
637         Button *button = p->data;
638 
639         if (gtk_widget_get_visible (button->button_widget)) {
640             gint min, nat;
641 
642             gtk_widget_get_preferred_width(button->button_widget, &min, &nat);
643             *minimum = MAX (*minimum, min + 2 * H_PADDING);
644             *natural = MAX (*natural, nat + 2 * H_PADDING);
645 		}
646     }
647 }
648 
649 static void
gdl_switcher_get_preferred_height(GtkWidget * widget,gint * minimum,gint * natural)650 gdl_switcher_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural)
651 {
652     GdlSwitcher *switcher = GDL_SWITCHER (widget);
653     GSList *p;
654     gint button_min = 0;
655     gint button_nat = 0;
656 
657     GTK_WIDGET_CLASS (gdl_switcher_parent_class)->get_preferred_height (GTK_WIDGET (switcher), minimum, natural);
658 
659     if (!switcher->priv->show)
660         return;
661 
662     for (p = switcher->priv->buttons; p != NULL; p = p->next) {
663         Button *button = p->data;
664 
665         if (gtk_widget_get_visible (button->button_widget)) {
666             gint min, nat;
667 
668             gtk_widget_get_preferred_height (button->button_widget, &min, &nat);
669             button_min = MAX (button_min, min + 2 * V_PADDING);
670             button_nat = MAX (button_nat, nat + 2 * V_PADDING);
671         }
672     }
673 
674     if (switcher->priv->buttons_height_request > 0) {
675         *minimum += switcher->priv->buttons_height_request;
676         *natural += switcher->priv->buttons_height_request;
677     } else {
678         *minimum += button_min + V_PADDING;
679         *natural += button_nat + V_PADDING;
680     }
681 }
682 
683 static void
gdl_switcher_size_allocate(GtkWidget * widget,GtkAllocation * allocation)684 gdl_switcher_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
685 {
686     do_layout (GDL_SWITCHER (widget), allocation);
687     gtk_widget_set_allocation (widget, allocation);
688 }
689 
690 static gint
gdl_switcher_draw(GtkWidget * widget,cairo_t * cr)691 gdl_switcher_draw (GtkWidget *widget, cairo_t *cr)
692 {
693     GSList *p;
694     GdlSwitcher *switcher = GDL_SWITCHER (widget);
695     if (switcher->priv->show) {
696         for (p = switcher->priv->buttons; p != NULL; p = p->next) {
697             GtkWidget *button = ((Button *) p->data)->button_widget;
698             gtk_container_propagate_draw (GTK_CONTAINER (widget),
699                                           button, cr);
700         }
701     }
702     return GTK_WIDGET_CLASS (gdl_switcher_parent_class)->draw (widget, cr);
703 }
704 
705 static void
gdl_switcher_map(GtkWidget * widget)706 gdl_switcher_map (GtkWidget *widget)
707 {
708     GSList *p;
709     GdlSwitcher *switcher = GDL_SWITCHER (widget);
710 
711     if (switcher->priv->show) {
712         for (p = switcher->priv->buttons; p != NULL; p = p->next) {
713             GtkWidget *button = ((Button *) p->data)->button_widget;
714             if (gtk_widget_get_visible (button) &&
715                 !gtk_widget_get_mapped (button))
716                 gtk_widget_map (button);
717         }
718     }
719     GTK_WIDGET_CLASS (gdl_switcher_parent_class)->map (widget);
720 }
721 
722 /* GObject methods.  */
723 
724 static void
gdl_switcher_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)725 gdl_switcher_set_property  (GObject      *object,
726                             guint         prop_id,
727                             const GValue *value,
728                             GParamSpec   *pspec)
729 {
730     GdlSwitcher *switcher = GDL_SWITCHER (object);
731 
732     switch (prop_id) {
733         case PROP_SWITCHER_STYLE:
734             gdl_switcher_set_style (switcher, g_value_get_enum (value));
735             break;
736         case PROP_TAB_POS:
737             gdl_switcher_set_tab_pos (switcher, g_value_get_enum (value));
738             break;
739         case PROP_TAB_REORDERABLE:
740             gdl_switcher_set_tab_reorderable (switcher, g_value_get_boolean (value));
741             break;
742         default:
743             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
744             break;
745     }
746 }
747 
748 static void
gdl_switcher_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)749 gdl_switcher_get_property  (GObject      *object,
750                             guint         prop_id,
751                             GValue       *value,
752                             GParamSpec   *pspec)
753 {
754     GdlSwitcher *switcher = GDL_SWITCHER (object);
755 
756     switch (prop_id) {
757         case PROP_SWITCHER_STYLE:
758             g_value_set_enum (value, gdl_switcher_get_style (switcher));
759             break;
760         case PROP_TAB_POS:
761             g_value_set_enum (value, switcher->priv->tab_pos);
762             break;
763         case PROP_TAB_REORDERABLE:
764             g_value_set_enum (value, switcher->priv->tab_reorderable);
765             break;
766         default:
767             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
768             break;
769     }
770 }
771 
772 static void
gdl_switcher_dispose(GObject * object)773 gdl_switcher_dispose (GObject *object)
774 {
775     GdlSwitcherPrivate *priv = GDL_SWITCHER (object)->priv;
776 
777 #if HAVE_GNOME
778     GConfClient *gconf_client = gconf_client_get_default ();
779 
780     if (priv->style_changed_id) {
781         gconf_client_notify_remove (gconf_client, priv->style_changed_id);
782         priv->style_changed_id = 0;
783     }
784     g_object_unref (gconf_client);
785 #endif
786 
787     g_slist_free_full (priv->buttons, (GDestroyNotify)button_free);
788     priv->buttons = NULL;
789 
790     G_OBJECT_CLASS (gdl_switcher_parent_class)->dispose (object);
791 }
792 
793 static void
gdl_switcher_finalize(GObject * object)794 gdl_switcher_finalize (GObject *object)
795 {
796     G_OBJECT_CLASS (gdl_switcher_parent_class)->finalize (object);
797 }
798 
799 /* Signal handlers */
800 
801 static void
gdl_switcher_notify_cb(GObject * g_object,GParamSpec * pspec,GdlSwitcher * switcher)802 gdl_switcher_notify_cb (GObject *g_object, GParamSpec *pspec,
803                         GdlSwitcher *switcher)
804 {
805 }
806 
807 static void
gdl_switcher_switch_page_cb(GtkNotebook * nb,GtkWidget * page_widget,gint page_num,GdlSwitcher * switcher)808 gdl_switcher_switch_page_cb (GtkNotebook *nb, GtkWidget *page_widget,
809                              gint page_num, GdlSwitcher *switcher)
810 {
811     gint             switcher_id;
812 
813     /* Change switcher button */
814     switcher_id = gdl_switcher_get_page_id (page_widget);
815     gdl_switcher_select_button (GDL_SWITCHER (switcher), switcher_id);
816 }
817 
818 static void
gdl_switcher_page_added_cb(GtkNotebook * nb,GtkWidget * page,gint page_num,GdlSwitcher * switcher)819 gdl_switcher_page_added_cb (GtkNotebook *nb, GtkWidget *page,
820                             gint page_num, GdlSwitcher *switcher)
821 {
822     gint         switcher_id;
823 
824     (void)nb;
825     (void)page_num;
826     switcher_id = gdl_switcher_get_page_id (page);
827 
828     gdl_switcher_add_button (GDL_SWITCHER (switcher), NULL, NULL, NULL, NULL,
829                              switcher_id, page);
830     gdl_switcher_select_button (GDL_SWITCHER (switcher), switcher_id);
831 }
832 
833 static void
gdl_switcher_select_page(GdlSwitcher * switcher,gint id)834 gdl_switcher_select_page (GdlSwitcher *switcher, gint id)
835 {
836     GList *children, *node;
837     children = gtk_container_get_children (GTK_CONTAINER (switcher));
838     node = children;
839     while (node)
840     {
841         gint switcher_id;
842         switcher_id = gdl_switcher_get_page_id (GTK_WIDGET (node->data));
843         if (switcher_id == id)
844         {
845             gint page_num;
846             page_num = gtk_notebook_page_num (GTK_NOTEBOOK (switcher),
847                                               GTK_WIDGET (node->data));
848             g_signal_handlers_block_by_func (switcher,
849                                              gdl_switcher_switch_page_cb,
850                                              switcher);
851             gtk_notebook_set_current_page (GTK_NOTEBOOK (switcher), page_num);
852             g_signal_handlers_unblock_by_func (switcher,
853                                                gdl_switcher_switch_page_cb,
854                                                switcher);
855             break;
856         }
857         node = g_list_next (node);
858     }
859     g_list_free (children);
860 }
861 
862 /* Initialization.  */
863 
864 static void
gdl_switcher_class_init(GdlSwitcherClass * klass)865 gdl_switcher_class_init (GdlSwitcherClass *klass)
866 {
867     GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
868     GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
869     GObjectClass *object_class = G_OBJECT_CLASS (klass);
870     static const gchar button_style[] =
871        "* {\n"
872            "outline-width : 1px;\n"
873            "padding: 0;\n"
874        "}";
875 
876     container_class->forall = gdl_switcher_forall;
877     container_class->remove = gdl_switcher_remove;
878 
879     widget_class->get_preferred_width = gdl_switcher_get_preferred_width;
880     widget_class->get_preferred_height = gdl_switcher_get_preferred_height;
881     widget_class->size_allocate = gdl_switcher_size_allocate;
882     widget_class->draw = gdl_switcher_draw;
883     widget_class->map = gdl_switcher_map;
884 
885     object_class->dispose  = gdl_switcher_dispose;
886     object_class->finalize = gdl_switcher_finalize;
887     object_class->set_property = gdl_switcher_set_property;
888     object_class->get_property = gdl_switcher_get_property;
889 
890     g_object_class_install_property (
891         object_class, PROP_SWITCHER_STYLE,
892         g_param_spec_enum ("switcher-style", _("Switcher Style"),
893                            _("Switcher buttons style"),
894                            GDL_TYPE_SWITCHER_STYLE,
895                            GDL_SWITCHER_STYLE_BOTH,
896                            G_PARAM_READWRITE));
897 
898     g_object_class_install_property (
899         object_class, PROP_TAB_POS,
900         g_param_spec_enum ("tab-pos", _("Tab Position"),
901                            _("Which side of the notebook holds the tabs"),
902                            GTK_TYPE_POSITION_TYPE,
903                            GTK_POS_BOTTOM,
904                            G_PARAM_READWRITE));
905 
906     g_object_class_install_property (
907         object_class, PROP_TAB_REORDERABLE,
908         g_param_spec_boolean ("tab-reorderable", _("Tab reorderable"),
909                               _("Whether the tab is reorderable by user action"),
910                               FALSE,
911                               G_PARAM_READWRITE));
912 
913     g_type_class_add_private (object_class, sizeof (GdlSwitcherPrivate));
914 
915     /* set the style */
916     klass->priv = G_TYPE_CLASS_GET_PRIVATE (klass, GDL_TYPE_SWITCHER, GdlSwitcherClassPrivate);
917 
918     klass->priv->css = gtk_css_provider_new ();
919     gtk_css_provider_load_from_data (klass->priv->css, button_style, -1, NULL);
920 }
921 
922 static void
gdl_switcher_init(GdlSwitcher * switcher)923 gdl_switcher_init (GdlSwitcher *switcher)
924 {
925     GdlSwitcherPrivate *priv;
926 
927     gtk_widget_set_has_window (GTK_WIDGET (switcher), FALSE);
928 
929     switcher->priv = G_TYPE_INSTANCE_GET_PRIVATE (switcher,
930                                                   GDL_TYPE_SWITCHER,
931                                                   GdlSwitcherPrivate);
932     priv = switcher->priv;
933 
934     priv->show = TRUE;
935     priv->buttons_height_request = -1;
936     priv->tab_pos = GTK_POS_BOTTOM;
937     priv->tab_reorderable = FALSE;
938 
939     gtk_notebook_set_tab_pos (GTK_NOTEBOOK (switcher), GTK_POS_BOTTOM);
940     gtk_notebook_set_show_tabs (GTK_NOTEBOOK (switcher), FALSE);
941     gtk_notebook_set_show_border (GTK_NOTEBOOK (switcher), FALSE);
942     gdl_switcher_set_style (switcher, GDL_SWITCHER_STYLE_BOTH);
943 
944     /* notebook signals */
945     g_signal_connect (switcher, "switch-page",
946                       G_CALLBACK (gdl_switcher_switch_page_cb), switcher);
947     g_signal_connect (switcher, "page-added",
948                       G_CALLBACK (gdl_switcher_page_added_cb), switcher);
949     g_signal_connect (switcher, "notify::show-tabs",
950                       G_CALLBACK (gdl_switcher_notify_cb), switcher);
951 }
952 
953 /**
954  * gdl_switcher_new:
955  *
956  * Creates a new notebook widget with no pages.
957  *
958  * Returns: The newly created #GdlSwitcher
959  */
960 GtkWidget *
gdl_switcher_new(void)961 gdl_switcher_new (void)
962 {
963     return g_object_new (gdl_switcher_get_type (), NULL);
964 }
965 
966 /**
967  * gdl_switcher_add_button:
968  * @switcher: The #GdlSwitcher to which a button will be added
969  * @label: The label for the button
970  * @tooltips: The tooltip for the button
971  * @stock_id: The stock ID for the button
972  * @pixbuf_icon: The pixbuf to use for the button icon
973  * @switcher_id: The ID of the switcher
974  * @page: The notebook page
975  *
976  * Adds a button to a #GdlSwitcher.  The button icon is taken preferentially
977  * from the @stock_id parameter.  If this is %NULL, then the @pixbuf_icon
978  * parameter is used.  Failing that, the %GTK_STOCK_NEW stock icon is used.
979  * The text label for the button is specified using the @label parameter.  If
980  * it is %NULL then a default incrementally numbered label is used instead.
981  */
982 static void
gdl_switcher_add_button(GdlSwitcher * switcher,const gchar * label,const gchar * tooltips,const gchar * stock_id,GdkPixbuf * pixbuf_icon,gint switcher_id,GtkWidget * page)983 gdl_switcher_add_button (GdlSwitcher *switcher, const gchar *label,
984                          const gchar *tooltips, const gchar *stock_id,
985 			 GdkPixbuf *pixbuf_icon,
986                          gint switcher_id, GtkWidget* page)
987 {
988     GtkWidget *event_box;
989     GtkWidget *button_widget;
990     GtkWidget *hbox;
991     GtkWidget *icon_widget;
992     GtkWidget *label_widget;
993     GtkWidget *arrow;
994 
995     button_widget = gtk_toggle_button_new ();
996     gtk_button_set_relief (GTK_BUTTON(button_widget), GTK_RELIEF_HALF);
997     if (switcher->priv->show && gtk_widget_get_visible (page))
998         gtk_widget_show (button_widget);
999     g_signal_connect (button_widget, "toggled",
1000                       G_CALLBACK (button_toggled_callback),
1001                       switcher);
1002     hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
1003     gtk_container_set_border_width (GTK_CONTAINER (hbox), 0);
1004     gtk_container_add (GTK_CONTAINER (button_widget), hbox);
1005     gtk_widget_show (hbox);
1006 
1007     if (stock_id) {
1008         icon_widget = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
1009     } else if (pixbuf_icon) {
1010         icon_widget = gtk_image_new_from_pixbuf (pixbuf_icon);
1011     } else {
1012         icon_widget = gtk_image_new_from_stock (GTK_STOCK_NEW, GTK_ICON_SIZE_MENU);
1013     }
1014 
1015     gtk_widget_show (icon_widget);
1016 
1017     if (!label) {
1018         gchar *text = g_strdup_printf ("Item %d", switcher_id);
1019         label_widget = gtk_label_new (text);
1020         g_free (text);
1021     } else {
1022         label_widget = gtk_label_new (label);
1023     }
1024     gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
1025     gtk_widget_show (label_widget);
1026 
1027 
1028     gtk_widget_set_tooltip_text (button_widget,
1029                                  tooltips);
1030 
1031     switch (INTERNAL_MODE (switcher)) {
1032     case GDL_SWITCHER_STYLE_TEXT:
1033         gtk_box_pack_start (GTK_BOX (hbox), label_widget, TRUE, TRUE, 0);
1034         break;
1035     case GDL_SWITCHER_STYLE_ICON:
1036         gtk_box_pack_start (GTK_BOX (hbox), icon_widget, TRUE, TRUE, 0);
1037         break;
1038     case GDL_SWITCHER_STYLE_BOTH:
1039     default:
1040         gtk_box_pack_start (GTK_BOX (hbox), icon_widget, FALSE, TRUE, 0);
1041         gtk_box_pack_start (GTK_BOX (hbox), label_widget, TRUE, TRUE, 0);
1042         break;
1043     }
1044     arrow = gtk_arrow_new (GTK_ARROW_UP, GTK_SHADOW_NONE);
1045     gtk_widget_show (arrow);
1046     gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
1047 
1048     switcher->priv->buttons =
1049         g_slist_append (switcher->priv->buttons,
1050                         button_new (button_widget, label_widget,
1051                                     icon_widget,
1052                                     arrow, hbox, switcher_id, page));
1053 
1054     gtk_widget_set_parent (button_widget, GTK_WIDGET (switcher));
1055     gdl_switcher_update_lone_button_visibility (switcher);
1056     gtk_widget_queue_resize (GTK_WIDGET (switcher));
1057 }
1058 
1059 #if 0
1060 static void
1061 gdl_switcher_remove_button (GdlSwitcher *switcher, gint switcher_id)
1062 {
1063     GSList *p;
1064 
1065     for (p = switcher->priv->buttons; p != NULL; p = p->next) {
1066         Button *button = p->data;
1067 
1068         if (button->id == switcher_id)
1069         {
1070             gtk_container_remove (GTK_CONTAINER (switcher),
1071                                   button->button_widget);
1072             break;
1073         }
1074     }
1075     gtk_widget_queue_resize (GTK_WIDGET (switcher));
1076 }
1077 #endif
1078 
1079 static void
gdl_switcher_select_button(GdlSwitcher * switcher,gint switcher_id)1080 gdl_switcher_select_button (GdlSwitcher *switcher, gint switcher_id)
1081 {
1082     update_buttons (switcher, switcher_id);
1083 
1084     /* Select the notebook page associated with this button */
1085     gdl_switcher_select_page (switcher, switcher_id);
1086 }
1087 
1088 
1089 /**
1090  * gdl_switcher_insert_page:
1091  * @switcher: The switcher to which a page will be added
1092  * @page: The page to add to the switcher
1093  * @tab_widget: The  to add to the switcher
1094  * @label: The label text for the button
1095  * @tooltips: The tooltip for the button
1096  * @stock_id: The stock ID for the button icon
1097  * @pixbuf_icon: The pixbuf to use for the button icon
1098  * @position: The position at which to create the page
1099  *
1100  * Adds a page to a #GdlSwitcher.  A button is created in the switcher, with its
1101  * icon taken preferentially from the @stock_id parameter.  If this parameter is
1102  * %NULL, then the @pixbuf_icon parameter is used.  Failing that, the
1103  * %GTK_STOCK_NEW stock icon is used.  The text label for the button is specified
1104  * using the @label parameter.  If it is %NULL then a default incrementally
1105  * numbered label is used instead.
1106  *
1107  * Returns: The index (starting from 0) of the appended page in the notebook, or -1 if function fails
1108  */
1109 gint
gdl_switcher_insert_page(GdlSwitcher * switcher,GtkWidget * page,GtkWidget * tab_widget,const gchar * label,const gchar * tooltips,const gchar * stock_id,GdkPixbuf * pixbuf_icon,gint position)1110 gdl_switcher_insert_page (GdlSwitcher *switcher, GtkWidget *page,
1111                           GtkWidget *tab_widget, const gchar *label,
1112                           const gchar *tooltips, const gchar *stock_id,
1113                           GdkPixbuf *pixbuf_icon, gint position)
1114 {
1115     GtkNotebook *notebook = GTK_NOTEBOOK (switcher);
1116     gint ret_position;
1117     gint switcher_id;
1118     g_signal_handlers_block_by_func (switcher,
1119                                      gdl_switcher_page_added_cb,
1120                                      switcher);
1121 
1122     if (!tab_widget) {
1123         tab_widget = gtk_label_new (label);
1124         if (gtk_widget_get_visible (page)) gtk_widget_show (tab_widget);
1125     }
1126     switcher_id = gdl_switcher_get_page_id (page);
1127     gdl_switcher_add_button (switcher, label, tooltips, stock_id, pixbuf_icon, switcher_id, page);
1128 
1129     ret_position = gtk_notebook_insert_page (notebook, page,
1130                                              tab_widget, position);
1131     gtk_notebook_set_tab_reorderable (notebook, page,
1132                                       switcher->priv->tab_reorderable);
1133     g_signal_handlers_unblock_by_func (switcher,
1134                                        gdl_switcher_page_added_cb,
1135                                        switcher);
1136 
1137     return ret_position;
1138 }
1139 
1140 static void
set_switcher_style_toolbar(GdlSwitcher * switcher,GdlSwitcherStyle switcher_style)1141 set_switcher_style_toolbar (GdlSwitcher *switcher,
1142                             GdlSwitcherStyle switcher_style)
1143 {
1144     GSList *p;
1145 
1146     if (switcher_style == GDL_SWITCHER_STYLE_NONE
1147         || switcher_style == GDL_SWITCHER_STYLE_TABS)
1148         return;
1149 
1150     if (switcher_style == GDL_SWITCHER_STYLE_TOOLBAR)
1151         switcher_style = GDL_SWITCHER_STYLE_BOTH;
1152 
1153     if (switcher_style == INTERNAL_MODE (switcher))
1154         return;
1155 
1156     gtk_notebook_set_show_tabs (GTK_NOTEBOOK (switcher), FALSE);
1157 
1158     for (p = switcher->priv->buttons; p != NULL; p = p->next) {
1159         Button *button = p->data;
1160 
1161         gtk_container_remove (GTK_CONTAINER (button->hbox), button->arrow);
1162 
1163         if (gtk_widget_get_parent (button->icon))
1164             gtk_container_remove (GTK_CONTAINER (button->hbox), button->icon);
1165         if (gtk_widget_get_parent (button->label))
1166             gtk_container_remove (GTK_CONTAINER (button->hbox), button->label);
1167 
1168         switch (switcher_style) {
1169         case GDL_SWITCHER_STYLE_TEXT:
1170             gtk_box_pack_start (GTK_BOX (button->hbox), button->label,
1171                                 TRUE, TRUE, 0);
1172             gtk_widget_show (button->label);
1173             break;
1174 
1175         case GDL_SWITCHER_STYLE_ICON:
1176             gtk_box_pack_start (GTK_BOX (button->hbox), button->icon,
1177                                 TRUE, TRUE, 0);
1178             gtk_widget_show (button->icon);
1179             break;
1180 
1181         case GDL_SWITCHER_STYLE_BOTH:
1182             gtk_box_pack_start (GTK_BOX (button->hbox), button->icon,
1183                                 FALSE, TRUE, 0);
1184             gtk_box_pack_start (GTK_BOX (button->hbox), button->label,
1185                                 TRUE, TRUE, 0);
1186             gtk_widget_show (button->icon);
1187             gtk_widget_show (button->label);
1188             break;
1189 
1190         default:
1191             break;
1192         }
1193 
1194         gtk_box_pack_start (GTK_BOX (button->hbox), button->arrow,
1195                             FALSE, FALSE, 0);
1196     }
1197 
1198     gdl_switcher_set_show_buttons (switcher, TRUE);
1199 }
1200 
1201 static void
gdl_switcher_set_style(GdlSwitcher * switcher,GdlSwitcherStyle switcher_style)1202 gdl_switcher_set_style (GdlSwitcher *switcher, GdlSwitcherStyle switcher_style)
1203 {
1204     if (switcher->priv->switcher_style == switcher_style)
1205         return;
1206 
1207     if (switcher_style == GDL_SWITCHER_STYLE_NONE) {
1208         gdl_switcher_set_show_buttons (switcher, FALSE);
1209         gtk_notebook_set_show_tabs (GTK_NOTEBOOK (switcher), FALSE);
1210     }
1211     else if (switcher_style == GDL_SWITCHER_STYLE_TABS) {
1212         gdl_switcher_set_show_buttons (switcher, FALSE);
1213         gtk_notebook_set_show_tabs (GTK_NOTEBOOK (switcher), TRUE);
1214     }
1215     else
1216         set_switcher_style_toolbar (switcher, switcher_style);
1217 
1218     gtk_widget_queue_resize (GTK_WIDGET (switcher));
1219     switcher->priv->switcher_style = switcher_style;
1220 }
1221 
1222 static void
gdl_switcher_set_show_buttons(GdlSwitcher * switcher,gboolean show)1223 gdl_switcher_set_show_buttons (GdlSwitcher *switcher, gboolean show)
1224 {
1225     GSList *p;
1226 
1227     if (switcher->priv->show == show)
1228         return;
1229 
1230     for (p = switcher->priv->buttons; p != NULL; p = p->next) {
1231         Button *button = p->data;
1232 
1233         if (show && gtk_widget_get_visible (button->page))
1234             gtk_widget_show (button->button_widget);
1235         else
1236             gtk_widget_hide (button->button_widget);
1237     }
1238     gdl_switcher_update_lone_button_visibility (switcher);
1239     switcher->priv->show = show;
1240 
1241     gtk_widget_queue_resize (GTK_WIDGET (switcher));
1242 }
1243 
1244 static GdlSwitcherStyle
gdl_switcher_get_style(GdlSwitcher * switcher)1245 gdl_switcher_get_style (GdlSwitcher *switcher)
1246 {
1247     if (!switcher->priv->show)
1248         return GDL_SWITCHER_STYLE_TABS;
1249     return switcher->priv->switcher_style;
1250 }
1251 
1252 static void
gdl_switcher_set_tab_pos(GdlSwitcher * switcher,GtkPositionType pos)1253 gdl_switcher_set_tab_pos (GdlSwitcher *switcher, GtkPositionType pos)
1254 {
1255     if (switcher->priv->tab_pos == pos)
1256         return;
1257 
1258     gtk_notebook_set_tab_pos (GTK_NOTEBOOK (switcher), pos);
1259 
1260     switcher->priv->tab_pos = pos;
1261 }
1262 
1263 static void
gdl_switcher_set_tab_reorderable(GdlSwitcher * switcher,gboolean reorderable)1264 gdl_switcher_set_tab_reorderable (GdlSwitcher *switcher, gboolean reorderable)
1265 {
1266     GList *children, *l;
1267 
1268     if (switcher->priv->tab_reorderable == reorderable)
1269         return;
1270 
1271     children = gtk_container_get_children (GTK_CONTAINER (switcher));
1272     for (l = children; l != NULL; l->next) {
1273         gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (switcher),
1274                                           GTK_WIDGET (l->data),
1275                                           reorderable);
1276     }
1277     g_list_free (children);
1278 
1279     switcher->priv->tab_reorderable = reorderable;
1280 }
1281