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