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