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