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