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