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