]> Pileus Git - ~andy/gtk/blob - gtk/gtknotebook.c
45796a0a7d14ab5cc0baddc81c5a370f8fdbb8cf
[~andy/gtk] / gtk / gtknotebook.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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 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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "gtknotebook.h"
28 #include "gtksignal.h"
29 #include "gtkmain.h"
30 #include "gtkmenu.h"
31 #include "gtkmenuitem.h"
32 #include "gtklabel.h"
33 #include <gdk/gdkkeysyms.h>
34 #include <stdio.h>
35 #include "gtkintl.h"
36 #include "gtkmarshalers.h"
37 #include "gtkbindings.h"
38
39
40 #define TAB_OVERLAP    2
41 #define TAB_CURVATURE  1
42 #define ARROW_SIZE     12
43 #define ARROW_SPACING  0
44 #define FOCUS_WIDTH    1
45 #define NOTEBOOK_INIT_SCROLL_DELAY (200)
46 #define NOTEBOOK_SCROLL_DELAY      (100)
47
48
49 enum {
50   SWITCH_PAGE,
51   FOCUS_TAB,
52   SELECT_PAGE,
53   CHANGE_CURRENT_PAGE,
54   LAST_SIGNAL
55 };
56
57 enum {
58   STEP_PREV,
59   STEP_NEXT
60 };
61
62 enum {
63   PROP_0,
64   PROP_TAB_POS,
65   PROP_SHOW_TABS,
66   PROP_SHOW_BORDER,
67   PROP_SCROLLABLE,
68   PROP_TAB_BORDER,
69   PROP_TAB_HBORDER,
70   PROP_TAB_VBORDER,
71   PROP_PAGE,
72   PROP_ENABLE_POPUP,
73   PROP_HOMOGENEOUS
74 };
75
76 enum {
77   CHILD_PROP_0,
78   CHILD_PROP_TAB_LABEL,
79   CHILD_PROP_MENU_LABEL,
80   CHILD_PROP_POSITION,
81   CHILD_PROP_TAB_EXPAND,
82   CHILD_PROP_TAB_FILL,
83   CHILD_PROP_TAB_PACK
84 };
85
86 #define GTK_NOTEBOOK_PAGE(_glist_)         ((GtkNotebookPage *)((GList *)(_glist_))->data)
87
88 struct _GtkNotebookPage
89 {
90   GtkWidget *child;
91   GtkWidget *tab_label;
92   GtkWidget *menu_label;
93
94   guint default_menu : 1;       /* If true, we create the menu label ourself */
95   guint default_tab  : 1;       /* If true, we create the tab label ourself */
96   guint expand       : 1;
97   guint fill         : 1;
98   guint pack         : 1;
99
100   GtkRequisition requisition;
101   GtkAllocation allocation;
102
103   guint mnemonic_activate_signal;
104 };
105
106 #ifdef G_DISABLE_CHECKS
107 #define CHECK_FIND_CHILD(notebook, child)                           \
108  gtk_notebook_find_child (notebook, child, G_STRLOC)
109 #else
110 #define CHECK_FIND_CHILD(notebook, child)                           \
111  gtk_notebook_find_child (notebook, child, NULL)
112 #endif
113  
114 /*** GtkNotebook Methods ***/
115 static void gtk_notebook_class_init          (GtkNotebookClass *klass);
116 static void gtk_notebook_init                (GtkNotebook      *notebook);
117
118 static void gtk_notebook_select_page         (GtkNotebook       *notebook,
119                                               gboolean           move_focus);
120 static void gtk_notebook_focus_tab           (GtkNotebook       *notebook,
121                                               GtkNotebookTab     type);
122 static void gtk_notebook_change_current_page (GtkNotebook       *notebook,
123                                               gint               offset);
124
125
126 /*** GtkObject Methods ***/
127 static void gtk_notebook_destroy             (GtkObject        *object);
128 static void gtk_notebook_set_property        (GObject         *object,
129                                               guint            prop_id,
130                                               const GValue    *value,
131                                               GParamSpec      *pspec);
132 static void gtk_notebook_get_property        (GObject         *object,
133                                               guint            prop_id,
134                                               GValue          *value,
135                                               GParamSpec      *pspec);
136
137 /*** GtkWidget Methods ***/
138 static void gtk_notebook_map                 (GtkWidget        *widget);
139 static void gtk_notebook_unmap               (GtkWidget        *widget);
140 static void gtk_notebook_realize             (GtkWidget        *widget);
141 static void gtk_notebook_unrealize           (GtkWidget        *widget);
142 static void gtk_notebook_size_request        (GtkWidget        *widget,
143                                               GtkRequisition   *requisition);
144 static void gtk_notebook_size_allocate       (GtkWidget        *widget,
145                                               GtkAllocation    *allocation);
146 static gint gtk_notebook_expose              (GtkWidget        *widget,
147                                               GdkEventExpose   *event);
148 static gint gtk_notebook_button_press        (GtkWidget        *widget,
149                                               GdkEventButton   *event);
150 static gint gtk_notebook_button_release      (GtkWidget        *widget,
151                                               GdkEventButton   *event);
152 static gint gtk_notebook_enter_notify        (GtkWidget        *widget,
153                                               GdkEventCrossing *event);
154 static gint gtk_notebook_leave_notify        (GtkWidget        *widget,
155                                               GdkEventCrossing *event);
156 static gint gtk_notebook_motion_notify       (GtkWidget        *widget,
157                                               GdkEventMotion   *event);
158 static gint gtk_notebook_focus_in            (GtkWidget        *widget,
159                                               GdkEventFocus    *event);
160 static void gtk_notebook_draw_focus          (GtkWidget        *widget);
161 static gint gtk_notebook_focus               (GtkWidget        *widget,
162                                               GtkDirectionType  direction);
163
164 /*** GtkContainer Methods ***/
165 static void gtk_notebook_set_child_property  (GtkContainer     *container,
166                                               GtkWidget        *child,
167                                               guint             property_id,
168                                               const GValue     *value,
169                                               GParamSpec       *pspec);
170 static void gtk_notebook_get_child_property  (GtkContainer     *container,
171                                               GtkWidget        *child,
172                                               guint             property_id,
173                                               GValue           *value,
174                                               GParamSpec       *pspec);
175 static void gtk_notebook_add                 (GtkContainer     *container,
176                                               GtkWidget        *widget);
177 static void gtk_notebook_remove              (GtkContainer     *container,
178                                               GtkWidget        *widget);
179 static void gtk_notebook_set_focus_child     (GtkContainer     *container,
180                                               GtkWidget        *child);
181 static GtkType gtk_notebook_child_type       (GtkContainer     *container);
182 static void gtk_notebook_forall              (GtkContainer     *container,
183                                               gboolean          include_internals,
184                                               GtkCallback       callback,
185                                               gpointer          callback_data);
186
187 /*** GtkNotebook Private Functions ***/
188 static void gtk_notebook_redraw_tabs         (GtkNotebook      *notebook);
189 static void gtk_notebook_redraw_arrows       (GtkNotebook      *notebook);
190 static void gtk_notebook_focus_changed       (GtkNotebook      *notebook,
191                                               GtkNotebookPage  *old_page);
192 static void gtk_notebook_real_remove         (GtkNotebook      *notebook,
193                                               GList            *list);
194 static void gtk_notebook_update_labels       (GtkNotebook      *notebook);
195 static gint gtk_notebook_timer               (GtkNotebook      *notebook);
196 static gint gtk_notebook_page_compare        (gconstpointer     a,
197                                               gconstpointer     b);
198 static GList* gtk_notebook_find_child        (GtkNotebook      *notebook,
199                                               GtkWidget        *child,
200                                               const gchar      *function);
201 static gint  gtk_notebook_real_page_position (GtkNotebook      *notebook,
202                                               GList            *list);
203 static GList * gtk_notebook_search_page      (GtkNotebook      *notebook,
204                                               GList            *list,
205                                               gint              direction,
206                                               gboolean          find_visible);
207
208 /*** GtkNotebook Drawing Functions ***/
209 static void gtk_notebook_paint               (GtkWidget        *widget,
210                                               GdkRectangle     *area);
211 static void gtk_notebook_draw_tab            (GtkNotebook      *notebook,
212                                               GtkNotebookPage  *page,
213                                               GdkRectangle     *area);
214 static void gtk_notebook_draw_arrow          (GtkNotebook      *notebook,
215                                               guint             arrow);
216
217 /*** GtkNotebook Size Allocate Functions ***/
218 static void gtk_notebook_pages_allocate      (GtkNotebook      *notebook);
219 static void gtk_notebook_page_allocate       (GtkNotebook      *notebook,
220                                               GtkNotebookPage  *page,
221                                               GtkAllocation    *allocation);
222 static void gtk_notebook_calc_tabs           (GtkNotebook      *notebook,
223                                               GList            *start,
224                                               GList           **end,
225                                               gint             *tab_space,
226                                               guint             direction);
227
228 /*** GtkNotebook Page Switch Methods ***/
229 static void gtk_notebook_real_switch_page    (GtkNotebook      *notebook,
230                                               GtkNotebookPage  *page,
231                                               guint             page_num);
232
233 /*** GtkNotebook Page Switch Functions ***/
234 static void gtk_notebook_switch_page         (GtkNotebook      *notebook,
235                                               GtkNotebookPage  *page,
236                                               gint              page_num);
237 static gint gtk_notebook_page_select         (GtkNotebook      *notebook,
238                                               gboolean          move_focus);
239 static void gtk_notebook_switch_focus_tab    (GtkNotebook      *notebook,
240                                               GList            *new_child);
241 static void gtk_notebook_menu_switch_page    (GtkWidget        *widget,
242                                               GtkNotebookPage  *page);
243
244 /*** GtkNotebook Menu Functions ***/
245 static void gtk_notebook_menu_item_create    (GtkNotebook      *notebook,
246                                               GList            *list);
247 static void gtk_notebook_menu_label_unparent (GtkWidget        *widget,
248                                               gpointer          data);
249 static void gtk_notebook_menu_detacher       (GtkWidget        *widget,
250                                               GtkMenu          *menu);
251
252
253 static GtkContainerClass *parent_class = NULL;
254 static guint notebook_signals[LAST_SIGNAL] = { 0 };
255
256 GtkType
257 gtk_notebook_get_type (void)
258 {
259   static GtkType notebook_type = 0;
260
261   if (!notebook_type)
262     {
263       static const GtkTypeInfo notebook_info =
264       {
265         "GtkNotebook",
266         sizeof (GtkNotebook),
267         sizeof (GtkNotebookClass),
268         (GtkClassInitFunc) gtk_notebook_class_init,
269         (GtkObjectInitFunc) gtk_notebook_init,
270         /* reserved_1 */ NULL,
271         /* reserved_2 */ NULL,
272         (GtkClassInitFunc) NULL,
273       };
274
275       notebook_type = gtk_type_unique (gtk_container_get_type (), &notebook_info);
276     }
277
278   return notebook_type;
279 }
280
281 static void
282 gtk_notebook_class_init (GtkNotebookClass *class)
283 {
284   GObjectClass   *gobject_class = G_OBJECT_CLASS (class);
285   GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
286   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
287   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
288   GtkBindingSet *binding_set;
289   
290   parent_class = g_type_class_peek_parent (class);
291
292   gobject_class->set_property = gtk_notebook_set_property;
293   gobject_class->get_property = gtk_notebook_get_property;
294   object_class->destroy = gtk_notebook_destroy;
295
296   widget_class->map = gtk_notebook_map;
297   widget_class->unmap = gtk_notebook_unmap;
298   widget_class->realize = gtk_notebook_realize;
299   widget_class->unrealize = gtk_notebook_unrealize;
300   widget_class->size_request = gtk_notebook_size_request;
301   widget_class->size_allocate = gtk_notebook_size_allocate;
302   widget_class->expose_event = gtk_notebook_expose;
303   widget_class->button_press_event = gtk_notebook_button_press;
304   widget_class->button_release_event = gtk_notebook_button_release;
305   widget_class->enter_notify_event = gtk_notebook_enter_notify;
306   widget_class->leave_notify_event = gtk_notebook_leave_notify;
307   widget_class->motion_notify_event = gtk_notebook_motion_notify;
308   widget_class->focus_in_event = gtk_notebook_focus_in;
309   widget_class->focus = gtk_notebook_focus;
310   
311   container_class->add = gtk_notebook_add;
312   container_class->remove = gtk_notebook_remove;
313   container_class->forall = gtk_notebook_forall;
314   container_class->set_focus_child = gtk_notebook_set_focus_child;
315   container_class->get_child_property = gtk_notebook_get_child_property;
316   container_class->set_child_property = gtk_notebook_set_child_property;
317   container_class->child_type = gtk_notebook_child_type;
318
319   class->switch_page = gtk_notebook_real_switch_page;
320
321   class->focus_tab = gtk_notebook_focus_tab;
322   class->select_page = gtk_notebook_select_page;
323   class->change_current_page = gtk_notebook_change_current_page;
324   
325   g_object_class_install_property (gobject_class,
326                                    PROP_PAGE,
327                                    g_param_spec_int ("page",
328                                                      _("Page"),
329                                                      _("The index of the current page"),
330                                                      0,
331                                                      G_MAXINT,
332                                                      0,
333                                                      G_PARAM_READWRITE));
334   g_object_class_install_property (gobject_class,
335                                    PROP_TAB_POS,
336                                    g_param_spec_enum ("tab_pos",
337                                                       _("Tab Position"),
338                                                       _("Which side of the notebook holds the tabs"),
339                                                       GTK_TYPE_POSITION_TYPE,
340                                                       GTK_POS_TOP,
341                                                       G_PARAM_READWRITE));
342   g_object_class_install_property (gobject_class,
343                                    PROP_TAB_BORDER,
344                                    g_param_spec_uint ("tab_border",
345                                                       _("Tab Border"),
346                                                       _("Width of the border around the tab labels"),
347                                                       0,
348                                                       G_MAXUINT,
349                                                       2,
350                                                       G_PARAM_WRITABLE));
351   g_object_class_install_property (gobject_class,
352                                    PROP_TAB_HBORDER,
353                                    g_param_spec_uint ("tab_hborder",
354                                                       _("Horizontal Tab Border"),
355                                                       _("Width of the horizontal border of tab labels"),
356                                                       0,
357                                                       G_MAXUINT,
358                                                       2,
359                                                       G_PARAM_READWRITE));
360   g_object_class_install_property (gobject_class,
361                                    PROP_TAB_VBORDER,
362                                    g_param_spec_uint ("tab_vborder",
363                                                       _("Vertical Tab Border"),
364                                                       _("Width of the vertical border of tab labels"),
365                                                       0,
366                                                       G_MAXUINT,
367                                                       2,
368                                                       G_PARAM_READWRITE));
369   g_object_class_install_property (gobject_class,
370                                    PROP_SHOW_TABS,
371                                    g_param_spec_boolean ("show_tabs",
372                                                          _("Show Tabs"),
373                                                          _("Whether tabs should be shown or not"),
374                                                          TRUE,
375                                                          G_PARAM_READWRITE));
376   g_object_class_install_property (gobject_class,
377                                    PROP_SHOW_BORDER,
378                                    g_param_spec_boolean ("show_border",
379                                                          _("Show Border"),
380                                                          _("Whether the border should be shown or not"),
381                                                          TRUE,
382                                                          G_PARAM_READWRITE));
383   g_object_class_install_property (gobject_class,
384                                    PROP_SCROLLABLE,
385                                    g_param_spec_boolean ("scrollable",
386                                                          _("Scrollable"),
387                                                          _("If TRUE, scroll arrows are added if there are to many tabs to fit"),
388                                                          FALSE,
389                                                          G_PARAM_READWRITE));
390   g_object_class_install_property (gobject_class,
391                                    PROP_ENABLE_POPUP,
392                                    g_param_spec_boolean ("enable_popup",
393                                                          _("Enable Popup"),
394                                                          _("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
395                                                          FALSE,
396                                                          G_PARAM_READWRITE));
397   g_object_class_install_property (gobject_class,
398                                    PROP_HOMOGENEOUS,
399                                    g_param_spec_boolean ("homogeneous",
400                                                          _("Homogeneous"),
401                                                          _("Whether tabs should have homogeneous sizes"),
402                                                          FALSE,
403                                                          G_PARAM_READWRITE));
404
405   gtk_container_class_install_child_property (container_class,
406                                               CHILD_PROP_TAB_LABEL,
407                                               g_param_spec_string ("tab_label", NULL, NULL,
408                                                                    NULL,
409                                                                    G_PARAM_READWRITE));
410   gtk_container_class_install_child_property (container_class,
411                                               CHILD_PROP_MENU_LABEL,
412                                               g_param_spec_string ("menu_label", NULL, NULL,
413                                                                    NULL,
414                                                                    G_PARAM_READWRITE));
415   gtk_container_class_install_child_property (container_class,
416                                               CHILD_PROP_POSITION,
417                                               g_param_spec_int ("position", NULL, NULL,
418                                                                 -1, G_MAXINT, 0,
419                                                                 G_PARAM_READWRITE));
420   gtk_container_class_install_child_property (container_class,
421                                               CHILD_PROP_TAB_EXPAND,
422                                               g_param_spec_boolean ("tab_expand", NULL, NULL,
423                                                                     TRUE,
424                                                                     G_PARAM_READWRITE));
425   gtk_container_class_install_child_property (container_class,
426                                               CHILD_PROP_TAB_FILL,
427                                               g_param_spec_boolean ("tab_fill", NULL, NULL,
428                                                                     TRUE,
429                                                                     G_PARAM_READWRITE));
430   gtk_container_class_install_child_property (container_class,
431                                               CHILD_PROP_TAB_PACK,
432                                               g_param_spec_enum ("tab_pack", NULL, NULL,
433                                                                  GTK_TYPE_PACK_TYPE, GTK_PACK_START,
434                                                                  G_PARAM_READWRITE));
435   
436   notebook_signals[SWITCH_PAGE] =
437     gtk_signal_new ("switch_page",
438                     GTK_RUN_LAST,
439                     GTK_CLASS_TYPE (object_class),
440                     GTK_SIGNAL_OFFSET (GtkNotebookClass, switch_page),
441                     _gtk_marshal_VOID__POINTER_UINT,
442                     GTK_TYPE_NONE, 2,
443                     GTK_TYPE_POINTER,
444                     GTK_TYPE_UINT);
445   notebook_signals[FOCUS_TAB] = 
446     g_signal_new ("focus_tab",
447                   G_TYPE_FROM_CLASS (object_class),
448                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
449                   G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
450                   NULL, NULL,
451                   _gtk_marshal_VOID__ENUM,
452                   G_TYPE_NONE, 1,
453                   GTK_TYPE_NOTEBOOK_TAB);
454   notebook_signals[SELECT_PAGE] = 
455     g_signal_new ("select_page",
456                   G_TYPE_FROM_CLASS (object_class),
457                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
458                   G_STRUCT_OFFSET (GtkNotebookClass, select_page),
459                   NULL, NULL,
460                   _gtk_marshal_VOID__BOOLEAN,
461                   G_TYPE_NONE, 1,
462                   G_TYPE_BOOLEAN);
463   notebook_signals[CHANGE_CURRENT_PAGE] = 
464     g_signal_new ("change_current_page",
465                   G_TYPE_FROM_CLASS (object_class),
466                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
467                   G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
468                   NULL, NULL,
469                   gtk_marshal_VOID__INT,
470                   G_TYPE_NONE, 1,
471                   G_TYPE_INT);
472   
473   binding_set = gtk_binding_set_by_class (object_class);
474   gtk_binding_entry_add_signal (binding_set,
475                                 GDK_Return, 0,
476                                 "select_page", 1, 
477                                 G_TYPE_BOOLEAN, TRUE);
478   gtk_binding_entry_add_signal (binding_set,
479                                 GDK_KP_Enter, 0,
480                                 "select_page", 1, 
481                                 G_TYPE_BOOLEAN, TRUE);
482   gtk_binding_entry_add_signal (binding_set,
483                                 GDK_space, 0,
484                                 "select_page", 1, 
485                                 G_TYPE_BOOLEAN, FALSE);
486   gtk_binding_entry_add_signal (binding_set,
487                                 GDK_KP_Space, 0,
488                                 "select_page", 1, 
489                                 G_TYPE_BOOLEAN, FALSE);
490   
491   gtk_binding_entry_add_signal (binding_set,
492                                 GDK_Home, 0,
493                                 "focus_tab", 1, 
494                                 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
495   gtk_binding_entry_add_signal (binding_set,
496                                 GDK_KP_Home, 0,
497                                 "focus_tab", 1, 
498                                 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
499   gtk_binding_entry_add_signal (binding_set,
500                                 GDK_End, 0,
501                                 "focus_tab", 1, 
502                                 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
503   gtk_binding_entry_add_signal (binding_set,
504                                 GDK_KP_End, 0,
505                                 "focus_tab", 1, 
506                                 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
507
508   gtk_binding_entry_add_signal (binding_set,
509                                 GDK_Page_Up, GDK_CONTROL_MASK,
510                                 "change_current_page", 1,
511                                 G_TYPE_INT, -1);
512   gtk_binding_entry_add_signal (binding_set,
513                                 GDK_Page_Down, GDK_CONTROL_MASK,
514                                 "change_current_page", 1,
515                                 G_TYPE_INT, 1);
516 }
517
518 static void
519 gtk_notebook_init (GtkNotebook *notebook)
520 {
521   GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS | GTK_RECEIVES_DEFAULT);
522   GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
523
524   notebook->cur_page = NULL;
525   notebook->children = NULL;
526   notebook->first_tab = NULL;
527   notebook->focus_tab = NULL;
528   notebook->event_window = NULL;
529   notebook->menu = NULL;
530
531   notebook->tab_hborder = 2;
532   notebook->tab_vborder = 2;
533
534   notebook->show_tabs = TRUE;
535   notebook->show_border = TRUE;
536   notebook->tab_pos = GTK_POS_TOP;
537   notebook->scrollable = FALSE;
538   notebook->in_child = 0;
539   notebook->click_child = 0;
540   notebook->button = 0;
541   notebook->need_timer = 0;
542   notebook->child_has_focus = FALSE;
543   notebook->have_visible_child = FALSE;
544 }
545
546 static void
547 gtk_notebook_select_page (GtkNotebook *notebook,
548                           gboolean     move_focus)
549 {
550   gtk_notebook_page_select (notebook, move_focus);
551 }
552
553 static void
554 gtk_notebook_focus_tab (GtkNotebook       *notebook,
555                         GtkNotebookTab     type)
556 {
557   GList *list;
558   
559   switch (type)
560     {
561     case GTK_NOTEBOOK_TAB_FIRST:
562       list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
563       if (list)
564         gtk_notebook_switch_focus_tab (notebook, list);
565       break;
566     case GTK_NOTEBOOK_TAB_LAST:
567       list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
568       if (list)
569         gtk_notebook_switch_focus_tab (notebook, list);
570       break;
571     }
572 }
573
574 static void
575 gtk_notebook_change_current_page (GtkNotebook *notebook,
576                                   gint         offset)
577 {
578   GList *current = NULL;
579   
580   if (notebook->cur_page)
581     current = g_list_find (notebook->children, notebook->cur_page);
582
583   while (offset != 0)
584     {
585       current = gtk_notebook_search_page (notebook, current, offset < 0 ? STEP_PREV : STEP_NEXT, TRUE);
586       offset += offset < 0 ? 1 : -1;
587     }
588
589   if (current)
590     gtk_notebook_switch_page (notebook, current->data, -1);
591 }
592
593 /**
594  * gtk_notebook_new:
595  * 
596  * Creates a new #GtkNotebook widget with no pages.
597
598  * Return value: the newly created #GtkNotebook
599  **/
600 GtkWidget*
601 gtk_notebook_new (void)
602 {
603   return GTK_WIDGET (gtk_type_new (gtk_notebook_get_type ()));
604 }
605
606 /* Private GtkObject Methods :
607  * 
608  * gtk_notebook_destroy
609  * gtk_notebook_set_arg
610  * gtk_notebook_get_arg
611  */
612 static void
613 gtk_notebook_destroy (GtkObject *object)
614 {
615   GtkNotebook *notebook;
616   
617   g_return_if_fail (GTK_IS_NOTEBOOK (object));
618
619   notebook = GTK_NOTEBOOK (object);
620
621   if (notebook->menu)
622     gtk_notebook_popup_disable (notebook);
623
624   GTK_OBJECT_CLASS (parent_class)->destroy (object);
625 }
626
627 static void
628 gtk_notebook_set_property (GObject         *object,
629                            guint            prop_id,
630                            const GValue    *value,
631                            GParamSpec      *pspec)
632 {
633   GtkNotebook *notebook;
634
635   notebook = GTK_NOTEBOOK (object);
636
637   switch (prop_id)
638     {
639     case PROP_SHOW_TABS:
640       gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
641       break;
642     case PROP_SHOW_BORDER:
643       gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
644       break;
645     case PROP_SCROLLABLE:
646       gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
647       break;
648     case PROP_ENABLE_POPUP:
649       if (g_value_get_boolean (value))
650         gtk_notebook_popup_enable (notebook);
651       else
652         gtk_notebook_popup_disable (notebook);
653       break;
654     case PROP_HOMOGENEOUS:
655       gtk_notebook_set_homogeneous_tabs (notebook, g_value_get_boolean (value));
656       break;  
657     case PROP_PAGE:
658       gtk_notebook_set_current_page (notebook, g_value_get_int (value));
659       break;
660     case PROP_TAB_POS:
661       gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
662       break;
663     case PROP_TAB_BORDER:
664       gtk_notebook_set_tab_border (notebook, g_value_get_uint (value));
665       break;
666     case PROP_TAB_HBORDER:
667       gtk_notebook_set_tab_hborder (notebook, g_value_get_uint (value));
668       break;
669     case PROP_TAB_VBORDER:
670       gtk_notebook_set_tab_vborder (notebook, g_value_get_uint (value));
671       break;
672     default:
673       break;
674     }
675 }
676
677 static void
678 gtk_notebook_get_property (GObject         *object,
679                            guint            prop_id,
680                            GValue          *value,
681                            GParamSpec      *pspec)
682 {
683   GtkNotebook *notebook;
684
685   notebook = GTK_NOTEBOOK (object);
686
687   switch (prop_id)
688     {
689     case PROP_SHOW_TABS:
690       g_value_set_boolean (value, notebook->show_tabs);
691       break;
692     case PROP_SHOW_BORDER:
693       g_value_set_boolean (value, notebook->show_border);
694       break;
695     case PROP_SCROLLABLE:
696       g_value_set_boolean (value, notebook->scrollable);
697       break;
698     case PROP_ENABLE_POPUP:
699       g_value_set_boolean (value, notebook->menu != NULL);
700       break;
701     case PROP_HOMOGENEOUS:
702       g_value_set_boolean (value, notebook->homogeneous);
703       break;
704     case PROP_PAGE:
705       g_value_set_int (value, gtk_notebook_get_current_page (notebook));
706       break;
707     case PROP_TAB_POS:
708       g_value_set_enum (value, notebook->tab_pos);
709       break;
710     case PROP_TAB_HBORDER:
711       g_value_set_uint (value, notebook->tab_hborder);
712       break;
713     case PROP_TAB_VBORDER:
714       g_value_set_uint (value, notebook->tab_vborder);
715       break;
716     default:
717       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
718       break;
719     }
720 }
721
722 /* Private GtkWidget Methods :
723  * 
724  * gtk_notebook_map
725  * gtk_notebook_unmap
726  * gtk_notebook_realize
727  * gtk_notebook_size_request
728  * gtk_notebook_size_allocate
729  * gtk_notebook_expose
730  * gtk_notebook_button_press
731  * gtk_notebook_button_release
732  * gtk_notebook_enter_notify
733  * gtk_notebook_leave_notify
734  * gtk_notebook_motion_notify
735  * gtk_notebook_focus_in
736  * gtk_notebook_focus_out
737  * gtk_notebook_draw_focus
738  * gtk_notebook_style_set
739  */
740 static gboolean
741 gtk_notebook_get_event_window_position (GtkNotebook  *notebook,
742                                         GdkRectangle *rectangle)
743 {
744   GtkWidget *widget = GTK_WIDGET (notebook);
745   gint border_width = GTK_CONTAINER (notebook)->border_width;
746
747   if (notebook->show_tabs && notebook->children)
748     {
749       if (rectangle)
750         {
751           GtkNotebookPage *page = notebook->children->data;
752
753           rectangle->x = widget->allocation.x + border_width;
754           rectangle->y = widget->allocation.y + border_width;
755           
756           switch (notebook->tab_pos)
757             {
758             case GTK_POS_TOP:
759             case GTK_POS_BOTTOM:
760               rectangle->width = widget->allocation.width - 2 * border_width;
761               rectangle->height = page->requisition.height;
762               if (notebook->tab_pos == GTK_POS_BOTTOM)
763                 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
764               break;
765             case GTK_POS_LEFT:
766             case GTK_POS_RIGHT:
767               rectangle->width = page->requisition.width;
768               rectangle->height = widget->allocation.height - 2 * border_width;
769               if (notebook->tab_pos == GTK_POS_RIGHT)
770                 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
771               break;
772             }
773         }
774
775       return TRUE;
776     }
777   else
778     {
779       if (rectangle)
780         {
781           rectangle->x = rectangle->y = 0;
782           rectangle->width = rectangle->height = 10;
783         }
784     }
785
786   return FALSE;
787 }
788
789 static void
790 gtk_notebook_map (GtkWidget *widget)
791 {
792   GtkNotebook *notebook;
793   GtkNotebookPage *page;
794   GList *children;
795
796   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
797
798   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
799
800   notebook = GTK_NOTEBOOK (widget);
801
802   if (notebook->cur_page && 
803       GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
804       !GTK_WIDGET_MAPPED (notebook->cur_page->child))
805     gtk_widget_map (notebook->cur_page->child);
806
807   if (notebook->scrollable)
808     gtk_notebook_pages_allocate (notebook);
809   else
810     {
811       children = notebook->children;
812
813       while (children)
814         {
815           page = children->data;
816           children = children->next;
817
818           if (page->tab_label &&
819               GTK_WIDGET_VISIBLE (page->tab_label) &&
820               !GTK_WIDGET_MAPPED (page->tab_label))
821             gtk_widget_map (page->tab_label);
822         }
823     }
824
825   if (gtk_notebook_get_event_window_position (notebook, NULL))
826     gdk_window_show_unraised (notebook->event_window);
827 }
828
829 static void
830 gtk_notebook_unmap (GtkWidget *widget)
831 {
832   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
833
834   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
835
836   gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
837
838   GTK_WIDGET_CLASS (parent_class)->unmap (widget);
839 }
840
841 static void
842 gtk_notebook_realize (GtkWidget *widget)
843 {
844   GtkNotebook *notebook;
845   GdkWindowAttr attributes;
846   gint attributes_mask;
847   GdkRectangle event_window_pos;
848
849   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
850
851   notebook = GTK_NOTEBOOK (widget);
852   GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
853
854   gtk_notebook_get_event_window_position (notebook, &event_window_pos);
855   
856   widget->window = gtk_widget_get_parent_window (widget);
857   gdk_window_ref (widget->window);
858   
859   attributes.window_type = GDK_WINDOW_CHILD;
860   attributes.x = event_window_pos.x;
861   attributes.y = event_window_pos.y;
862   attributes.width = event_window_pos.width;
863   attributes.height = event_window_pos.height;
864   attributes.wclass = GDK_INPUT_ONLY;
865   attributes.event_mask = gtk_widget_get_events (widget);
866   attributes.event_mask |= (GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
867                             GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK);
868
869   attributes_mask = GDK_WA_X | GDK_WA_Y;
870
871   notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), 
872                                            &attributes, attributes_mask);
873   gdk_window_set_user_data (notebook->event_window, notebook);
874
875   widget->style = gtk_style_attach (widget->style, widget->window);
876 }
877
878 static void
879 gtk_notebook_unrealize (GtkWidget *widget)
880 {
881   GtkNotebook *notebook;
882
883   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
884
885   notebook = GTK_NOTEBOOK (widget);
886
887   gdk_window_set_user_data (notebook->event_window, NULL);
888   gdk_window_destroy (notebook->event_window);
889   notebook->event_window = NULL;
890
891   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
892     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
893 }
894
895 static void
896 gtk_notebook_size_request (GtkWidget      *widget,
897                            GtkRequisition *requisition)
898 {
899   GtkNotebook *notebook;
900   GtkNotebookPage *page;
901   GList *children;
902   GtkRequisition child_requisition;
903   gboolean switch_page = FALSE;
904   gint vis_pages;
905
906   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
907   g_return_if_fail (requisition != NULL);
908
909   notebook = GTK_NOTEBOOK (widget);
910   widget->requisition.width = 0;
911   widget->requisition.height = 0;
912
913   for (children = notebook->children, vis_pages = 0; children;
914        children = children->next)
915     {
916       page = children->data;
917
918       if (GTK_WIDGET_VISIBLE (page->child))
919         {
920           vis_pages++;
921           gtk_widget_size_request (page->child, &child_requisition);
922           
923           widget->requisition.width = MAX (widget->requisition.width,
924                                            child_requisition.width);
925           widget->requisition.height = MAX (widget->requisition.height,
926                                             child_requisition.height);
927
928           if (notebook->menu && page->menu_label->parent &&
929               !GTK_WIDGET_VISIBLE (page->menu_label->parent))
930             gtk_widget_show (page->menu_label->parent);
931         }
932       else
933         {
934           if (page == notebook->cur_page)
935             switch_page = TRUE;
936           if (notebook->menu && page->menu_label->parent &&
937               GTK_WIDGET_VISIBLE (page->menu_label->parent))
938             gtk_widget_hide (page->menu_label->parent);
939         }
940     }
941
942   if (notebook->show_border || notebook->show_tabs)
943     {
944       widget->requisition.width += widget->style->xthickness * 2;
945       widget->requisition.height += widget->style->ythickness * 2;
946
947       if (notebook->show_tabs)
948         {
949           gint tab_width = 0;
950           gint tab_height = 0;
951           gint tab_max = 0;
952           gint padding;
953           
954           for (children = notebook->children; children;
955                children = children->next)
956             {
957               page = children->data;
958               
959               if (GTK_WIDGET_VISIBLE (page->child))
960                 {
961                   if (!GTK_WIDGET_VISIBLE (page->tab_label))
962                     gtk_widget_show (page->tab_label);
963
964                   gtk_widget_size_request (page->tab_label,
965                                            &child_requisition);
966
967                   page->requisition.width = 
968                     child_requisition.width +
969                     2 * widget->style->xthickness;
970                   page->requisition.height = 
971                     child_requisition.height +
972                     2 * widget->style->ythickness;
973                   
974                   switch (notebook->tab_pos)
975                     {
976                     case GTK_POS_TOP:
977                     case GTK_POS_BOTTOM:
978                       page->requisition.height += 2 * (notebook->tab_vborder +
979                                                        FOCUS_WIDTH);
980                       tab_height = MAX (tab_height, page->requisition.height);
981                       tab_max = MAX (tab_max, page->requisition.width);
982                       break;
983                     case GTK_POS_LEFT:
984                     case GTK_POS_RIGHT:
985                       page->requisition.width += 2 * (notebook->tab_hborder +
986                                                       FOCUS_WIDTH);
987                       tab_width = MAX (tab_width, page->requisition.width);
988                       tab_max = MAX (tab_max, page->requisition.height);
989                       break;
990                     }
991                 }
992               else if (GTK_WIDGET_VISIBLE (page->tab_label))
993                 gtk_widget_hide (page->tab_label);
994             }
995
996           children = notebook->children;
997
998           if (vis_pages)
999             {
1000               switch (notebook->tab_pos)
1001                 {
1002                 case GTK_POS_TOP:
1003                 case GTK_POS_BOTTOM:
1004                   if (tab_height == 0)
1005                     break;
1006
1007                   if (notebook->scrollable && vis_pages > 1 && 
1008                       widget->requisition.width < tab_width)
1009                     tab_height = MAX (tab_height, ARROW_SIZE);
1010
1011                   padding = 2 * (TAB_CURVATURE + FOCUS_WIDTH +
1012                                  notebook->tab_hborder) - TAB_OVERLAP;
1013                   tab_max += padding;
1014                   while (children)
1015                     {
1016                       page = children->data;
1017                       children = children->next;
1018                   
1019                       if (!GTK_WIDGET_VISIBLE (page->child))
1020                         continue;
1021
1022                       if (notebook->homogeneous)
1023                         page->requisition.width = tab_max;
1024                       else
1025                         page->requisition.width += padding;
1026
1027                       tab_width += page->requisition.width;
1028                       page->requisition.height = tab_height;
1029                     }
1030
1031                   if (notebook->scrollable && vis_pages > 1 &&
1032                       widget->requisition.width < tab_width)
1033                     tab_width = tab_max + 2 * (ARROW_SIZE + ARROW_SPACING);
1034
1035                   if (notebook->homogeneous && !notebook->scrollable)
1036                     widget->requisition.width = MAX (widget->requisition.width,
1037                                                      vis_pages * tab_max +
1038                                                      TAB_OVERLAP);
1039                   else
1040                     widget->requisition.width = MAX (widget->requisition.width,
1041                                                      tab_width + TAB_OVERLAP);
1042
1043                   widget->requisition.height += tab_height;
1044                   break;
1045                 case GTK_POS_LEFT:
1046                 case GTK_POS_RIGHT:
1047                   if (tab_width == 0)
1048                     break;
1049
1050                   if (notebook->scrollable && vis_pages > 1 && 
1051                       widget->requisition.height < tab_height)
1052                     tab_width = MAX (tab_width, ARROW_SPACING +2 * ARROW_SIZE);
1053
1054                   padding = 2 * (TAB_CURVATURE + FOCUS_WIDTH +
1055                                  notebook->tab_vborder) - TAB_OVERLAP;
1056                   tab_max += padding;
1057
1058                   while (children)
1059                     {
1060                       page = children->data;
1061                       children = children->next;
1062
1063                       if (!GTK_WIDGET_VISIBLE (page->child))
1064                         continue;
1065
1066                       page->requisition.width   = tab_width;
1067
1068                       if (notebook->homogeneous)
1069                         page->requisition.height = tab_max;
1070                       else
1071                         page->requisition.height += padding;
1072
1073                       tab_height += page->requisition.height;
1074                     }
1075
1076                   if (notebook->scrollable && vis_pages > 1 && 
1077                       widget->requisition.height < tab_height)
1078                     tab_height = tab_max + ARROW_SIZE + ARROW_SPACING;
1079
1080                   widget->requisition.width += tab_width;
1081
1082                   if (notebook->homogeneous && !notebook->scrollable)
1083                     widget->requisition.height =
1084                       MAX (widget->requisition.height,
1085                            vis_pages * tab_max + TAB_OVERLAP);
1086                   else
1087                     widget->requisition.height =
1088                       MAX (widget->requisition.height,
1089                            tab_height + TAB_OVERLAP);
1090
1091                   if (!notebook->homogeneous || notebook->scrollable)
1092                     vis_pages = 1;
1093                   widget->requisition.height = MAX (widget->requisition.height,
1094                                                     vis_pages * tab_max +
1095                                                     TAB_OVERLAP);
1096                   break;
1097                 }
1098             }
1099         }
1100       else
1101         {
1102           for (children = notebook->children; children;
1103                children = children->next)
1104             {
1105               page = children->data;
1106               
1107               if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
1108                 gtk_widget_hide (page->tab_label);
1109             }
1110         }
1111     }
1112
1113   widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
1114   widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
1115
1116   if (switch_page)
1117     {
1118       if (vis_pages)
1119         {
1120           for (children = notebook->children; children;
1121                children = children->next)
1122             {
1123               page = children->data;
1124               if (GTK_WIDGET_VISIBLE (page->child))
1125                 {
1126                   gtk_notebook_switch_page (notebook, page, -1);
1127                   break;
1128                 }
1129             }
1130         }
1131       else if (GTK_WIDGET_VISIBLE (widget))
1132         {
1133           widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
1134           widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
1135         }
1136     }
1137   if (vis_pages && !notebook->cur_page)
1138     {
1139       children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1140       if (children)
1141         {
1142           notebook->first_tab = children;
1143           gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children),-1);
1144         }
1145     }
1146 }
1147
1148 static void
1149 gtk_notebook_size_allocate (GtkWidget     *widget,
1150                             GtkAllocation *allocation)
1151 {
1152   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1153
1154   widget->allocation = *allocation;
1155   if (GTK_WIDGET_REALIZED (widget))
1156     {
1157       GdkRectangle position;
1158
1159       if (gtk_notebook_get_event_window_position (notebook, &position))
1160         gdk_window_move_resize (notebook->event_window,
1161                                 position.x, position.y,
1162                                 position.width, position.height);
1163     }
1164
1165   if (notebook->children)
1166     {
1167       gint border_width = GTK_CONTAINER (widget)->border_width;
1168       GtkNotebookPage *page;
1169       GtkAllocation child_allocation;
1170       GList *children;
1171       
1172       child_allocation.x = widget->allocation.x + border_width;
1173       child_allocation.y = widget->allocation.y + border_width;
1174       child_allocation.width = MAX (1, allocation->width - border_width * 2);
1175       child_allocation.height = MAX (1, allocation->height - border_width * 2);
1176
1177       if (notebook->show_tabs || notebook->show_border)
1178         {
1179           child_allocation.x += widget->style->xthickness;
1180           child_allocation.y += widget->style->ythickness;
1181           child_allocation.width = MAX (1, child_allocation.width -
1182                                         widget->style->xthickness * 2);
1183           child_allocation.height = MAX (1, child_allocation.height -
1184                                          widget->style->ythickness * 2);
1185
1186           if (notebook->show_tabs && notebook->children && notebook->cur_page)
1187             {
1188               switch (notebook->tab_pos)
1189                 {
1190                 case GTK_POS_TOP:
1191                   child_allocation.y += notebook->cur_page->requisition.height;
1192                 case GTK_POS_BOTTOM:
1193                   child_allocation.height =
1194                     MAX (1, child_allocation.height -
1195                          notebook->cur_page->requisition.height);
1196                   break;
1197                 case GTK_POS_LEFT:
1198                   child_allocation.x += notebook->cur_page->requisition.width;
1199                 case GTK_POS_RIGHT:
1200                   child_allocation.width =
1201                     MAX (1, child_allocation.width -
1202                          notebook->cur_page->requisition.width);
1203                   break;
1204                 }
1205             }
1206         }
1207
1208       children = notebook->children;
1209       while (children)
1210         {
1211           page = children->data;
1212           children = children->next;
1213           
1214           if (GTK_WIDGET_VISIBLE (page->child))
1215             gtk_widget_size_allocate (page->child, &child_allocation);
1216         }
1217
1218       gtk_notebook_pages_allocate (notebook);
1219     }
1220 }
1221
1222 static gint
1223 gtk_notebook_expose (GtkWidget      *widget,
1224                      GdkEventExpose *event)
1225 {
1226   GtkNotebook *notebook;
1227   GdkRectangle child_area;
1228    
1229   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1230   g_return_val_if_fail (event != NULL, FALSE);
1231
1232   if (GTK_WIDGET_DRAWABLE (widget))
1233     {
1234       notebook = GTK_NOTEBOOK (widget);
1235
1236       gtk_notebook_paint (widget, &event->area);
1237       if (notebook->show_tabs)
1238         {
1239           if (notebook->cur_page && 
1240               gtk_widget_intersect (notebook->cur_page->tab_label, 
1241                                     &event->area, &child_area))
1242             gtk_notebook_draw_focus (widget);
1243         }
1244
1245       
1246       if (notebook->cur_page)
1247         gtk_container_propagate_expose (GTK_CONTAINER (notebook),
1248                                         notebook->cur_page->child,
1249                                         event);
1250     }
1251
1252   return FALSE;
1253 }
1254
1255 static gboolean
1256 gtk_notebook_show_arrows (GtkNotebook *notebook)
1257 {
1258   gboolean show_arrow = FALSE;
1259   GList *children;
1260   
1261   if (!notebook->scrollable)
1262     return FALSE;
1263
1264   children = notebook->children;
1265   while (children)
1266     {
1267       GtkNotebookPage *page = children->data;
1268
1269       if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
1270         show_arrow = TRUE;
1271
1272       children = children->next;
1273     }
1274
1275   return show_arrow;
1276 }
1277
1278 static void
1279 gtk_notebook_get_arrow_rect (GtkNotebook  *notebook,
1280                              GdkRectangle *rectangle)
1281 {
1282   GdkRectangle event_window_pos;
1283
1284   if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
1285     {
1286       rectangle->width = 2 * ARROW_SIZE + ARROW_SPACING;
1287       rectangle->height = ARROW_SIZE;
1288
1289       switch (notebook->tab_pos)
1290         {
1291         case GTK_POS_LEFT:
1292         case GTK_POS_RIGHT:
1293           rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
1294           rectangle->y = event_window_pos.y + event_window_pos.height - rectangle->height;
1295           break;
1296         case GTK_POS_TOP:
1297         case GTK_POS_BOTTOM:
1298           rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
1299           rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
1300           break;
1301         }
1302     }
1303 }
1304
1305 static GtkArrowType
1306 gtk_notebook_get_arrow (GtkNotebook *notebook,
1307                         gint         x,
1308                         gint         y)
1309 {
1310   GdkRectangle arrow_rect;
1311   GdkRectangle event_window_pos;
1312
1313   if (gtk_notebook_show_arrows (notebook))
1314     {
1315       gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1316       gtk_notebook_get_arrow_rect (notebook, &arrow_rect);
1317       
1318       x -= arrow_rect.x;
1319       y -= arrow_rect.y;
1320       
1321       if (y >= 0 && y < arrow_rect.height)
1322         {
1323           if (x >= 0 && x < ARROW_SIZE + ARROW_SPACING / 2)
1324             return GTK_ARROW_LEFT;
1325           else if (x >= ARROW_SIZE + ARROW_SPACING / 2 && x < arrow_rect.width)
1326             return GTK_ARROW_RIGHT;
1327         }
1328     }
1329       
1330   return 0;
1331 }
1332
1333 static gboolean
1334 gtk_notebook_arrow_button_press (GtkNotebook    *notebook,
1335                                  GtkArrowType    arrow,
1336                                  GdkEventButton *event)
1337 {
1338   GtkWidget *widget = GTK_WIDGET (notebook);
1339   
1340   if (!GTK_WIDGET_HAS_FOCUS (widget))
1341     gtk_widget_grab_focus (widget);
1342   
1343   notebook->button = event->button;
1344   notebook->click_child = arrow;
1345   
1346   if (event->button == 1)
1347     {
1348       GtkDirectionType dir;
1349       if (!notebook->focus_tab ||
1350           gtk_notebook_search_page (notebook, notebook->focus_tab,
1351                                     arrow == GTK_ARROW_LEFT ? STEP_PREV : STEP_NEXT,
1352                                     TRUE))
1353         {
1354           if (notebook->tab_pos == GTK_POS_LEFT ||
1355               notebook->tab_pos == GTK_POS_RIGHT)
1356             dir = (arrow == GTK_ARROW_LEFT) ? GTK_DIR_UP : GTK_DIR_DOWN;
1357           else
1358             dir = (arrow == GTK_ARROW_LEFT) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
1359           gtk_widget_child_focus (widget, dir);
1360         }
1361       
1362       if (!notebook->timer)
1363         {
1364           notebook->timer = gtk_timeout_add 
1365             (NOTEBOOK_INIT_SCROLL_DELAY, 
1366              (GtkFunction) gtk_notebook_timer, (gpointer) notebook);
1367           notebook->need_timer = TRUE;
1368         }
1369     }
1370   else if (event->button == 2)
1371     gtk_notebook_page_select (notebook, TRUE);
1372   else if (event->button == 3)
1373     gtk_notebook_switch_focus_tab (notebook,
1374                                    gtk_notebook_search_page (notebook,
1375                                                              NULL,
1376                                                              arrow == GTK_ARROW_LEFT ? STEP_NEXT : STEP_PREV,
1377                                                              TRUE));
1378   gtk_notebook_redraw_arrows (notebook);
1379
1380   return TRUE;
1381 }
1382
1383 static gboolean
1384 get_widget_coordinates (GtkWidget *widget,
1385                         GdkEvent  *event,
1386                         gint      *x,
1387                         gint      *y)
1388 {
1389   GdkWindow *window = ((GdkEventAny *)event)->window;
1390   gdouble tx, ty;
1391
1392   if (!gdk_event_get_coords (event, &tx, &ty))
1393     return FALSE;
1394
1395   while (window && window != widget->window)
1396     {
1397       gint window_x, window_y;
1398       
1399       gdk_window_get_position (window, &window_x, &window_y);
1400       tx += window_x;
1401       ty += window_y;
1402
1403       window = gdk_window_get_parent (window);
1404     }
1405
1406   if (window)
1407     {
1408       *x = tx;
1409       *y = ty;
1410
1411       return TRUE;
1412     }
1413   else
1414     return FALSE;
1415 }
1416
1417 static gboolean
1418 gtk_notebook_button_press (GtkWidget      *widget,
1419                            GdkEventButton *event)
1420 {
1421   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1422   GtkNotebookPage *page;
1423   GList *children;
1424   GtkArrowType arrow;
1425   gint num;
1426   gint x, y;
1427
1428   if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
1429       notebook->button)
1430     return FALSE;
1431
1432   if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
1433     return FALSE;
1434
1435   arrow = gtk_notebook_get_arrow (notebook, x, y);
1436   if (arrow)
1437     return gtk_notebook_arrow_button_press (notebook, arrow, event);
1438
1439   if (event->button == 3 && notebook->menu)
1440     {
1441       gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL, 
1442                       NULL, NULL, 3, event->time);
1443       return TRUE;
1444     }
1445
1446   num = 0;
1447   children = notebook->children;
1448   while (children)
1449     {
1450       page = children->data;
1451       
1452       if (GTK_WIDGET_VISIBLE (page->child) &&
1453           page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
1454           (x >= page->allocation.x) &&
1455           (y >= page->allocation.y) &&
1456           (x <= (page->allocation.x + page->allocation.width)) &&
1457           (y <= (page->allocation.y + page->allocation.height)))
1458         {
1459           if (page == notebook->cur_page && notebook->focus_tab &&
1460               notebook->focus_tab != children &&
1461               GTK_WIDGET_HAS_FOCUS (notebook))
1462             {
1463               GtkNotebookPage *old_page;
1464               
1465               notebook->child_has_focus = FALSE;
1466               old_page = (GtkNotebookPage *)
1467                 (notebook->focus_tab->data);
1468               gtk_notebook_switch_focus_tab (notebook, children);
1469               gtk_notebook_focus_changed (notebook, old_page);
1470             }
1471           else
1472             {
1473               gtk_notebook_switch_focus_tab (notebook, children);
1474               gtk_widget_grab_focus (widget);
1475               gtk_notebook_switch_page (notebook, page, num);
1476             }
1477           break;
1478         }
1479       children = children->next;
1480       num++;
1481     }
1482   if (!children && !GTK_WIDGET_HAS_FOCUS (widget))
1483     gtk_widget_grab_focus (widget);
1484   
1485   return TRUE;
1486 }
1487
1488 static gint
1489 gtk_notebook_button_release (GtkWidget      *widget,
1490                              GdkEventButton *event)
1491 {
1492   GtkNotebook *notebook;
1493
1494   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1495   g_return_val_if_fail (event != NULL, FALSE);
1496
1497   if (event->type != GDK_BUTTON_RELEASE)
1498     return FALSE;
1499
1500   notebook = GTK_NOTEBOOK (widget);
1501
1502   if (event->button == notebook->button)
1503     {
1504       guint click_child;
1505
1506       if (notebook->timer)
1507         {
1508           gtk_timeout_remove (notebook->timer);
1509           notebook->timer = 0;
1510           notebook->need_timer = FALSE;
1511         }
1512       click_child = notebook->click_child;
1513       notebook->click_child = 0;
1514       notebook->button = 0;
1515       gtk_notebook_redraw_arrows (notebook);
1516
1517       return TRUE;
1518     }
1519   else
1520     return FALSE;
1521 }
1522
1523 static gint
1524 gtk_notebook_enter_notify (GtkWidget        *widget,
1525                            GdkEventCrossing *event)
1526 {
1527   GtkNotebook *notebook;
1528   GtkArrowType arrow;
1529   gint x, y;
1530
1531   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1532   g_return_val_if_fail (event != NULL, FALSE);
1533
1534   notebook = GTK_NOTEBOOK (widget);
1535
1536   if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
1537     return FALSE;
1538
1539   arrow = gtk_notebook_get_arrow (notebook, x, y);
1540
1541   if (arrow != notebook->in_child)
1542     {
1543       notebook->in_child = arrow;
1544       gtk_notebook_redraw_arrows (notebook);
1545
1546       return TRUE;
1547     }
1548
1549   return TRUE;
1550 }
1551
1552 static gint
1553 gtk_notebook_leave_notify (GtkWidget        *widget,
1554                            GdkEventCrossing *event)
1555 {
1556   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1557   GtkArrowType arrow;
1558   gint x, y;
1559
1560   if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
1561     return FALSE;
1562
1563   arrow = gtk_notebook_get_arrow (notebook, x, y);
1564
1565   if (notebook->in_child)
1566     {
1567       notebook->in_child = 0;
1568       gtk_notebook_redraw_arrows (notebook);
1569     }
1570
1571   return TRUE;
1572 }
1573
1574 static gint
1575 gtk_notebook_motion_notify (GtkWidget      *widget,
1576                             GdkEventMotion *event)
1577 {
1578   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1579   GtkArrowType arrow;
1580   gint x, y;
1581   
1582   if (notebook->button)
1583     return FALSE;
1584
1585   if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
1586     return FALSE;
1587
1588   arrow = gtk_notebook_get_arrow (notebook, x, y);
1589
1590   if (arrow != notebook->in_child)
1591     {
1592       notebook->in_child = arrow;
1593       gtk_notebook_redraw_arrows (notebook);
1594     }
1595   
1596   return TRUE;
1597 }
1598
1599 static gint
1600 gtk_notebook_focus_in (GtkWidget     *widget,
1601                        GdkEventFocus *event)
1602 {
1603   GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
1604
1605   return (* GTK_WIDGET_CLASS (parent_class)->focus_in_event) (widget, event);
1606 }
1607
1608 static void
1609 gtk_notebook_draw_focus (GtkWidget *widget)
1610 {
1611   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1612
1613   if (GTK_WIDGET_DRAWABLE (widget) && notebook->show_tabs &&
1614       notebook->focus_tab)
1615     {
1616       GtkNotebookPage *page;
1617       GdkRectangle area;
1618
1619       page = notebook->focus_tab->data;
1620
1621       area.x = page->tab_label->allocation.x - 1;
1622       area.y = page->tab_label->allocation.y - 1;
1623       area.width = page->tab_label->allocation.width + 2;
1624       area.height = page->tab_label->allocation.height + 2;
1625
1626       gtk_notebook_draw_tab (GTK_NOTEBOOK (widget), page, &area);
1627     }
1628 }
1629
1630 /* Private GtkContainer Methods :
1631  * 
1632  * gtk_notebook_set_child_arg
1633  * gtk_notebook_get_child_arg
1634  * gtk_notebook_add
1635  * gtk_notebook_remove
1636  * gtk_notebook_focus
1637  * gtk_notebook_set_focus_child
1638  * gtk_notebook_child_type
1639  * gtk_notebook_forall
1640  */
1641 static void
1642 gtk_notebook_set_child_property (GtkContainer    *container,
1643                                  GtkWidget       *child,
1644                                  guint            property_id,
1645                                  const GValue    *value,
1646                                  GParamSpec      *pspec)
1647 {
1648   gboolean expand;
1649   gboolean fill;
1650   GtkPackType pack_type;
1651
1652   /* not finding child's page is valid for menus or labels */
1653   if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
1654     return;
1655
1656   switch (property_id)
1657     {
1658     case CHILD_PROP_TAB_LABEL:
1659       /* a NULL pointer indicates a default_tab setting, otherwise
1660        * we need to set the associated label
1661        */
1662       gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
1663                                        g_value_get_string (value));
1664       break;
1665     case CHILD_PROP_MENU_LABEL:
1666       gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
1667                                         g_value_get_string (value));
1668       break;
1669     case CHILD_PROP_POSITION:
1670       gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
1671                                   g_value_get_int (value));
1672       break;
1673     case CHILD_PROP_TAB_EXPAND:
1674       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
1675                                             &expand, &fill, &pack_type);
1676       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
1677                                           g_value_get_boolean (value),
1678                                           fill, pack_type);
1679       break;
1680     case CHILD_PROP_TAB_FILL:
1681       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
1682                                             &expand, &fill, &pack_type);
1683       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
1684                                           expand,
1685                                           g_value_get_boolean (value),
1686                                           pack_type);
1687       break;
1688     case CHILD_PROP_TAB_PACK:
1689       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
1690                                             &expand, &fill, &pack_type);
1691       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
1692                                           expand, fill,
1693                                           g_value_get_enum (value));
1694       break;
1695     default:
1696       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
1697       break;
1698     }
1699 }
1700
1701 static void
1702 gtk_notebook_get_child_property (GtkContainer    *container,
1703                                  GtkWidget       *child,
1704                                  guint            property_id,
1705                                  GValue          *value,
1706                                  GParamSpec      *pspec)
1707 {
1708   GList *list;
1709   GtkNotebook *notebook;
1710   GtkWidget *label;
1711   gboolean expand;
1712   gboolean fill;
1713   GtkPackType pack_type;
1714
1715   notebook = GTK_NOTEBOOK (container);
1716
1717   /* not finding child's page is valid for menus or labels */
1718   list = gtk_notebook_find_child (notebook, child, NULL);
1719   if (!list)
1720     {
1721       /* nothing to set on labels or menus */
1722       g_param_value_set_default (pspec, value);
1723       return;
1724     }
1725
1726   switch (property_id)
1727     {
1728     case CHILD_PROP_TAB_LABEL:
1729       label = gtk_notebook_get_tab_label (notebook, child);
1730
1731       if (label && GTK_IS_LABEL (label))
1732         g_value_set_string (value, GTK_LABEL (label)->label);
1733       else
1734         g_value_set_string (value, NULL);
1735       break;
1736     case CHILD_PROP_MENU_LABEL:
1737       label = gtk_notebook_get_menu_label (notebook, child);
1738
1739       if (label && GTK_IS_LABEL (label))
1740         g_value_set_string (value, GTK_LABEL (label)->label);
1741       else
1742         g_value_set_string (value, NULL);
1743       break;
1744     case CHILD_PROP_POSITION:
1745       g_value_set_int (value, g_list_position (notebook->children, list));
1746       break;
1747     case CHILD_PROP_TAB_EXPAND:
1748         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
1749                                               &expand, NULL, NULL);
1750         g_value_set_boolean (value, expand);
1751       break;
1752     case CHILD_PROP_TAB_FILL:
1753         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
1754                                               NULL, &fill, NULL);
1755         g_value_set_boolean (value, fill);
1756       break;
1757     case CHILD_PROP_TAB_PACK:
1758         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
1759                                               NULL, NULL, &pack_type);
1760         g_value_set_enum (value, pack_type);
1761       break;
1762     default:
1763       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
1764       break;
1765     }
1766 }
1767
1768 static void
1769 gtk_notebook_add (GtkContainer *container,
1770                   GtkWidget    *widget)
1771 {
1772   g_return_if_fail (GTK_IS_NOTEBOOK (container));
1773
1774   gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget, 
1775                                  NULL, NULL, -1);
1776 }
1777
1778 static void
1779 gtk_notebook_remove (GtkContainer *container,
1780                      GtkWidget    *widget)
1781 {
1782   GtkNotebook *notebook;
1783   GtkNotebookPage *page;
1784   GList *children;
1785   guint page_num;
1786
1787   g_return_if_fail (GTK_IS_NOTEBOOK (container));
1788   g_return_if_fail (widget != NULL);
1789
1790   notebook = GTK_NOTEBOOK (container);
1791
1792   children = notebook->children;
1793   page_num = 0;
1794   while (children)
1795     {
1796       page = children->data;
1797       if (page->child == widget)
1798         {
1799           gtk_notebook_real_remove (notebook, children);
1800           break;
1801         }
1802       page_num++;
1803       children = children->next;
1804     }
1805 }
1806
1807 static gboolean
1808 focus_tabs_in (GtkNotebook *notebook)
1809 {
1810   if (notebook->cur_page)
1811     {
1812       gtk_widget_grab_focus (GTK_WIDGET (notebook));
1813
1814       gtk_notebook_switch_focus_tab (notebook,
1815                                      g_list_find (notebook->children,
1816                                                   notebook->cur_page));
1817
1818       return TRUE;
1819     }
1820   else
1821     return FALSE;
1822 }
1823
1824 static gboolean
1825 focus_tabs_move (GtkNotebook     *notebook,
1826                  GtkDirectionType direction,
1827                  gint             search_direction)
1828 {
1829   GList *new_page;
1830
1831   new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
1832                                        search_direction, TRUE);
1833   if (!new_page)
1834     new_page = (search_direction == STEP_NEXT) ?
1835                  notebook->children :
1836                  g_list_last (notebook->children);
1837
1838   gtk_notebook_switch_focus_tab (notebook, new_page);
1839   
1840   return TRUE;
1841 }
1842
1843 static gboolean
1844 focus_child_in (GtkNotebook     *notebook,
1845                 GtkDirectionType direction)
1846 {
1847   return gtk_widget_child_focus (notebook->cur_page->child, direction);
1848 }
1849
1850 /* Focus in the notebook can either be on the pages, or on
1851  * the tabs.
1852  */
1853 static gint
1854 gtk_notebook_focus (GtkWidget        *widget,
1855                     GtkDirectionType  direction)
1856 {
1857   GtkWidget *old_focus_child;
1858   GtkNotebook *notebook;
1859   GtkDirectionType effective_direction;
1860
1861   /* Remap the directions into the effective direction it would be for a
1862    * GTK_POS_TOP notebook
1863    */
1864 #define D(rest) GTK_DIR_##rest
1865
1866   static const GtkDirectionType translate_direction[4][6] = {
1867     /* LEFT */   { D(TAB_FORWARD),  D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP),   D(DOWN) },
1868     /* RIGHT */  { D(TAB_BACKWARD), D(TAB_FORWARD),  D(LEFT), D(RIGHT), D(DOWN), D(UP)   },
1869     /* TOP */    { D(TAB_FORWARD),  D(TAB_BACKWARD), D(UP),   D(DOWN),  D(LEFT), D(RIGHT) },
1870     /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD),  D(DOWN), D(UP),    D(LEFT), D(RIGHT) },
1871   };
1872
1873 #undef D  
1874
1875   gboolean widget_is_focus;
1876   GtkContainer *container;
1877
1878   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1879
1880   container = GTK_CONTAINER (widget);
1881   notebook = GTK_NOTEBOOK (container);
1882
1883   widget_is_focus = gtk_widget_is_focus (widget);
1884   old_focus_child = container->focus_child; 
1885
1886   effective_direction = translate_direction[notebook->tab_pos][direction];
1887
1888   if (old_focus_child)          /* Focus on page child */
1889     {
1890       if (gtk_widget_child_focus (old_focus_child, direction))
1891         return TRUE;
1892       
1893       switch (effective_direction)
1894         {
1895         case GTK_DIR_TAB_BACKWARD:
1896         case GTK_DIR_UP:
1897           /* Focus onto the tabs */
1898           if (notebook->show_tabs)
1899             return focus_tabs_in (notebook);
1900           else
1901             return FALSE;
1902         case GTK_DIR_DOWN:
1903         case GTK_DIR_TAB_FORWARD:
1904         case GTK_DIR_LEFT:
1905         case GTK_DIR_RIGHT:
1906           return FALSE;
1907         }
1908     }
1909   else if (widget_is_focus)     /* Focus was on tabs */
1910     {
1911       switch (effective_direction)
1912         {
1913         case GTK_DIR_TAB_BACKWARD:
1914         case GTK_DIR_UP:
1915           return FALSE;
1916         case GTK_DIR_TAB_FORWARD:
1917         case GTK_DIR_DOWN:
1918           return focus_child_in (notebook, direction);
1919         case GTK_DIR_LEFT:
1920           return focus_tabs_move (notebook, direction, STEP_PREV);
1921         case GTK_DIR_RIGHT:
1922           return focus_tabs_move (notebook, direction, STEP_NEXT);
1923         }
1924     }
1925   else /* Focus was not on widget */
1926     {
1927       switch (effective_direction)
1928         {
1929         case GTK_DIR_TAB_FORWARD:
1930         case GTK_DIR_DOWN:
1931           if (focus_tabs_in (notebook))
1932             return TRUE;
1933           if (focus_child_in (notebook, direction))
1934             return TRUE;
1935           return FALSE;
1936         case GTK_DIR_TAB_BACKWARD:
1937         case GTK_DIR_UP:
1938           if (focus_child_in (notebook, direction))
1939             return TRUE;
1940           if (focus_tabs_in (notebook))
1941             return TRUE;
1942           return FALSE;
1943         case GTK_DIR_LEFT:
1944         case GTK_DIR_RIGHT:
1945           return focus_child_in (notebook, direction);
1946         }
1947     }
1948
1949   g_assert_not_reached ();
1950   return FALSE;
1951 }  
1952   
1953 static void
1954 gtk_notebook_set_focus_child (GtkContainer *container,
1955                               GtkWidget    *child)
1956 {
1957   GtkNotebook *notebook;
1958
1959   g_return_if_fail (GTK_IS_NOTEBOOK (container));
1960   
1961   if (child)
1962     {
1963       g_return_if_fail (GTK_IS_WIDGET (child));
1964
1965       notebook = GTK_NOTEBOOK (container);
1966
1967       notebook->child_has_focus = TRUE;
1968       if (!notebook->focus_tab)
1969         {
1970           GList *children;
1971           GtkNotebookPage *page;
1972
1973           children = notebook->children;
1974           while (children)
1975             {
1976               page = children->data;
1977               if (page->child == child || page->tab_label == child)
1978                 gtk_notebook_switch_focus_tab (notebook, children);
1979               children = children->next;
1980             }
1981         }
1982     }
1983   parent_class->set_focus_child (container, child);
1984 }
1985
1986 static void
1987 gtk_notebook_forall (GtkContainer *container,
1988                      gboolean      include_internals,
1989                      GtkCallback   callback,
1990                      gpointer      callback_data)
1991 {
1992   GtkNotebook *notebook;
1993   GList *children;
1994
1995   g_return_if_fail (GTK_IS_NOTEBOOK (container));
1996   g_return_if_fail (callback != NULL);
1997
1998   notebook = GTK_NOTEBOOK (container);
1999
2000   children = notebook->children;
2001   while (children)
2002     {
2003       GtkNotebookPage *page;
2004       
2005       page = children->data;
2006       children = children->next;
2007       (* callback) (page->child, callback_data);
2008       if (include_internals)
2009         {
2010           if (page->tab_label)
2011             (* callback) (page->tab_label, callback_data);
2012           if (page->menu_label)
2013             (* callback) (page->menu_label, callback_data);
2014         }
2015     }
2016 }
2017
2018 static GtkType
2019 gtk_notebook_child_type (GtkContainer     *container)
2020 {
2021   return GTK_TYPE_WIDGET;
2022 }
2023
2024 /* Private GtkNotebook Functions:
2025  *
2026  * gtk_notebook_redraw_tabs
2027  * gtk_notebook_focus_changed
2028  * gtk_notebook_real_remove
2029  * gtk_notebook_update_labels
2030  * gtk_notebook_timer
2031  * gtk_notebook_page_compare
2032  * gtk_notebook_real_page_position
2033  * gtk_notebook_search_page
2034  */
2035 static void
2036 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
2037 {
2038   GtkWidget *widget;
2039   GtkNotebookPage *page;
2040   GdkRectangle redraw_rect;
2041   gint border;
2042
2043   widget = GTK_WIDGET (notebook);
2044   border = GTK_CONTAINER (notebook)->border_width;
2045
2046   if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
2047     return;
2048
2049   page = notebook->first_tab->data;
2050
2051   redraw_rect.x = border;
2052   redraw_rect.y = border;
2053
2054   switch (notebook->tab_pos)
2055     {
2056     case GTK_POS_BOTTOM:
2057       redraw_rect.y = (widget->allocation.height - border -
2058                        page->allocation.height -
2059                        widget->style->ythickness);
2060       if (page != notebook->cur_page)
2061         redraw_rect.y -= widget->style->ythickness;
2062       /* fall through */
2063     case GTK_POS_TOP:
2064       redraw_rect.width = widget->allocation.width - 2 * border;
2065       redraw_rect.height = (page->allocation.height +
2066                             widget->style->ythickness);
2067       if (page != notebook->cur_page)
2068         redraw_rect.height += widget->style->ythickness;
2069       break;
2070     case GTK_POS_RIGHT:
2071       redraw_rect.x = (widget->allocation.width - border -
2072                        page->allocation.width -
2073                        widget->style->xthickness);
2074       if (page != notebook->cur_page)
2075         redraw_rect.x -= widget->style->xthickness;
2076       /* fall through */
2077     case GTK_POS_LEFT:
2078       redraw_rect.width = (page->allocation.width +
2079                            widget->style->xthickness);
2080       redraw_rect.height = widget->allocation.height - 2 * border;
2081       if (page != notebook->cur_page)
2082         redraw_rect.width += widget->style->xthickness;
2083       break;
2084     }
2085
2086   gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
2087 }
2088
2089 static void
2090 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
2091 {
2092   if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
2093     {
2094       GdkRectangle rect;
2095
2096       gtk_notebook_get_arrow_rect (notebook, &rect);
2097       gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window, &rect, FALSE);
2098     }
2099 }
2100
2101 static void
2102 gtk_notebook_focus_changed (GtkNotebook     *notebook,
2103                             GtkNotebookPage *old_page)
2104 {
2105   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
2106
2107   if (GTK_WIDGET_DRAWABLE (notebook) && notebook->show_tabs) 
2108     {
2109       GdkRectangle area;
2110
2111       if (notebook->focus_tab)
2112         {
2113           GtkNotebookPage *page;
2114
2115           page = notebook->focus_tab->data;
2116
2117           area.x = page->tab_label->allocation.x - 1;
2118           area.y = page->tab_label->allocation.y - 1;
2119           area.width = page->tab_label->allocation.width + 2;
2120           area.height = page->tab_label->allocation.height + 2;
2121
2122           gtk_notebook_draw_tab (notebook, page, &area);
2123         }
2124
2125       if (old_page)
2126         {
2127           area.x = old_page->tab_label->allocation.x - 1;
2128           area.y = old_page->tab_label->allocation.y - 1;
2129           area.width = old_page->tab_label->allocation.width + 2;
2130           area.height = old_page->tab_label->allocation.height + 2;
2131
2132           gtk_notebook_draw_tab (notebook, old_page, &area);
2133         }
2134     }
2135 }
2136
2137 static gint
2138 gtk_notebook_timer (GtkNotebook *notebook)
2139 {
2140   gboolean retval = FALSE;
2141
2142   GDK_THREADS_ENTER ();
2143   
2144   if (notebook->timer)
2145     {
2146       if (notebook->click_child == GTK_ARROW_LEFT)
2147         {
2148           if (!notebook->focus_tab ||
2149               gtk_notebook_search_page (notebook, notebook->focus_tab,
2150                                         STEP_PREV, TRUE))
2151             gtk_widget_child_focus (GTK_WIDGET (notebook), GTK_DIR_LEFT);
2152         }
2153       else if (notebook->click_child == GTK_ARROW_RIGHT)
2154         {
2155           if (!notebook->focus_tab ||
2156               gtk_notebook_search_page (notebook, notebook->focus_tab,
2157                                         STEP_NEXT, TRUE))
2158             gtk_widget_child_focus (GTK_WIDGET (notebook), GTK_DIR_RIGHT);
2159         }
2160       if (notebook->need_timer) 
2161         {
2162           notebook->need_timer = FALSE;
2163           notebook->timer = gtk_timeout_add (NOTEBOOK_SCROLL_DELAY,
2164                                              (GtkFunction) gtk_notebook_timer, 
2165                                              (gpointer) notebook);
2166         }
2167       else
2168         retval = TRUE;
2169     }
2170
2171   GDK_THREADS_LEAVE ();
2172
2173   return retval;
2174 }
2175
2176 static gint
2177 gtk_notebook_page_compare (gconstpointer a,
2178                            gconstpointer b)
2179 {
2180   return (((GtkNotebookPage *) a)->child != b);
2181 }
2182
2183 static GList*
2184 gtk_notebook_find_child (GtkNotebook *notebook,
2185                          GtkWidget   *child,
2186                          const gchar *function)
2187 {
2188   GList *list = g_list_find_custom (notebook->children, child,
2189                                     gtk_notebook_page_compare);
2190
2191 #ifndef G_DISABLE_CHECKS
2192   if (!list && function)
2193     g_warning ("%s: unable to find child %p in notebook %p",
2194                function, child, notebook);
2195 #endif
2196
2197   return list;
2198 }
2199
2200 static void
2201 gtk_notebook_remove_tab_label (GtkNotebook     *notebook,
2202                                GtkNotebookPage *page)
2203 {
2204   if (page->tab_label)
2205     {
2206       if (page->mnemonic_activate_signal)
2207         gtk_signal_disconnect (page->tab_label,
2208                                page->mnemonic_activate_signal);
2209       page->mnemonic_activate_signal = 0;
2210
2211       gtk_widget_unparent (page->tab_label);
2212     }
2213 }
2214
2215 static void
2216 gtk_notebook_real_remove (GtkNotebook *notebook,
2217                           GList       *list)
2218 {
2219   GtkNotebookPage *page;
2220   GList * next_list;
2221   gint need_resize = FALSE;
2222
2223   next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
2224   if (!next_list)
2225     next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
2226
2227   if (notebook->cur_page == list->data)
2228     { 
2229       notebook->cur_page = NULL;
2230       if (next_list)
2231         gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
2232     }
2233
2234   if (list == notebook->first_tab)
2235     notebook->first_tab = next_list;
2236   if (list == notebook->focus_tab)
2237     gtk_notebook_switch_focus_tab (notebook, next_list);
2238
2239   page = list->data;
2240
2241   if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
2242     need_resize = TRUE;
2243
2244   gtk_widget_unparent (page->child);
2245
2246   gtk_notebook_remove_tab_label (notebook, page);
2247   
2248   if (notebook->menu)
2249     {
2250       gtk_container_remove (GTK_CONTAINER (notebook->menu), 
2251                             page->menu_label->parent);
2252       gtk_widget_queue_resize (notebook->menu);
2253     }
2254   if (!page->default_menu)
2255     gtk_widget_unref (page->menu_label);
2256   
2257   notebook->children = g_list_remove_link (notebook->children, list);
2258   g_list_free (list);
2259   g_free (page);
2260
2261   if (!notebook->children && notebook->show_tabs &&
2262       GTK_WIDGET_MAPPED (notebook))
2263     gdk_window_hide (notebook->event_window);
2264
2265   gtk_notebook_update_labels (notebook);
2266   if (need_resize)
2267     gtk_widget_queue_resize (GTK_WIDGET (notebook));
2268 }
2269
2270 static void
2271 gtk_notebook_update_labels (GtkNotebook *notebook)
2272 {
2273   GtkNotebookPage *page;
2274   GList *list;
2275   gchar string[32];
2276   gint page_num = 1;
2277
2278   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
2279        list;
2280        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
2281     {
2282       page = list->data;
2283       g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
2284       if (notebook->show_tabs)
2285         {
2286           if (page->default_tab)
2287             {
2288               if (!page->tab_label)
2289                 {
2290                   page->tab_label = gtk_label_new (string);
2291                   gtk_widget_set_parent (page->tab_label,
2292                                          GTK_WIDGET (notebook));
2293                 }
2294               else
2295                 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
2296             }
2297
2298           if (GTK_WIDGET_VISIBLE (page->child) &&
2299               !GTK_WIDGET_VISIBLE (page->tab_label))
2300             gtk_widget_show (page->tab_label);
2301           else if (!GTK_WIDGET_VISIBLE (page->child) &&
2302                    GTK_WIDGET_VISIBLE (page->tab_label))
2303             gtk_widget_hide (page->tab_label);
2304         }
2305       if (notebook->menu && page->default_menu)
2306         {
2307           if (page->tab_label && GTK_IS_LABEL (page->tab_label))
2308             gtk_label_set_text (GTK_LABEL (page->menu_label),
2309                            GTK_LABEL (page->tab_label)->label);
2310           else
2311             gtk_label_set_text (GTK_LABEL (page->menu_label), string);
2312         }
2313     }  
2314 }
2315
2316 static gint
2317 gtk_notebook_real_page_position (GtkNotebook *notebook,
2318                                  GList       *list)
2319 {
2320   GList *work;
2321   gint count_start;
2322
2323   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
2324   g_return_val_if_fail (list != NULL, -1);
2325
2326   for (work = notebook->children, count_start = 0;
2327        work && work != list; work = work->next)
2328     if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
2329       count_start++;
2330
2331   if (!work)
2332     return -1;
2333
2334   if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
2335     return count_start;
2336
2337   return (count_start + g_list_length (list) - 1);
2338 }
2339
2340 static GList *
2341 gtk_notebook_search_page (GtkNotebook *notebook,
2342                           GList       *list,
2343                           gint         direction,
2344                           gboolean     find_visible)
2345 {
2346   GtkNotebookPage *page = NULL;
2347   GList *old_list = NULL;
2348   gint flag = 0;
2349
2350   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
2351
2352   switch (direction)
2353     {
2354     case STEP_PREV:
2355       flag = GTK_PACK_END;
2356       break;
2357
2358     case STEP_NEXT:
2359       flag = GTK_PACK_START;
2360       break;
2361     }
2362
2363   if (list)
2364     page = list->data;
2365
2366   if (!page || page->pack == flag)
2367     {
2368       if (list)
2369         {
2370           old_list = list;
2371           list = list->next;
2372         }
2373       else
2374         list = notebook->children;
2375
2376       while (list)
2377         {
2378           page = list->data;
2379           if (page->pack == flag &&
2380               (!find_visible || GTK_WIDGET_VISIBLE (page->child)))
2381             return list;
2382           old_list = list;
2383           list = list->next;
2384         }
2385       list = old_list;
2386     }
2387   else
2388     {
2389       old_list = list;
2390       list = list->prev;
2391     }
2392   while (list)
2393     {
2394       page = list->data;
2395       if (page->pack != flag &&
2396           (!find_visible || GTK_WIDGET_VISIBLE (page->child)))
2397         return list;
2398       old_list = list;
2399       list = list->prev;
2400     }
2401   return NULL;
2402 }
2403
2404 /* Private GtkNotebook Drawing Functions:
2405  *
2406  * gtk_notebook_paint
2407  * gtk_notebook_draw_tab
2408  * gtk_notebook_draw_arrow
2409  */
2410 static void
2411 gtk_notebook_paint (GtkWidget    *widget,
2412                     GdkRectangle *area)
2413 {
2414   GtkNotebook *notebook;
2415   GtkNotebookPage *page;
2416   GList *children;
2417   gboolean showarrow;
2418   gint width, height;
2419   gint x, y;
2420   gint border_width = GTK_CONTAINER (widget)->border_width;
2421   gint gap_x = 0, gap_width = 0;
2422    
2423   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
2424   g_return_if_fail (area != NULL);
2425
2426   if (!GTK_WIDGET_DRAWABLE (widget))
2427     return;
2428
2429   notebook = GTK_NOTEBOOK (widget);
2430
2431   if ((!notebook->show_tabs && !notebook->show_border) ||
2432       !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
2433     return;
2434
2435   x = widget->allocation.x + border_width;
2436   y = widget->allocation.y + border_width;
2437   width = widget->allocation.width - border_width * 2;
2438   height = widget->allocation.height - border_width * 2;
2439
2440   if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
2441     {
2442       gtk_paint_box (widget->style, widget->window,
2443                      GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2444                      area, widget, "notebook",
2445                      x, y, width, height);
2446       return;
2447     }
2448
2449
2450   if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
2451     {
2452       page = notebook->first_tab->data;
2453
2454       switch (notebook->tab_pos)
2455         {
2456         case GTK_POS_TOP:
2457           y += page->allocation.height + widget->style->ythickness;
2458         case GTK_POS_BOTTOM:
2459           height -= page->allocation.height + widget->style->ythickness;
2460           break;
2461         case GTK_POS_LEFT:
2462           x += page->allocation.width + widget->style->xthickness;
2463         case GTK_POS_RIGHT:
2464           width -= page->allocation.width + widget->style->xthickness;
2465           break;
2466         }
2467       gtk_paint_box (widget->style, widget->window,
2468                      GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2469                      area, widget, "notebook",
2470                      x, y, width, height);
2471     }
2472   else
2473     {
2474       switch (notebook->tab_pos)
2475         {
2476         case GTK_POS_TOP:
2477           y += notebook->cur_page->allocation.height;
2478         case GTK_POS_BOTTOM:
2479           height -= notebook->cur_page->allocation.height;
2480           break;
2481         case GTK_POS_LEFT:
2482           x += notebook->cur_page->allocation.width;
2483         case GTK_POS_RIGHT:
2484           width -= notebook->cur_page->allocation.width;
2485           break;
2486         }
2487
2488       switch (notebook->tab_pos)
2489         {
2490         case GTK_POS_TOP:
2491         case GTK_POS_BOTTOM:
2492           gap_x = (notebook->cur_page->allocation.x - widget->allocation.x - border_width);
2493           gap_width = notebook->cur_page->allocation.width;
2494           break;
2495         case GTK_POS_LEFT:
2496         case GTK_POS_RIGHT:
2497           gap_x = (notebook->cur_page->allocation.y - widget->allocation.y - border_width);
2498           gap_width = notebook->cur_page->allocation.height;
2499           break;
2500         }
2501       gtk_paint_box_gap(widget->style, widget->window,
2502                         GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2503                         area, widget, "notebook",
2504                         x, y, width, height,
2505                         notebook->tab_pos, gap_x, gap_width);
2506     }
2507
2508   showarrow = FALSE;
2509   children = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
2510   while (children)
2511     {
2512       page = children->data;
2513       children = gtk_notebook_search_page (notebook, children,
2514                                            STEP_PREV, TRUE);
2515       if (!GTK_WIDGET_VISIBLE (page->child))
2516         continue;
2517       if (!GTK_WIDGET_MAPPED (page->tab_label))
2518         showarrow = TRUE;
2519       else if (page != notebook->cur_page)
2520         gtk_notebook_draw_tab (notebook, page, area);
2521     }
2522
2523   if (showarrow && notebook->scrollable) 
2524     {
2525       gtk_notebook_draw_arrow (notebook, GTK_ARROW_LEFT);
2526       gtk_notebook_draw_arrow (notebook, GTK_ARROW_RIGHT);
2527     }
2528   gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
2529 }
2530
2531 static void
2532 gtk_notebook_draw_tab (GtkNotebook     *notebook,
2533                        GtkNotebookPage *page,
2534                        GdkRectangle    *area)
2535 {
2536   GdkRectangle child_area;
2537   GdkRectangle page_area;
2538   GtkStateType state_type;
2539   GtkPositionType gap_side;
2540   
2541   g_return_if_fail (notebook != NULL);
2542   g_return_if_fail (page != NULL);
2543   g_return_if_fail (area != NULL);
2544
2545   if (!GTK_WIDGET_MAPPED (page->tab_label) ||
2546       (page->allocation.width == 0) || (page->allocation.height == 0))
2547     return;
2548
2549   page_area.x = page->allocation.x;
2550   page_area.y = page->allocation.y;
2551   page_area.width = page->allocation.width;
2552   page_area.height = page->allocation.height;
2553
2554   if (gdk_rectangle_intersect (&page_area, area, &child_area))
2555     {
2556       GtkWidget *widget;
2557
2558       widget = GTK_WIDGET (notebook);
2559       gap_side = 0;
2560       switch (notebook->tab_pos)
2561         {
2562         case GTK_POS_TOP:
2563           gap_side = GTK_POS_BOTTOM;
2564           break;
2565         case GTK_POS_BOTTOM:
2566           gap_side = GTK_POS_TOP;
2567           break;
2568         case GTK_POS_LEFT:
2569           gap_side = GTK_POS_RIGHT;
2570           break;
2571         case GTK_POS_RIGHT:
2572           gap_side = GTK_POS_LEFT;
2573           break;
2574         }
2575       
2576       if (notebook->cur_page == page)
2577         state_type = GTK_STATE_NORMAL;
2578       else 
2579         state_type = GTK_STATE_ACTIVE;
2580       gtk_paint_extension(widget->style, widget->window,
2581                           state_type, GTK_SHADOW_OUT,
2582                           area, widget, "tab",
2583                           page_area.x, page_area.y,
2584                           page_area.width, page_area.height,
2585                           gap_side);
2586       if ((GTK_WIDGET_HAS_FOCUS (widget)) &&
2587           notebook->focus_tab && (notebook->focus_tab->data == page))
2588         {
2589           gtk_paint_focus (widget->style, widget->window,
2590                            area, widget, "tab",
2591                            page->tab_label->allocation.x - 1,
2592                            page->tab_label->allocation.y - 1,
2593                            page->tab_label->allocation.width + 1,
2594                            page->tab_label->allocation.height + 1);
2595         }
2596       if (gtk_widget_intersect (page->tab_label, area, &child_area) &&
2597           GTK_WIDGET_DRAWABLE (page->tab_label))
2598         {
2599           GdkEventExpose expose_event;
2600
2601           /* This is a lame hack since all this code needs rewriting anyhow */
2602           
2603           expose_event.window = page->tab_label->window;
2604           expose_event.area = child_area;
2605           expose_event.region = gdk_region_rectangle (&child_area);
2606           expose_event.send_event = TRUE;
2607           expose_event.type = GDK_EXPOSE;
2608           expose_event.count = 0;
2609
2610           gtk_container_propagate_expose (GTK_CONTAINER (notebook), page->tab_label, &expose_event);
2611
2612           gdk_region_destroy (expose_event.region);
2613         }
2614     }
2615 }
2616
2617 static void
2618 gtk_notebook_draw_arrow (GtkNotebook *notebook,
2619                          guint        arrow)
2620 {
2621   GtkStateType state_type;
2622   GtkShadowType shadow_type;
2623   GtkWidget *widget;
2624   GdkRectangle arrow_rect;
2625
2626   gtk_notebook_get_arrow_rect (notebook, &arrow_rect);
2627
2628   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
2629
2630   widget = GTK_WIDGET(notebook);
2631
2632   if (GTK_WIDGET_DRAWABLE (notebook))
2633     {
2634       if (notebook->in_child == arrow)
2635         {
2636           if (notebook->click_child == arrow)
2637             state_type = GTK_STATE_ACTIVE;
2638           else
2639             state_type = GTK_STATE_PRELIGHT;
2640         }
2641       else
2642         state_type = GTK_STATE_NORMAL;
2643
2644       if (notebook->click_child == arrow)
2645         shadow_type = GTK_SHADOW_IN;
2646       else
2647         shadow_type = GTK_SHADOW_OUT;
2648
2649       if (arrow == GTK_ARROW_LEFT)
2650         {
2651           if (notebook->focus_tab &&
2652               !gtk_notebook_search_page (notebook, notebook->focus_tab,
2653                                          STEP_PREV, TRUE))
2654             {
2655               shadow_type = GTK_SHADOW_ETCHED_IN;
2656               state_type = GTK_STATE_NORMAL;
2657             }
2658
2659           if (notebook->tab_pos == GTK_POS_LEFT ||
2660               notebook->tab_pos == GTK_POS_RIGHT)
2661             arrow = GTK_ARROW_UP;
2662
2663           gtk_paint_arrow (widget->style, widget->window, state_type, 
2664                            shadow_type, NULL, GTK_WIDGET(notebook), "notebook",
2665                            arrow, TRUE, 
2666                            arrow_rect.x, arrow_rect.y, ARROW_SIZE, ARROW_SIZE);
2667         }
2668       else
2669         {
2670           if (notebook->focus_tab &&
2671               !gtk_notebook_search_page (notebook, notebook->focus_tab,
2672                                          STEP_NEXT, TRUE))
2673             {
2674               shadow_type = GTK_SHADOW_ETCHED_IN;
2675               state_type = GTK_STATE_NORMAL;
2676             }
2677
2678           if (notebook->tab_pos == GTK_POS_LEFT ||
2679               notebook->tab_pos == GTK_POS_RIGHT)
2680             arrow = GTK_ARROW_DOWN;
2681
2682            gtk_paint_arrow (widget->style, widget->window, state_type, 
2683                             shadow_type, NULL, GTK_WIDGET(notebook), "notebook",
2684                             arrow, TRUE, arrow_rect.x + ARROW_SIZE + ARROW_SPACING,
2685                             arrow_rect.y, ARROW_SIZE, ARROW_SIZE);
2686         }
2687     }
2688 }
2689
2690 /* Private GtkNotebook Size Allocate Functions:
2691  *
2692  * gtk_notebook_pages_allocate
2693  * gtk_notebook_page_allocate
2694  * gtk_notebook_calc_tabs
2695  */
2696 static void
2697 gtk_notebook_pages_allocate (GtkNotebook   *notebook)
2698 {
2699   GtkWidget    *widget = GTK_WIDGET (notebook);
2700   GtkContainer *container = GTK_CONTAINER (notebook);
2701   GtkNotebookPage *page = NULL;
2702   GtkAllocation *allocation = &widget->allocation;
2703   GtkAllocation child_allocation;
2704   GList *children = NULL;
2705   GList *last_child = NULL;
2706   gboolean showarrow = FALSE;
2707   gint tab_space = 0; 
2708   gint delta; 
2709   gint x = 0;
2710   gint y = 0;
2711   gint i;
2712   gint n = 1;
2713   gint old_fill = 0;
2714   gint new_fill = 0;
2715
2716   if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
2717     return;
2718
2719   child_allocation.x = widget->allocation.x + container->border_width;
2720   child_allocation.y = widget->allocation.y + container->border_width;
2721
2722   switch (notebook->tab_pos)
2723     {
2724     case GTK_POS_BOTTOM:
2725       child_allocation.y = (widget->allocation.y +
2726                             allocation->height -
2727                             notebook->cur_page->requisition.height -
2728                             container->border_width);
2729       /* fall through */
2730     case GTK_POS_TOP:
2731       child_allocation.height = notebook->cur_page->requisition.height;
2732       break;
2733       
2734     case GTK_POS_RIGHT:
2735       child_allocation.x = (widget->allocation.x +
2736                             allocation->width -
2737                             notebook->cur_page->requisition.width -
2738                             container->border_width);
2739       /* fall through */
2740     case GTK_POS_LEFT:
2741       child_allocation.width = notebook->cur_page->requisition.width;
2742       break;
2743     }
2744   
2745   if (notebook->scrollable) 
2746     {
2747       GList *focus_tab;
2748       
2749       children = notebook->children;
2750       
2751       if (notebook->focus_tab)
2752         focus_tab = notebook->focus_tab;
2753       else if (notebook->first_tab)
2754         focus_tab = notebook->first_tab;
2755       else
2756         focus_tab = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2757
2758       switch (notebook->tab_pos)
2759         {
2760         case GTK_POS_TOP:
2761         case GTK_POS_BOTTOM:
2762           while (children)
2763             {
2764               page = children->data;
2765               children = children->next;
2766
2767               if (GTK_WIDGET_VISIBLE (page->child))
2768                 tab_space += page->requisition.width;
2769             }
2770           if (tab_space >
2771               allocation->width - 2 * container->border_width - TAB_OVERLAP) 
2772             {
2773               showarrow = TRUE;
2774               page = focus_tab->data; 
2775
2776               tab_space = (allocation->width - TAB_OVERLAP -
2777                            page->requisition.width -
2778                            2 * (container->border_width + ARROW_SPACING +
2779                                 ARROW_SIZE));
2780               x = (allocation->width - 2 * ARROW_SIZE - ARROW_SPACING -
2781                    container->border_width);
2782
2783               page = notebook->children->data;
2784               if (notebook->tab_pos == GTK_POS_TOP)
2785                 y = (container->border_width +
2786                      (page->requisition.height - ARROW_SIZE) / 2);
2787               else
2788                 y = (allocation->height - container->border_width - 
2789                      ARROW_SIZE - (page->requisition.height - ARROW_SIZE) / 2);
2790             }
2791           break;
2792         case GTK_POS_LEFT:
2793         case GTK_POS_RIGHT:
2794           while (children)
2795             {
2796               page = children->data;
2797               children = children->next;
2798
2799               if (GTK_WIDGET_VISIBLE (page->child))
2800                 tab_space += page->requisition.height;
2801             }
2802           if (tab_space >
2803               (allocation->height - 2 * container->border_width - TAB_OVERLAP))
2804             {
2805               showarrow = TRUE;
2806               page = focus_tab->data; 
2807               tab_space = (allocation->height -
2808                            ARROW_SIZE - ARROW_SPACING - TAB_OVERLAP -
2809                            2 * container->border_width -
2810                            page->requisition.height);
2811               y = allocation->height - container->border_width - ARROW_SIZE;  
2812
2813               page = notebook->children->data;
2814               if (notebook->tab_pos == GTK_POS_LEFT)
2815                 x = (container->border_width +
2816                      (page->requisition.width -
2817                       (2 * ARROW_SIZE - ARROW_SPACING)) / 2); 
2818               else
2819                 x = (allocation->width - container->border_width -
2820                      (2 * ARROW_SIZE - ARROW_SPACING) -
2821                      (page->requisition.width -
2822                       (2 * ARROW_SIZE - ARROW_SPACING)) / 2);
2823             }
2824           break;
2825         }
2826       if (showarrow) /* first_tab <- focus_tab */
2827         { 
2828           if (tab_space <= 0)
2829             {
2830               notebook->first_tab = focus_tab;
2831               last_child = gtk_notebook_search_page (notebook, focus_tab,
2832                                                      STEP_NEXT, TRUE);
2833             }
2834           else
2835             {
2836               children = NULL;
2837               if (notebook->first_tab && notebook->first_tab != focus_tab)
2838                 {
2839                   /* Is first_tab really predecessor of focus_tab  ? */
2840                   page = notebook->first_tab->data;
2841                   if (GTK_WIDGET_VISIBLE (page->child))
2842                     for (children = focus_tab;
2843                          children && children != notebook->first_tab;
2844                          children = gtk_notebook_search_page (notebook,
2845                                                               children,
2846                                                               STEP_PREV,
2847                                                               TRUE));
2848                 }
2849               if (!children)
2850                 notebook->first_tab = focus_tab;
2851               else
2852                 gtk_notebook_calc_tabs (notebook,
2853                                         gtk_notebook_search_page (notebook,
2854                                                                   focus_tab,
2855                                                                   STEP_PREV,
2856                                                                   TRUE), 
2857                                         &(notebook->first_tab), &tab_space,
2858                                         STEP_PREV);
2859
2860               if (tab_space <= 0)
2861                 {
2862                   notebook->first_tab =
2863                     gtk_notebook_search_page (notebook, notebook->first_tab,
2864                                               STEP_NEXT, TRUE);
2865                   if (!notebook->first_tab)
2866                     notebook->first_tab = focus_tab;
2867                   last_child = gtk_notebook_search_page (notebook, focus_tab,
2868                                                          STEP_NEXT, TRUE); 
2869                 }
2870               else /* focus_tab -> end */   
2871                 {
2872                   if (!notebook->first_tab)
2873                     notebook->first_tab = gtk_notebook_search_page (notebook,
2874                                                                     NULL,
2875                                                                     STEP_NEXT,
2876                                                                     TRUE);
2877                   children = NULL;
2878                   gtk_notebook_calc_tabs (notebook,
2879                                           gtk_notebook_search_page (notebook,
2880                                                                     focus_tab,
2881                                                                     STEP_NEXT,
2882                                                                     TRUE),
2883                                           &children, &tab_space, STEP_NEXT);
2884
2885                   if (tab_space <= 0) 
2886                     last_child = children;
2887                   else /* start <- first_tab */
2888                     {
2889                       last_child = NULL;
2890                       children = NULL;
2891                       gtk_notebook_calc_tabs
2892                         (notebook,
2893                          gtk_notebook_search_page (notebook,
2894                                                    notebook->first_tab,
2895                                                    STEP_PREV,
2896                                                    TRUE),
2897                          &children, &tab_space, STEP_PREV);
2898                       notebook->first_tab = gtk_notebook_search_page(notebook,
2899                                                                      children,
2900                                                                      STEP_NEXT,
2901                                                                      TRUE);
2902                     }
2903                 }
2904             }
2905
2906           if (tab_space < 0) 
2907             {
2908               tab_space = -tab_space;
2909               n = 0;
2910               for (children = notebook->first_tab;
2911                    children && children != last_child;
2912                    children = gtk_notebook_search_page (notebook, children,
2913                                                         STEP_NEXT, TRUE))
2914                 n++;
2915             }
2916           else 
2917             tab_space = 0;
2918
2919           /*unmap all non-visible tabs*/
2920           for (children = gtk_notebook_search_page (notebook, NULL,
2921                                                     STEP_NEXT, TRUE);
2922                children && children != notebook->first_tab;
2923                children = gtk_notebook_search_page (notebook, children,
2924                                                     STEP_NEXT, TRUE))
2925             {
2926               page = children->data;
2927               if (page->tab_label)
2928                 gtk_widget_set_child_visible (page->tab_label, FALSE);
2929             }
2930           for (children = last_child; children;
2931                children = gtk_notebook_search_page (notebook, children,
2932                                                     STEP_NEXT, TRUE))
2933             {
2934               page = children->data;
2935               if (page->tab_label)
2936                 gtk_widget_set_child_visible (page->tab_label, FALSE);
2937             }
2938         }
2939       else /* !showarrow */
2940         {
2941           notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
2942                                                           STEP_NEXT, TRUE);
2943           tab_space = 0;
2944         }
2945     }
2946
2947   if (!showarrow)
2948     {
2949       gint c = 0;
2950
2951       n = 0;
2952       children = notebook->children;
2953       switch (notebook->tab_pos)
2954         {
2955         case GTK_POS_TOP:
2956         case GTK_POS_BOTTOM:
2957           while (children)
2958             {
2959               page = children->data;
2960               children = children->next;
2961
2962               if (GTK_WIDGET_VISIBLE (page->child))
2963                 {
2964                   c++;
2965                   tab_space += page->requisition.width;
2966                   if (page->expand)
2967                     n++;
2968                 }
2969             }
2970           tab_space -= allocation->width;
2971           break;
2972         case GTK_POS_LEFT:
2973         case GTK_POS_RIGHT:
2974           while (children)
2975             {
2976               page = children->data;
2977               children = children->next;
2978
2979               if (GTK_WIDGET_VISIBLE (page->child))
2980                 {
2981                   c++;
2982                   tab_space += page->requisition.height;
2983                   if (page->expand)
2984                     n++;
2985                 }
2986             }
2987           tab_space -= allocation->height;
2988         }
2989       tab_space += 2 * container->border_width + TAB_OVERLAP;
2990       tab_space *= -1;
2991       notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
2992                                                       STEP_NEXT, TRUE);
2993       if (notebook->homogeneous && n)
2994         n = c;
2995     }
2996   
2997   children = notebook->first_tab;
2998   i = 1;
2999   while (children)
3000     {
3001       if (children == last_child)
3002         {
3003           /* FIXME double check */
3004           goto done;
3005         }
3006
3007       page = children->data;
3008       if (!showarrow && page->pack != GTK_PACK_START)
3009         break;
3010       children = gtk_notebook_search_page (notebook, children, STEP_NEXT,TRUE);
3011       
3012       delta = 0;
3013       if (n && (showarrow || page->expand || notebook->homogeneous))
3014         {
3015           new_fill = (tab_space * i++) / n;
3016           delta = new_fill - old_fill;
3017           old_fill = new_fill;
3018         }
3019       
3020       switch (notebook->tab_pos)
3021         {
3022         case GTK_POS_TOP:
3023         case GTK_POS_BOTTOM:
3024           child_allocation.width = (page->requisition.width +
3025                                     TAB_OVERLAP + delta);
3026           break;
3027         case GTK_POS_LEFT:
3028         case GTK_POS_RIGHT:
3029           child_allocation.height = (page->requisition.height +
3030                                      TAB_OVERLAP + delta);
3031           break;
3032         }
3033
3034       gtk_notebook_page_allocate (notebook, page, &child_allocation);
3035           
3036       switch (notebook->tab_pos)
3037         {
3038         case GTK_POS_TOP:
3039         case GTK_POS_BOTTOM:
3040           child_allocation.x += child_allocation.width - TAB_OVERLAP;
3041           break;
3042         case GTK_POS_LEFT:
3043         case GTK_POS_RIGHT:
3044           child_allocation.y += child_allocation.height - TAB_OVERLAP;
3045           break;
3046         }
3047
3048       if (page->tab_label)
3049         gtk_widget_set_child_visible (page->tab_label, TRUE);
3050     }
3051
3052   if (children)
3053     {
3054       children = notebook->children;
3055       switch (notebook->tab_pos)
3056         {
3057         case GTK_POS_TOP:
3058         case GTK_POS_BOTTOM:
3059           child_allocation.x = (allocation->x + allocation->width -
3060                                 container->border_width);
3061           break;
3062         case GTK_POS_LEFT:
3063         case GTK_POS_RIGHT:
3064           child_allocation.y = (allocation->y + allocation->height -
3065                                 container->border_width);
3066           break;
3067         }
3068
3069       while (children != last_child)
3070         {
3071           page = children->data;
3072           children = children->next;
3073
3074           if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
3075             continue;
3076
3077           delta = 0;
3078           if (n && (page->expand || notebook->homogeneous))
3079             {
3080               new_fill = (tab_space * i++) / n;
3081               delta = new_fill - old_fill;
3082               old_fill = new_fill;
3083             }
3084
3085           switch (notebook->tab_pos)
3086             {
3087             case GTK_POS_TOP:
3088             case GTK_POS_BOTTOM:
3089               child_allocation.width = (page->requisition.width +
3090                                         TAB_OVERLAP + delta);
3091               child_allocation.x -= child_allocation.width;
3092               break;
3093             case GTK_POS_LEFT:
3094             case GTK_POS_RIGHT:
3095               child_allocation.height = (page->requisition.height +
3096                                          TAB_OVERLAP + delta);
3097               child_allocation.y -= child_allocation.height;
3098               break;
3099             }
3100
3101           gtk_notebook_page_allocate (notebook, page, &child_allocation);
3102
3103           switch (notebook->tab_pos)
3104             {
3105             case GTK_POS_TOP:
3106             case GTK_POS_BOTTOM:
3107               child_allocation.x += TAB_OVERLAP;
3108               break;
3109             case GTK_POS_LEFT:
3110             case GTK_POS_RIGHT:
3111               child_allocation.y += TAB_OVERLAP;
3112               break;
3113             }
3114
3115           if (page->tab_label)
3116             gtk_widget_set_child_visible (page->tab_label, TRUE);
3117         }
3118     }
3119
3120  done:
3121   gtk_notebook_redraw_tabs (notebook);  
3122 }
3123
3124 static void
3125 gtk_notebook_page_allocate (GtkNotebook     *notebook,
3126                             GtkNotebookPage *page,
3127                             GtkAllocation   *allocation)
3128 {
3129   GtkWidget *widget;
3130   GtkAllocation child_allocation;
3131   GtkRequisition tab_requisition;
3132   gint xthickness;
3133   gint ythickness;
3134   gint padding;
3135
3136   g_return_if_fail (notebook != NULL);
3137   g_return_if_fail (page != NULL);
3138   g_return_if_fail (allocation != NULL);
3139
3140   widget = GTK_WIDGET (notebook);
3141
3142   xthickness = widget->style->xthickness;
3143   ythickness = widget->style->ythickness;
3144
3145   /* If the size of the notebook tabs change, we need to queue
3146    * a redraw on the tab area
3147    */
3148   if ((allocation->width != page->allocation.width) ||
3149       (allocation->height != page->allocation.height))
3150     {
3151       gint x, y, width, height, border_width;
3152
3153       border_width = GTK_CONTAINER (notebook)->border_width;
3154
3155       switch (notebook->tab_pos)
3156        {
3157        case GTK_POS_TOP:
3158          width = widget->allocation.width;
3159          height = MAX (page->allocation.height, allocation->height) + ythickness;
3160          x = 0;                              
3161          y = border_width;
3162          break;
3163
3164        case GTK_POS_BOTTOM:
3165          width = widget->allocation.width + xthickness;
3166          height = MAX (page->allocation.height, allocation->height) + ythickness;
3167          x = 0;                              
3168          y = widget->allocation.height - height - border_width;
3169          break;
3170
3171        case GTK_POS_LEFT:
3172          width = MAX (page->allocation.width, allocation->width) + xthickness;
3173          height = widget->allocation.height;
3174          x = border_width;
3175          y = 0;
3176          break;
3177
3178        case GTK_POS_RIGHT:
3179        default:                /* quiet gcc */
3180          width = MAX (page->allocation.width, allocation->width) + xthickness;
3181          height = widget->allocation.height;
3182          x = widget->allocation.width - width - border_width;
3183          y = 0;
3184          break;
3185        }
3186
3187       gtk_widget_queue_clear_area (widget, x, y, width, height);
3188     }
3189
3190   page->allocation = *allocation;
3191   gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
3192
3193   if (notebook->cur_page != page)
3194     {
3195       switch (notebook->tab_pos)
3196         {
3197         case GTK_POS_TOP:
3198           page->allocation.y += ythickness;
3199         case GTK_POS_BOTTOM:
3200           if (page->allocation.height > ythickness)
3201             page->allocation.height -= ythickness;
3202           break;
3203         case GTK_POS_LEFT:
3204           page->allocation.x += xthickness;
3205         case GTK_POS_RIGHT:
3206           if (page->allocation.width > xthickness)
3207             page->allocation.width -= xthickness;
3208           break;
3209         }
3210     }
3211
3212   switch (notebook->tab_pos)
3213     {
3214     case GTK_POS_TOP:
3215     case GTK_POS_BOTTOM:
3216       padding = TAB_CURVATURE + FOCUS_WIDTH + notebook->tab_hborder;
3217       if (page->fill)
3218         {
3219           child_allocation.x = (xthickness + FOCUS_WIDTH +
3220                                 notebook->tab_hborder);
3221           child_allocation.width = MAX (1, (page->allocation.width -
3222                                             2 * child_allocation.x));
3223           child_allocation.x += page->allocation.x;
3224         }
3225       else
3226         {
3227           child_allocation.x = (page->allocation.x +
3228                                 (page->allocation.width -
3229                                  tab_requisition.width) / 2);
3230           child_allocation.width = tab_requisition.width;
3231         }
3232       child_allocation.y = (notebook->tab_vborder + FOCUS_WIDTH +
3233                             page->allocation.y);
3234       if (notebook->tab_pos == GTK_POS_TOP)
3235         child_allocation.y += ythickness;
3236       child_allocation.height = MAX (1, (page->allocation.height - ythickness -
3237                                          2 * (notebook->tab_vborder + FOCUS_WIDTH)));
3238       break;
3239     case GTK_POS_LEFT:
3240     case GTK_POS_RIGHT:
3241       padding = TAB_CURVATURE + FOCUS_WIDTH + notebook->tab_vborder;
3242       if (page->fill)
3243         {
3244           child_allocation.y = ythickness + padding;
3245           child_allocation.height = MAX (1, (page->allocation.height -
3246                                              2 * child_allocation.y));
3247           child_allocation.y += page->allocation.y;
3248         }
3249       else
3250         {
3251           child_allocation.y = (page->allocation.y + (page->allocation.height -
3252                                                       tab_requisition.height) / 2);
3253           child_allocation.height = tab_requisition.height;
3254         }
3255       child_allocation.x = page->allocation.x + notebook->tab_hborder + FOCUS_WIDTH;
3256       if (notebook->tab_pos == GTK_POS_LEFT)
3257         child_allocation.x += xthickness;
3258       child_allocation.width = MAX (1, (page->allocation.width - xthickness -
3259                                         2 * (notebook->tab_hborder + FOCUS_WIDTH)));
3260       break;
3261     }
3262
3263   if (page->tab_label)
3264     gtk_widget_size_allocate (page->tab_label, &child_allocation);
3265 }
3266
3267 static void 
3268 gtk_notebook_calc_tabs (GtkNotebook  *notebook, 
3269                         GList        *start, 
3270                         GList       **end,
3271                         gint         *tab_space,
3272                         guint         direction)
3273 {
3274   GtkNotebookPage *page = NULL;
3275   GList *children;
3276   GList *last_list = NULL;
3277   gboolean pack;
3278
3279   if (!start)
3280     return;
3281
3282   children = start;
3283   pack = GTK_NOTEBOOK_PAGE (start)->pack;
3284   if (pack == GTK_PACK_END)
3285     direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
3286
3287   while (1)
3288     {
3289       switch (notebook->tab_pos)
3290         {
3291         case GTK_POS_TOP:
3292         case GTK_POS_BOTTOM:
3293           while (children)
3294             {
3295               page = children->data;
3296               if (GTK_WIDGET_VISIBLE (page->child))
3297                 {
3298                   if (page->pack == pack)
3299                     {
3300                       *tab_space -= page->requisition.width;
3301                       if (*tab_space < 0 || children == *end)
3302                         {
3303                           if (*tab_space < 0) 
3304                             {
3305                               *tab_space = - (*tab_space +
3306                                               page->requisition.width);
3307                               *end = children;
3308                             }
3309                           return;
3310                         }
3311                     }
3312                   last_list = children;
3313                 }
3314               if (direction == STEP_NEXT)
3315                 children = children->next;
3316               else
3317                 children = children->prev;
3318             }
3319           break;
3320         case GTK_POS_LEFT:
3321         case GTK_POS_RIGHT:
3322           while (children)
3323             {
3324               page = children->data;
3325               if (GTK_WIDGET_VISIBLE (page->child))
3326                 {
3327                   if (page->pack == pack)
3328                     {
3329                       *tab_space -= page->requisition.height;
3330                       if (*tab_space < 0 || children == *end)
3331                         {
3332                           if (*tab_space < 0)
3333                             {
3334                               *tab_space = - (*tab_space +
3335                                               page->requisition.height);
3336                               *end = children;
3337                             }
3338                           return;
3339                         }
3340                     }
3341                   last_list = children;
3342                 }
3343               if (direction == STEP_NEXT)
3344                 children = children->next;
3345               else
3346                 children = children->prev;
3347             }
3348           break;
3349         }
3350       if (direction == STEP_PREV)
3351         return;
3352       pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
3353       direction = STEP_PREV;
3354       children = last_list;
3355     }
3356 }
3357
3358 /* Private GtkNotebook Page Switch Methods:
3359  *
3360  * gtk_notebook_real_switch_page
3361  */
3362 static void
3363 gtk_notebook_real_switch_page (GtkNotebook     *notebook,
3364                                GtkNotebookPage *page,
3365                                guint            page_num)
3366 {
3367   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3368   g_return_if_fail (page != NULL);
3369
3370   if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
3371     return;
3372
3373   if (notebook->cur_page)
3374     gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
3375   
3376   notebook->cur_page = page;
3377
3378   if (!notebook->focus_tab ||
3379       notebook->focus_tab->data != (gpointer) notebook->cur_page)
3380     notebook->focus_tab = 
3381       g_list_find (notebook->children, notebook->cur_page);
3382
3383   gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
3384
3385   gtk_widget_queue_resize (GTK_WIDGET (notebook));
3386   g_object_notify (G_OBJECT (notebook), "page");
3387 }
3388
3389 /* Private GtkNotebook Page Switch Functions:
3390  *
3391  * gtk_notebook_switch_page
3392  * gtk_notebook_page_select
3393  * gtk_notebook_switch_focus_tab
3394  * gtk_notebook_menu_switch_page
3395  */
3396 static void
3397 gtk_notebook_switch_page (GtkNotebook     *notebook,
3398                           GtkNotebookPage *page,
3399                           gint             page_num)
3400
3401   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3402   g_return_if_fail (page != NULL);
3403  
3404   if (notebook->cur_page == page)
3405     return;
3406
3407   if (page_num < 0)
3408     page_num = g_list_index (notebook->children, page);
3409
3410   gtk_signal_emit (GTK_OBJECT (notebook), 
3411                    notebook_signals[SWITCH_PAGE], 
3412                    page,
3413                    page_num);
3414 }
3415
3416 static gint
3417 gtk_notebook_page_select (GtkNotebook *notebook,
3418                           gboolean     move_focus)
3419 {
3420   GtkNotebookPage *page;
3421   GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
3422
3423   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
3424
3425   if (!notebook->focus_tab)
3426     return FALSE;
3427
3428   page = notebook->focus_tab->data;
3429   gtk_notebook_switch_page (notebook, page, -1);
3430
3431   if (move_focus)
3432     {
3433       switch (notebook->tab_pos)
3434         {
3435         case GTK_POS_TOP:
3436           dir = GTK_DIR_DOWN;
3437           break;
3438         case GTK_POS_BOTTOM:
3439           dir = GTK_DIR_UP;
3440           break;
3441         case GTK_POS_LEFT:
3442           dir = GTK_DIR_RIGHT;
3443           break;
3444         case GTK_POS_RIGHT:
3445           dir = GTK_DIR_LEFT;
3446           break;
3447         }
3448
3449       if (gtk_widget_child_focus (page->child, dir))
3450         return TRUE;
3451     }
3452   return FALSE;
3453 }
3454
3455 static void
3456 gtk_notebook_switch_focus_tab (GtkNotebook *notebook, 
3457                                GList       *new_child)
3458 {
3459   GList *old_child;
3460   GtkNotebookPage *old_page = NULL;
3461   GtkNotebookPage *page;
3462
3463   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3464
3465   if (notebook->focus_tab == new_child)
3466     return;
3467
3468   old_child = notebook->focus_tab;
3469   notebook->focus_tab = new_child;
3470
3471   if (notebook->scrollable)
3472     gtk_notebook_redraw_arrows (notebook);
3473
3474   if (!notebook->show_tabs || !notebook->focus_tab)
3475     return;
3476
3477   if (old_child)
3478     old_page = old_child->data;
3479
3480   page = notebook->focus_tab->data;
3481   if (GTK_WIDGET_MAPPED (page->tab_label))
3482     gtk_notebook_focus_changed (notebook, old_page);
3483   else
3484     gtk_notebook_pages_allocate (notebook);
3485 }
3486
3487 static void
3488 gtk_notebook_menu_switch_page (GtkWidget       *widget,
3489                                GtkNotebookPage *page)
3490 {
3491   GtkNotebook *notebook;
3492   GList *children;
3493   guint page_num;
3494
3495   g_return_if_fail (widget != NULL);
3496   g_return_if_fail (page != NULL);
3497
3498   notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
3499                            (GTK_MENU (widget->parent)));
3500
3501   if (notebook->cur_page == page)
3502     return;
3503
3504   page_num = 0;
3505   children = notebook->children;
3506   while (children && children->data != page)
3507     {
3508       children = children->next;
3509       page_num++;
3510     }
3511
3512   gtk_signal_emit (GTK_OBJECT (notebook), 
3513                    notebook_signals[SWITCH_PAGE], 
3514                    page,
3515                    page_num);
3516 }
3517
3518 /* Private GtkNotebook Menu Functions:
3519  *
3520  * gtk_notebook_menu_item_create
3521  * gtk_notebook_menu_label_unparent
3522  * gtk_notebook_menu_detacher
3523  */
3524 static void
3525 gtk_notebook_menu_item_create (GtkNotebook *notebook, 
3526                                GList       *list)
3527 {       
3528   GtkNotebookPage *page;
3529   GtkWidget *menu_item;
3530
3531   page = list->data;
3532   if (page->default_menu)
3533     {
3534       if (page->tab_label && GTK_IS_LABEL (page->tab_label))
3535         page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
3536       else
3537         page->menu_label = gtk_label_new ("");
3538       gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
3539     }
3540
3541   gtk_widget_show (page->menu_label);
3542   menu_item = gtk_menu_item_new ();
3543   gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
3544   gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
3545                          gtk_notebook_real_page_position (notebook, list));
3546   gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
3547                       GTK_SIGNAL_FUNC (gtk_notebook_menu_switch_page), page);
3548   if (GTK_WIDGET_VISIBLE (page->child))
3549     gtk_widget_show (menu_item);
3550 }
3551
3552 static void
3553 gtk_notebook_menu_label_unparent (GtkWidget *widget, 
3554                                   gpointer  data)
3555 {
3556   gtk_widget_unparent (GTK_BIN(widget)->child);
3557   GTK_BIN(widget)->child = NULL;
3558 }
3559
3560 static void
3561 gtk_notebook_menu_detacher (GtkWidget *widget,
3562                             GtkMenu   *menu)
3563 {
3564   GtkNotebook *notebook;
3565
3566   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
3567
3568   notebook = GTK_NOTEBOOK (widget);
3569   g_return_if_fail (notebook->menu == (GtkWidget*) menu);
3570
3571   notebook->menu = NULL;
3572 }
3573
3574 /* Public GtkNotebook Page Insert/Remove Methods :
3575  *
3576  * gtk_notebook_append_page
3577  * gtk_notebook_append_page_menu
3578  * gtk_notebook_prepend_page
3579  * gtk_notebook_prepend_page_menu
3580  * gtk_notebook_insert_page
3581  * gtk_notebook_insert_page_menu
3582  * gtk_notebook_remove_page
3583  */
3584 /**
3585  * gtk_notebook_append_page:
3586  * @notebook: a #GtkNotebook
3587  * @child: the #GtkWidget to use as the contents of the page.
3588  * @tab_label: the #GtkWidget to be used as the label for the page,
3589  *             or %NULL to use the default label, 'page N'.
3590  * 
3591  * Appends a page to @notebook.
3592  **/
3593 void
3594 gtk_notebook_append_page (GtkNotebook *notebook,
3595                           GtkWidget   *child,
3596                           GtkWidget   *tab_label)
3597 {
3598   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3599   g_return_if_fail (GTK_IS_WIDGET (child));
3600   g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
3601   
3602   gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
3603 }
3604
3605 /**
3606  * gtk_notebook_append_page_menu:
3607  * @notebook: a #GtkNotebook
3608  * @child: the #GtkWidget to use as the contents of the page.
3609  * @tab_label: the #GtkWidget to be used as the label for the page,
3610  *             or %NULL to use the default label, 'page N'.
3611  * @menu_label: the widget to use as a label for the page-switch
3612  *              menu, if that is enabled. If %NULL, and @tab_label
3613  *              is a #GtkLabel or %NULL, then the menu label will be
3614  *              a newly created label with the same text as @tab_label;
3615  *              If @tab_label is not a #GtkLabel, @menu_label must be
3616  *              specified if the page-switch menu is to be used.
3617  * 
3618  * Appends a page to @notebook, specifying the widget to use as the
3619  * label in the popup menu.
3620  **/
3621 void
3622 gtk_notebook_append_page_menu (GtkNotebook *notebook,
3623                                GtkWidget   *child,
3624                                GtkWidget   *tab_label,
3625                                GtkWidget   *menu_label)
3626 {
3627   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3628   g_return_if_fail (GTK_IS_WIDGET (child));
3629   g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
3630   g_return_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label));
3631   
3632   gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
3633 }
3634
3635 /**
3636  * gtk_notebook_prepend_page:
3637  * @notebook: a #GtkNotebook
3638  * @child: the #GtkWidget to use as the contents of the page.
3639  * @tab_label: the #GtkWidget to be used as the label for the page,
3640  *             or %NULL to use the default label, 'page N'.
3641  *
3642  * Prepends a page to @notebook.
3643  **/
3644 void
3645 gtk_notebook_prepend_page (GtkNotebook *notebook,
3646                            GtkWidget   *child,
3647                            GtkWidget   *tab_label)
3648 {
3649   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3650   g_return_if_fail (GTK_IS_WIDGET (child));
3651   g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
3652   
3653   gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
3654 }
3655
3656 /**
3657  * gtk_notebook_prepend_page_menu:
3658  * @notebook: a #GtkNotebook
3659  * @child: the #GtkWidget to use as the contents of the page.
3660  * @tab_label: the #GtkWidget to be used as the label for the page,
3661  *             or %NULL to use the default label, 'page N'.
3662  * @menu_label: the widget to use as a label for the page-switch
3663  *              menu, if that is enabled. If %NULL, and @tab_label
3664  *              is a #GtkLabel or %NULL, then the menu label will be
3665  *              a newly created label with the same text as @tab_label;
3666  *              If @tab_label is not a #GtkLabel, @menu_label must be
3667  *              specified if the page-switch menu is to be used.
3668  * 
3669  * Prepends a page to @notebook, specifying the widget to use as the
3670  * label in the popup menu.
3671  **/
3672 void
3673 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
3674                                 GtkWidget   *child,
3675                                 GtkWidget   *tab_label,
3676                                 GtkWidget   *menu_label)
3677 {
3678   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3679   g_return_if_fail (GTK_IS_WIDGET (child));
3680   g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
3681   g_return_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label));
3682   
3683   gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
3684 }
3685
3686 /**
3687  * gtk_notebook_insert_page:
3688  * @notebook: a #GtkNotebook
3689  * @child: the #GtkWidget to use as the contents of the page.
3690  * @tab_label: the #GtkWidget to be used as the label for the page,
3691  *             or %NULL to use the default label, 'page N'.
3692  * @position: the index (starting at 0) at which to insert the page,
3693  *            or -1 to append the page after all other pages.
3694  * 
3695  * Insert a page into @notebook at the given position
3696  **/
3697 void
3698 gtk_notebook_insert_page (GtkNotebook *notebook,
3699                           GtkWidget   *child,
3700                           GtkWidget   *tab_label,
3701                           gint         position)
3702 {
3703   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3704   g_return_if_fail (GTK_IS_WIDGET (child));
3705   g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
3706   
3707   gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
3708 }
3709
3710
3711 static gint
3712 gtk_notebook_page_compare_tab (gconstpointer a,
3713                                gconstpointer b)
3714 {
3715   return (((GtkNotebookPage *) a)->tab_label != b);
3716 }
3717
3718 static gboolean
3719 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
3720                                             gboolean overload,
3721                                             gpointer data)
3722 {
3723   GtkNotebook *notebook = GTK_NOTEBOOK (data);
3724   GList *list;
3725   
3726   list = g_list_find_custom (notebook->children, child,
3727                              gtk_notebook_page_compare_tab);
3728   if (list)
3729     {
3730       GtkNotebookPage *page = list->data;
3731
3732       gtk_notebook_switch_page (notebook, page,  -1);
3733     }
3734
3735   return TRUE;
3736 }
3737
3738 /**
3739  * gtk_notebook_insert_page_menu:
3740  * @notebook: a #GtkNotebook
3741  * @child: the #GtkWidget to use as the contents of the page.
3742  * @tab_label: the #GtkWidget to be used as the label for the page,
3743  *             or %NULL to use the default label, 'page N'.
3744  * @menu_label: the widget to use as a label for the page-switch
3745  *              menu, if that is enabled. If %NULL, and @tab_label
3746  *              is a #GtkLabel or %NULL, then the menu label will be
3747  *              a newly created label with the same text as @tab_label;
3748  *              If @tab_label is not a #GtkLabel, @menu_label must be
3749  *              specified if the page-switch menu is to be used.
3750  * @position: the index (starting at 0) at which to insert the page,
3751  *            or -1 to append the page after all other pages.
3752  * 
3753  * Insert a page into @notebook at the given position, specifying
3754  * the widget to use as the label in the popup menu.
3755  **/
3756 void
3757 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
3758                                GtkWidget   *child,
3759                                GtkWidget   *tab_label,
3760                                GtkWidget   *menu_label,
3761                                gint         position)
3762 {
3763   GtkNotebookPage *page;
3764   gint nchildren;
3765
3766   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3767   g_return_if_fail (GTK_IS_WIDGET (child));
3768   g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
3769   g_return_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label));
3770
3771   gtk_widget_freeze_child_notify (child);
3772   
3773   page = g_new (GtkNotebookPage, 1);
3774   page->child = child;
3775   page->requisition.width = 0;
3776   page->requisition.height = 0;
3777   page->allocation.x = 0;
3778   page->allocation.y = 0;
3779   page->allocation.width = 0;
3780   page->allocation.height = 0;
3781   page->default_menu = FALSE;
3782   page->default_tab = FALSE;
3783   page->mnemonic_activate_signal = 0;
3784    
3785   nchildren = g_list_length (notebook->children);
3786   if ((position < 0) || (position > nchildren))
3787     position = nchildren;
3788
3789   notebook->children = g_list_insert (notebook->children, page, position);
3790
3791   if (!tab_label)
3792     {
3793       page->default_tab = TRUE;
3794       if (notebook->show_tabs)
3795         tab_label = gtk_label_new ("");
3796     }
3797   page->tab_label = tab_label;
3798   page->menu_label = menu_label;
3799   page->expand = FALSE;
3800   page->fill = TRUE;
3801   page->pack = GTK_PACK_START;
3802
3803   if (!menu_label)
3804     page->default_menu = TRUE;
3805   else  
3806     {
3807       gtk_widget_ref (page->menu_label);
3808       gtk_object_sink (GTK_OBJECT (page->menu_label));
3809     }
3810
3811   if (notebook->menu)
3812     gtk_notebook_menu_item_create (notebook,
3813                                    g_list_find (notebook->children, page));
3814
3815   gtk_widget_set_parent (child, GTK_WIDGET (notebook));
3816   if (tab_label)
3817     gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
3818
3819   gtk_notebook_update_labels (notebook);
3820
3821   if (!notebook->first_tab)
3822     notebook->first_tab = notebook->children;
3823
3824   if (!notebook->cur_page)
3825     gtk_widget_set_child_visible (child, TRUE);
3826   else
3827     gtk_widget_set_child_visible (child, FALSE);
3828   
3829   if (tab_label)
3830     {
3831       if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
3832         gtk_widget_show (tab_label);
3833       else
3834         gtk_widget_hide (tab_label);
3835     }
3836
3837   if (!notebook->cur_page)
3838     {
3839       gtk_notebook_switch_page (notebook, page, 0);
3840       gtk_notebook_switch_focus_tab (notebook, NULL);
3841     }
3842
3843   if (tab_label)
3844     page->mnemonic_activate_signal =
3845       gtk_signal_connect (GTK_OBJECT (tab_label),
3846                           "mnemonic_activate",
3847                           (GtkSignalFunc) gtk_notebook_mnemonic_activate_switch_page,
3848                           notebook);
3849
3850   if (notebook->show_tabs && GTK_WIDGET_MAPPED (notebook))
3851     gdk_window_show_unraised (notebook->event_window);
3852
3853   gtk_widget_child_notify (child, "tab_expand");
3854   gtk_widget_child_notify (child, "tab_fill");
3855   gtk_widget_child_notify (child, "tab_pack");
3856   gtk_widget_child_notify (child, "tab_label");
3857   gtk_widget_child_notify (child, "menu_label");
3858   gtk_widget_child_notify (child, "position");
3859   gtk_widget_thaw_child_notify (child);
3860 }
3861
3862 /**
3863  * gtk_notebook_remove_page:
3864  * @notebook: a #GtkNotebook.
3865  * @page_num: the index of a notebook page, starting
3866  *            from 0. If -1, the last page will
3867  *            be removed.
3868  * 
3869  * Removes a page from the notebook given its index
3870  * in the notebook.
3871  **/
3872 void
3873 gtk_notebook_remove_page (GtkNotebook *notebook,
3874                           gint         page_num)
3875 {
3876   GList *list;
3877   
3878   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3879   
3880   if (page_num >= 0)
3881     {
3882       list = g_list_nth (notebook->children, page_num);
3883       if (list)
3884         gtk_notebook_real_remove (notebook, list);
3885     }
3886   else
3887     {
3888       list = g_list_last (notebook->children);
3889       if (list)
3890         gtk_notebook_real_remove (notebook, list);
3891     }
3892 }
3893
3894 /* Public GtkNotebook Page Switch Methods :
3895  * gtk_notebook_get_current_page
3896  * gtk_notebook_page_num
3897  * gtk_notebook_set_current_page
3898  * gtk_notebook_next_page
3899  * gtk_notebook_prev_page
3900  */
3901 /**
3902  * gtk_notebook_get_current_page:
3903  * @notebook: a #GtkNotebook
3904  * 
3905  * Returns the page number of the current page.
3906  * 
3907  * Return value: the index (starting from 0) of the current
3908  * page in the notebook. If the notebook has no pages, then
3909  * -1 will be returned.
3910  **/
3911 gint
3912 gtk_notebook_get_current_page (GtkNotebook *notebook)
3913 {
3914   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3915
3916   if (!notebook->cur_page)
3917     return -1;
3918
3919   return g_list_index (notebook->children, notebook->cur_page);
3920 }
3921
3922 /**
3923  * gtk_notebook_get_nth_page:
3924  * @notebook: a #GtkNotebook
3925  * @page_num: the index of a page in the noteobok
3926  * 
3927  * Returns the child widget contained in page number @page_num.
3928  * 
3929  * Return value: the child widget, or %NULL if @page_num is
3930  * out of bounds.
3931  **/
3932 GtkWidget*
3933 gtk_notebook_get_nth_page (GtkNotebook *notebook,
3934                            gint         page_num)
3935 {
3936   GtkNotebookPage *page;
3937
3938   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
3939
3940   page = g_list_nth_data (notebook->children, page_num);
3941
3942   if (page)
3943     return page->child;
3944
3945   return NULL;
3946 }
3947
3948 /**
3949  * gtk_notebook_page_num:
3950  * @notebook: a #GtkNotebook
3951  * @child: a #GtkWidget
3952  * 
3953  * Finds the index of the page which contains the given child
3954  * widget.
3955  * 
3956  * Return value: the index of the page containing @child, or
3957  *   -1 if @child is not in the notebook.
3958  **/
3959 gint
3960 gtk_notebook_page_num (GtkNotebook      *notebook,
3961                        GtkWidget        *child)
3962 {
3963   GList *children;
3964   gint num;
3965
3966   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3967
3968   num = 0;
3969   children = notebook->children;
3970   while (children)
3971     {
3972       GtkNotebookPage *page =  children->data;
3973       
3974       if (page->child == child)
3975         return num;
3976
3977       children = children->next;
3978       num++;
3979     }
3980
3981   return -1;
3982 }
3983
3984 /**
3985  * gtk_notebook_set_current_page:
3986  * @notebook: a #GtkNotebook
3987  * @page_num: index of the page to switch to, starting from 0.
3988  *            If negative, or greater than the number of pages
3989  *            in the notebook the last page will be used.
3990  *                
3991  * Switches to the page number @page_num.
3992  **/
3993 void
3994 gtk_notebook_set_current_page (GtkNotebook *notebook,
3995                                gint         page_num)
3996 {
3997   GList *list;
3998
3999   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4000
4001   if (page_num >= 0)
4002     list = g_list_nth (notebook->children, page_num);
4003   else
4004     list = g_list_last (notebook->children);
4005
4006   page_num = g_list_index (notebook->children, list);
4007
4008   if (list)
4009     gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
4010 }
4011
4012 /**
4013  * gtk_notebook_next_page:
4014  * @notebook: a #GtkNotebook
4015  * 
4016  * Switches to the next page. Nothing happens if the current page is
4017  * the last page.
4018  **/
4019 void
4020 gtk_notebook_next_page (GtkNotebook *notebook)
4021 {
4022   GList *list;
4023
4024   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4025
4026   list = g_list_find (notebook->children, notebook->cur_page);
4027   if (!list)
4028     return;
4029
4030   list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4031   if (!list)
4032     return;
4033
4034   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
4035 }
4036
4037 /**
4038  * gtk_notebook_prev_page:
4039  * @notebook: a #GtkNotebook
4040  * 
4041  * Switches to the previous page. Nothing happens if the current page
4042  * is the first page.
4043  **/
4044 void
4045 gtk_notebook_prev_page (GtkNotebook *notebook)
4046 {
4047   GList *list;
4048
4049   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4050
4051   list = g_list_find (notebook->children, notebook->cur_page);
4052   if (!list)
4053     return;
4054
4055   list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4056   if (!list)
4057     return;
4058
4059   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
4060 }
4061
4062 /* Public GtkNotebook/Tab Style Functions
4063  *
4064  * gtk_notebook_set_show_border
4065  * gtk_notebook_set_show_tabs
4066  * gtk_notebook_set_tab_pos
4067  * gtk_notebook_set_homogeneous_tabs
4068  * gtk_notebook_set_tab_border
4069  * gtk_notebook_set_tab_hborder
4070  * gtk_notebook_set_tab_vborder
4071  * gtk_notebook_set_scrollable
4072  */
4073 /**
4074  * gtk_notebook_set_show_border:
4075  * @notebook: a #GtkNotebook
4076  * @show_border: %TRUE if a bevel should be drawn around the notebook.
4077  * 
4078  * Sets whether a bevel will be drawn around the notebook pages.
4079  * this is only has an effect when the tabs are not shown.
4080  * See gtk_notebook_set_show_tabs().
4081  **/
4082 void
4083 gtk_notebook_set_show_border (GtkNotebook *notebook,
4084                               gboolean     show_border)
4085 {
4086   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4087
4088   if (notebook->show_border != show_border)
4089     {
4090       notebook->show_border = show_border;
4091
4092       if (GTK_WIDGET_VISIBLE (notebook))
4093         gtk_widget_queue_resize (GTK_WIDGET (notebook));
4094       
4095       g_object_notify (G_OBJECT (notebook), "show_border");
4096     }
4097 }
4098
4099 /**
4100  * gtk_notebook_get_show_border:
4101  * @notebook: a #GtkNotebook
4102  *
4103  * Returns whether a bevel will be drawn around the notebook pages. See
4104  * gtk_notebook_set_show_border().
4105  *
4106  * Return value: %TRUE if the bevel is drawn
4107  **/
4108 gboolean
4109 gtk_notebook_get_show_border (GtkNotebook *notebook)
4110 {
4111   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
4112
4113   return notebook->show_border;
4114 }
4115
4116 /**
4117  * gtk_notebook_set_show_tabs:
4118  * @notebook: a #GtkNotebook
4119  * @show_tabs: %TRUE if the tabs should be shown.
4120  * 
4121  * Sets whether to show the tabs for the notebook or not.
4122  **/
4123 void
4124 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
4125                             gboolean     show_tabs)
4126 {
4127   GtkNotebookPage *page;
4128   GList *children;
4129
4130   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4131
4132   show_tabs = show_tabs != FALSE;
4133
4134   if (notebook->show_tabs == show_tabs)
4135     return;
4136
4137   notebook->show_tabs = show_tabs;
4138   children = notebook->children;
4139
4140   if (!show_tabs)
4141     {
4142       GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
4143       
4144       while (children)
4145         {
4146           page = children->data;
4147           children = children->next;
4148           if (page->default_tab)
4149             {
4150               gtk_widget_destroy (page->tab_label);
4151               page->tab_label = NULL;
4152             }
4153           else
4154             gtk_widget_hide (page->tab_label);
4155         }
4156     }
4157   else
4158     {
4159       GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
4160       gtk_notebook_update_labels (notebook);
4161     }
4162   gtk_widget_queue_resize (GTK_WIDGET (notebook));
4163
4164   g_object_notify (G_OBJECT (notebook), "show_tabs");
4165 }
4166
4167 /**
4168  * gtk_notebook_get_show_tabs:
4169  * @notebook: a #GtkNotebook
4170  *
4171  * Returns whether the tabs of the notebook are shown. See
4172  * gtk_notebook_set_show_tabs().
4173  *
4174  * Return value: %TRUE if the tabs are shown
4175  **/
4176 gboolean
4177 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
4178 {
4179   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
4180
4181   return notebook->show_tabs;
4182 }
4183
4184 /**
4185  * gtk_notebook_set_tab_pos:
4186  * @notebook: a #GtkNotebook.
4187  * @pos: the edge to draw the tabs at.
4188  * 
4189  * Sets the edge at which the tabs for switching pages in the
4190  * notebook are drawn.
4191  **/
4192 void
4193 gtk_notebook_set_tab_pos (GtkNotebook     *notebook,
4194                           GtkPositionType  pos)
4195 {
4196   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4197
4198   if (notebook->tab_pos != pos)
4199     {
4200       notebook->tab_pos = pos;
4201       if (GTK_WIDGET_VISIBLE (notebook))
4202         gtk_widget_queue_resize (GTK_WIDGET (notebook));
4203     }
4204
4205   g_object_notify (G_OBJECT (notebook), "tab_pos");
4206 }
4207
4208 /**
4209  * gtk_notebook_get_tab_pos:
4210  * @notebook: a #GtkNotebook
4211  *
4212  * Gets the edge at which the tabs for switching pages in the
4213  * notebook are drawn.
4214  *
4215  * Return value: the edge at which the tabs are drawn
4216  **/
4217 GtkPositionType
4218 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
4219 {
4220   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
4221
4222   return notebook->tab_pos;
4223 }
4224
4225 /**
4226  * gtk_notebook_set_homogeneous_tabs:
4227  * @notebook: a #GtkNotebook
4228  * @homogeneous: %TRUE if all tabs should be the same size.
4229  * 
4230  * Sets whether the tabs must have all the same size or not.
4231  **/
4232 void
4233 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
4234                                    gboolean     homogeneous)
4235 {
4236   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4237
4238   if (homogeneous == notebook->homogeneous)
4239     return;
4240
4241   notebook->homogeneous = homogeneous;
4242   gtk_widget_queue_resize (GTK_WIDGET (notebook));
4243
4244   g_object_notify (G_OBJECT (notebook), "homogeneous");
4245 }
4246
4247 /**
4248  * gtk_notebook_set_tab_border:
4249  * @notebook: a #GtkNotebook
4250  * @border_width: width of the border around the tab labels.
4251  * 
4252  * Sets the width the border around the tab labels
4253  * in a notebook. This is equivalent to calling
4254  * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
4255  * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
4256  **/
4257 void
4258 gtk_notebook_set_tab_border (GtkNotebook *notebook,
4259                              guint        border_width)
4260 {
4261   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4262
4263   notebook->tab_hborder = border_width;
4264   notebook->tab_vborder = border_width;
4265
4266   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
4267     gtk_widget_queue_resize (GTK_WIDGET (notebook));
4268
4269   g_object_notify (G_OBJECT (notebook), "tab_hborder");
4270 }
4271
4272 /**
4273  * gtk_notebook_set_tab_hborder:
4274  * @notebook: a #GtkNotebook
4275  * @tab_hborder: width of the horizontal border of tab labels.
4276  * 
4277  * Sets the width of the horizontal border of tab labels.
4278  **/
4279 void
4280 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
4281                               guint        tab_hborder)
4282 {
4283   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4284
4285   if (notebook->tab_hborder == tab_hborder)
4286     return;
4287
4288   notebook->tab_hborder = tab_hborder;
4289
4290   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
4291     gtk_widget_queue_resize (GTK_WIDGET (notebook));
4292
4293   g_object_notify (G_OBJECT (notebook), "tab_vborder");
4294 }
4295
4296 /**
4297  * gtk_notebook_set_tab_vborder:
4298  * @notebook: a #GtkNotebook
4299  * @tab_vborder: width of the vertical border of tab labels.
4300  * 
4301  * Sets the width of the vertical border of tab labels.
4302  **/
4303 void
4304 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
4305                               guint        tab_vborder)
4306 {
4307   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4308
4309   if (notebook->tab_vborder == tab_vborder)
4310     return;
4311
4312   notebook->tab_vborder = tab_vborder;
4313
4314   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
4315     gtk_widget_queue_resize (GTK_WIDGET (notebook));
4316 }
4317
4318 /**
4319  * gtk_notebook_set_scrollable:
4320  * @notebook: a #GtkNotebook
4321  * @scrollable: %TRUE if scroll arrows should be added
4322  * 
4323  * Sets whether the tab label area will have arrows for scrolling if
4324  * there are too many tabs to fit in the area.
4325  **/
4326 void
4327 gtk_notebook_set_scrollable (GtkNotebook *notebook,
4328                              gboolean     scrollable)
4329 {
4330   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4331
4332   scrollable = (scrollable != FALSE);
4333
4334   if (scrollable != notebook->scrollable)
4335     {
4336       notebook->scrollable = scrollable;
4337
4338       if (GTK_WIDGET_VISIBLE (notebook))
4339         gtk_widget_queue_resize (GTK_WIDGET (notebook));
4340
4341       g_object_notify (G_OBJECT (notebook), "scrollable");
4342     }
4343 }
4344
4345 /**
4346  * gtk_notebook_get_scrollable:
4347  * @notebook: a #GtkNotebook
4348  *
4349  * Returns whether the tab label area has arrows for scrolling. See
4350  * gtk_notebook_set_scrollable().
4351  *
4352  * Return value: %TRUE if arrows for scrolling are present
4353  **/
4354 gboolean
4355 gtk_notebook_get_scrollable (GtkNotebook *notebook)
4356 {
4357   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
4358
4359   return notebook->scrollable;
4360 }
4361
4362 /* Public GtkNotebook Popup Menu Methods:
4363  *
4364  * gtk_notebook_popup_enable
4365  * gtk_notebook_popup_disable
4366  */
4367
4368
4369 /**
4370  * gtk_notebook_popup_enable:
4371  * @notebook: a #GtkNotebook
4372  * 
4373  * Enables the popup menu: if the user clicks with the right mouse button on
4374  * the bookmarks, a menu with all the pages will be popped up.
4375  **/
4376 void
4377 gtk_notebook_popup_enable (GtkNotebook *notebook)
4378 {
4379   GList *list;
4380
4381   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4382
4383   if (notebook->menu)
4384     return;
4385
4386   notebook->menu = gtk_menu_new ();
4387   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4388        list;
4389        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4390     gtk_notebook_menu_item_create (notebook, list);
4391
4392   gtk_notebook_update_labels (notebook);
4393   gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
4394                              GTK_WIDGET (notebook),
4395                              gtk_notebook_menu_detacher);
4396
4397   g_object_notify (G_OBJECT (notebook), "enable_popup");
4398 }
4399
4400 /**
4401  * gtk_notebook_popup_disable:
4402  * @notebook: a #GtkNotebook
4403  * 
4404  * Disables the popup menu.
4405  **/
4406 void       
4407 gtk_notebook_popup_disable  (GtkNotebook *notebook)
4408 {
4409   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4410
4411   if (!notebook->menu)
4412     return;
4413
4414   gtk_container_foreach (GTK_CONTAINER (notebook->menu),
4415                          (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
4416   gtk_widget_destroy (notebook->menu);
4417
4418   g_object_notify (G_OBJECT (notebook), "enable_popup");
4419 }
4420
4421 /* Public GtkNotebook Page Properties Functions:
4422  *
4423  * gtk_notebook_get_tab_label
4424  * gtk_notebook_set_tab_label
4425  * gtk_notebook_set_tab_label_text
4426  * gtk_notebook_get_menu_label
4427  * gtk_notebook_set_menu_label
4428  * gtk_notebook_set_menu_label_text
4429  * gtk_notebook_set_tab_label_packing
4430  * gtk_notebook_query_tab_label_packing
4431  */
4432
4433 /**
4434  * gtk_notebook_get_tab_label:
4435  * @notebook: a #GtkNotebook
4436  * @child: the page
4437  * 
4438  * Returns the tab label widget for the page @child. %NULL is returned
4439  * if @child is not in @notebook or if no tab label has specifically
4440  * been set for @child.
4441  * 
4442  * Return value: the tab label
4443  **/
4444 GtkWidget *
4445 gtk_notebook_get_tab_label (GtkNotebook *notebook,
4446                             GtkWidget   *child)
4447 {
4448   GList *list;
4449
4450   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4451   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
4452
4453   list = CHECK_FIND_CHILD (notebook, child);
4454   if (!list)  
4455     return NULL;
4456
4457   if (GTK_NOTEBOOK_PAGE (list)->default_tab)
4458     return NULL;
4459
4460   return GTK_NOTEBOOK_PAGE (list)->tab_label;
4461 }  
4462
4463 /**
4464  * gtk_notebook_set_tab_label:
4465  * @notebook: a #GtkNotebook
4466  * @child: the page
4467  * @tab_label: the tab label widget to use, or %NULL for default tab
4468  *             label.
4469  * 
4470  * Changes the tab label for @child. If %NULL is specified
4471  * for @tab_label, then the page will have the label 'page N'.
4472  **/
4473 void
4474 gtk_notebook_set_tab_label (GtkNotebook *notebook,
4475                             GtkWidget   *child,
4476                             GtkWidget   *tab_label)
4477 {
4478   GtkNotebookPage *page;
4479   GList *list;
4480
4481   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4482   g_return_if_fail (GTK_IS_WIDGET (child));
4483
4484   list = CHECK_FIND_CHILD (notebook, child);
4485   if (!list)  
4486     return;
4487
4488   /* a NULL pointer indicates a default_tab setting, otherwise
4489    * we need to set the associated label
4490    */
4491   page = list->data;
4492   
4493   if (page->tab_label == tab_label)
4494     return;
4495   
4496   gtk_notebook_remove_tab_label (notebook, page);
4497   
4498   if (tab_label)
4499     {
4500       page->default_tab = FALSE;
4501       page->tab_label = tab_label;
4502       gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
4503     }
4504   else
4505     {
4506       page->default_tab = TRUE;
4507       page->tab_label = NULL;
4508
4509       if (notebook->show_tabs)
4510         {
4511           gchar string[32];
4512
4513           g_snprintf (string, sizeof(string), _("Page %u"), 
4514                       gtk_notebook_real_page_position (notebook, list));
4515           page->tab_label = gtk_label_new (string);
4516           gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
4517         }
4518     }
4519
4520   if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
4521     {
4522       gtk_widget_show (page->tab_label);
4523       gtk_widget_queue_resize (GTK_WIDGET (notebook));
4524     }
4525   gtk_widget_child_notify (child, "tab_label");
4526 }
4527
4528 /**
4529  * gtk_notebook_set_tab_label_text:
4530  * @notebook: a #GtkNotebook
4531  * @child: the page
4532  * @tab_text: the label text
4533  * 
4534  * Creates a new label and sets it as the tab label for the page
4535  * containing @child.
4536  **/
4537 void
4538 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
4539                                  GtkWidget   *child,
4540                                  const gchar *tab_text)
4541 {
4542   GtkWidget *tab_label = NULL;
4543
4544   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4545
4546   if (tab_text)
4547     tab_label = gtk_label_new (tab_text);
4548   gtk_notebook_set_tab_label (notebook, child, tab_label);
4549   gtk_widget_child_notify (child, "tab_label");
4550 }
4551
4552 /**
4553  * gtk_notebook_get_tab_label_text:
4554  * @notebook: a #GtkNotebook
4555  * @child: a widget contained in a page of @notebook
4556  *
4557  * Retrieves the text of the tab label for the page containing
4558  *    @child.
4559  *
4560  * Returns value: the text of the tab label, or %NULL if the
4561  *                tab label widget is not a #GtkLabel. The
4562  *                string is owned by the widget and must not
4563  *                be freed.
4564  **/
4565 G_CONST_RETURN gchar *
4566 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
4567                                  GtkWidget   *child)
4568 {
4569   GtkWidget *tab_label;
4570
4571   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4572   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
4573
4574   tab_label = gtk_notebook_get_tab_label (notebook, child);
4575
4576   if (tab_label && GTK_IS_LABEL (tab_label))
4577     return gtk_label_get_text (GTK_LABEL (tab_label));
4578   else
4579     return NULL;
4580 }
4581
4582 /**
4583  * gtk_notebook_get_menu_label:
4584  * @notebook: a #GtkNotebook
4585  * @child: a widget contained in a page of @notebook
4586  * 
4587  * Retrieves the menu label widget of the page containing @child.
4588  * 
4589  * Return value: the menu label, or %NULL if the
4590  *               notebook page does not have a menu label other
4591  *               than the default (the tab label).
4592  **/
4593 GtkWidget*
4594 gtk_notebook_get_menu_label (GtkNotebook *notebook,
4595                              GtkWidget   *child)
4596 {
4597   GList *list;
4598
4599   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4600   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
4601
4602   list = CHECK_FIND_CHILD (notebook, child);
4603   if (!list)  
4604     return NULL;
4605
4606   if (GTK_NOTEBOOK_PAGE (list)->default_menu)
4607     return NULL;
4608
4609   return GTK_NOTEBOOK_PAGE (list)->menu_label;
4610 }  
4611
4612 /**
4613  * gtk_notebook_set_menu_label:
4614  * @notebook: a #GtkNotebook
4615  * @child: the child widget
4616  * @menu_label: the menu label, or NULL for default
4617  * 
4618  * Changes the menu label for the page containing @child. 
4619  **/
4620 void
4621 gtk_notebook_set_menu_label (GtkNotebook *notebook,
4622                              GtkWidget   *child,
4623                              GtkWidget   *menu_label)
4624 {
4625   GtkNotebookPage *page;
4626   GList *list;
4627
4628   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4629   g_return_if_fail (GTK_IS_WIDGET (child));
4630
4631   list = CHECK_FIND_CHILD (notebook, child);
4632   if (!list)  
4633     return;
4634
4635   page = list->data;
4636   if (page->menu_label)
4637     {
4638       if (notebook->menu)
4639         gtk_container_remove (GTK_CONTAINER (notebook->menu), 
4640                               page->menu_label->parent);
4641
4642       if (!page->default_menu)
4643         gtk_widget_unref (page->menu_label);
4644     }
4645
4646   if (menu_label)
4647     {
4648       page->menu_label = menu_label;
4649       gtk_widget_ref (page->menu_label);
4650       gtk_object_sink (GTK_OBJECT(page->menu_label));
4651       page->default_menu = FALSE;
4652     }
4653   else
4654     page->default_menu = TRUE;
4655
4656   if (notebook->menu)
4657     gtk_notebook_menu_item_create (notebook, list);
4658   gtk_widget_child_notify (child, "menu_label");
4659 }
4660
4661 /**
4662  * gtk_notebook_set_menu_label_text:
4663  * @notebook: a #GtkNotebook
4664  * @child: the child widget
4665  * @menu_text: the label text
4666  * 
4667  * Creates a new label and sets it as the menu label of @child.
4668  **/
4669 void
4670 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
4671                                   GtkWidget   *child,
4672                                   const gchar *menu_text)
4673 {
4674   GtkWidget *menu_label = NULL;
4675
4676   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4677
4678   if (menu_text)
4679     menu_label = gtk_label_new (menu_text);
4680   gtk_notebook_set_menu_label (notebook, child, menu_label);
4681   gtk_widget_child_notify (child, "menu_label");
4682 }
4683
4684 /**
4685  * gtk_notebook_get_menu_label_text:
4686  * @notebook: a #GtkNotebook
4687  * @child: the child widget of a page of the notebook.
4688  *
4689  * Retrieves the text of the menu label for the page containing
4690  *    @child.
4691  *
4692  * Returns value: the text of the tab label, or %NULL if the
4693  *                widget does not have a menu label other than
4694  *                the default menu label, or the menu label widget
4695  *                is not a #GtkLabel. The string is owned by
4696  *                the widget and must not be freed.
4697  **/
4698 G_CONST_RETURN gchar *
4699 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
4700                                   GtkWidget *child)
4701 {
4702   GtkWidget *menu_label;
4703
4704   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4705   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
4706  
4707   menu_label = gtk_notebook_get_menu_label (notebook, child);
4708
4709   if (menu_label && GTK_IS_LABEL (menu_label))
4710     return gtk_label_get_text (GTK_LABEL (menu_label));
4711   else
4712     return NULL;
4713 }
4714   
4715 /* Helper function called when pages are reordered
4716  */
4717 static void
4718 gtk_notebook_child_reordered (GtkNotebook     *notebook,
4719                               GtkNotebookPage *page)
4720 {
4721   if (notebook->menu)
4722     {
4723       GtkWidget *menu_item;
4724       
4725       menu_item = page->menu_label->parent;
4726       gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
4727       gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
4728       gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
4729     }
4730   
4731   gtk_notebook_update_labels (notebook);
4732 }
4733
4734 /**
4735  * gtk_notebook_set_tab_label_packing:
4736  * @notebook: a #GtkNotebook
4737  * @child: the child widget
4738  * @expand: whether to expand the bookmark or not
4739  * @fill: whether the bookmark should fill the allocated area or not
4740  * @pack_type: the position of the bookmark
4741  * 
4742  * Sets the packing parameters for the tab label of the page
4743  * containing @child. See gtk_box_pack_start() for the exact meaning
4744  * of the parameters.
4745  **/
4746 void
4747 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
4748                                     GtkWidget   *child,
4749                                     gboolean     expand,
4750                                     gboolean     fill,
4751                                     GtkPackType  pack_type)
4752 {
4753   GtkNotebookPage *page;
4754   GList *list;
4755
4756   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4757   g_return_if_fail (GTK_IS_WIDGET (child));
4758
4759   list = CHECK_FIND_CHILD (notebook, child);
4760   if (!list)  
4761     return;
4762
4763   page = list->data;
4764   expand = expand != FALSE;
4765   fill = fill != FALSE;
4766   if (page->pack == pack_type && page->expand == expand && page->fill == fill)
4767     return;
4768
4769   gtk_widget_freeze_child_notify (child);
4770   page->expand = expand;
4771   gtk_widget_child_notify (child, "tab_expand");
4772   page->fill = fill;
4773   gtk_widget_child_notify (child, "tab_fill");
4774   if (page->pack != pack_type)
4775     {
4776       page->pack = pack_type;
4777       gtk_notebook_child_reordered (notebook, page);
4778     }
4779   gtk_widget_child_notify (child, "tab_pack");
4780   gtk_widget_child_notify (child, "position");
4781   if (notebook->show_tabs)
4782     gtk_notebook_pages_allocate (notebook);
4783   gtk_widget_thaw_child_notify (child);
4784 }  
4785
4786 /**
4787  * gtk_notebook_query_tab_label_packing:
4788  * @notebook: a #GtkNotebook
4789  * @child: the page
4790  * @expand: location to store the expand value (or NULL)
4791  * @fill: location to store the fill value (or NULL)
4792  * @pack_type: location to store the pack_type (or NULL)
4793  * 
4794  * Query the packing attributes for the tab label of the page
4795  * containing @child.
4796  **/
4797 void
4798 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
4799                                       GtkWidget   *child,
4800                                       gboolean    *expand,
4801                                       gboolean    *fill,
4802                                       GtkPackType *pack_type)
4803 {
4804   GList *list;
4805
4806   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4807   g_return_if_fail (GTK_IS_WIDGET (child));
4808
4809   list = CHECK_FIND_CHILD (notebook, child);
4810   if (!list)
4811     return;
4812
4813   if (expand)
4814     *expand = GTK_NOTEBOOK_PAGE (list)->expand;
4815   if (fill)
4816     *fill = GTK_NOTEBOOK_PAGE (list)->fill;
4817   if (pack_type)
4818     *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
4819 }
4820
4821 /**
4822  * gtk_notebook_reorder_child:
4823  * @notebook: a #GtkNotebook
4824  * @child: the child to move
4825  * @position: the new position
4826  * 
4827  * Reorders the page containing @child, so that it appears in position
4828  * @position. Out of bounds @position will be clamped.
4829  **/
4830 void
4831 gtk_notebook_reorder_child (GtkNotebook *notebook,
4832                             GtkWidget   *child,
4833                             gint         position)
4834 {
4835   GList *list, *new_list;
4836   GtkNotebookPage *page;
4837   gint old_pos;
4838
4839   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4840   g_return_if_fail (GTK_IS_WIDGET (child));
4841
4842   list = CHECK_FIND_CHILD (notebook, child);
4843   if (!list)
4844     return;
4845
4846   old_pos = g_list_position (notebook->children, list);
4847
4848   if (old_pos == position)
4849     return;
4850
4851   page = list->data;
4852   notebook->children = g_list_delete_link (notebook->children, list);
4853
4854   position = CLAMP (position, 0, g_list_length (notebook->children));
4855
4856   notebook->children = g_list_insert (notebook->children, page, position);
4857   new_list = g_list_nth (notebook->children, position);
4858
4859   /* Fix up GList references in GtkNotebook structure */
4860   if (notebook->first_tab == list)
4861     notebook->first_tab = new_list;
4862   if (notebook->focus_tab == list)
4863     notebook->focus_tab = new_list;
4864
4865   gtk_widget_freeze_child_notify (child);
4866
4867   /* Move around the menu items if necesary */
4868   gtk_notebook_child_reordered (notebook, page);
4869   gtk_widget_child_notify (child, "tab_pack");
4870   gtk_widget_child_notify (child, "position");
4871   
4872   if (notebook->show_tabs)
4873     gtk_notebook_pages_allocate (notebook);
4874
4875   gtk_widget_thaw_child_notify (child);
4876 }