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