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