]> Pileus Git - ~andy/gtk/blob - gtk/gtknotebook.c
new default color scheme based on the GNOME stock icon palette. (#80691,
[~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         gdk_window_move_resize (notebook->event_window,
1313                                 position.x, position.y,
1314                                 position.width, position.height);
1315     }
1316
1317   if (notebook->children)
1318     {
1319       gint border_width = GTK_CONTAINER (widget)->border_width;
1320       GtkNotebookPage *page;
1321       GtkAllocation child_allocation;
1322       GList *children;
1323       
1324       child_allocation.x = widget->allocation.x + border_width;
1325       child_allocation.y = widget->allocation.y + border_width;
1326       child_allocation.width = MAX (1, allocation->width - border_width * 2);
1327       child_allocation.height = MAX (1, allocation->height - border_width * 2);
1328
1329       if (notebook->show_tabs || notebook->show_border)
1330         {
1331           child_allocation.x += widget->style->xthickness;
1332           child_allocation.y += widget->style->ythickness;
1333           child_allocation.width = MAX (1, child_allocation.width -
1334                                         widget->style->xthickness * 2);
1335           child_allocation.height = MAX (1, child_allocation.height -
1336                                          widget->style->ythickness * 2);
1337
1338           if (notebook->show_tabs && notebook->children && notebook->cur_page)
1339             {
1340               switch (notebook->tab_pos)
1341                 {
1342                 case GTK_POS_TOP:
1343                   child_allocation.y += notebook->cur_page->requisition.height;
1344                 case GTK_POS_BOTTOM:
1345                   child_allocation.height =
1346                     MAX (1, child_allocation.height -
1347                          notebook->cur_page->requisition.height);
1348                   break;
1349                 case GTK_POS_LEFT:
1350                   child_allocation.x += notebook->cur_page->requisition.width;
1351                 case GTK_POS_RIGHT:
1352                   child_allocation.width =
1353                     MAX (1, child_allocation.width -
1354                          notebook->cur_page->requisition.width);
1355                   break;
1356                 }
1357             }
1358         }
1359
1360       children = notebook->children;
1361       while (children)
1362         {
1363           page = children->data;
1364           children = children->next;
1365           
1366           if (GTK_WIDGET_VISIBLE (page->child))
1367             {
1368               gtk_widget_size_allocate (page->child, &child_allocation);
1369               vis_pages++;
1370             }
1371         }
1372
1373       gtk_notebook_pages_allocate (notebook);
1374     }
1375
1376   if ((vis_pages != 0) != notebook->have_visible_child)
1377     {
1378       notebook->have_visible_child = (vis_pages != 0);
1379       if (notebook->show_tabs)
1380         gtk_widget_queue_draw (widget);
1381     }
1382 }
1383
1384 static gint
1385 gtk_notebook_expose (GtkWidget      *widget,
1386                      GdkEventExpose *event)
1387 {
1388   GtkNotebook *notebook;
1389   GdkRectangle child_area;
1390    
1391   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1392   g_return_val_if_fail (event != NULL, FALSE);
1393
1394   if (GTK_WIDGET_DRAWABLE (widget))
1395     {
1396       notebook = GTK_NOTEBOOK (widget);
1397
1398       gtk_notebook_paint (widget, &event->area);
1399       if (notebook->show_tabs)
1400         {
1401           if (notebook->cur_page && 
1402               gtk_widget_intersect (notebook->cur_page->tab_label, 
1403                                     &event->area, &child_area))
1404             gtk_notebook_draw_focus (widget);
1405         }
1406
1407       
1408       if (notebook->cur_page)
1409         gtk_container_propagate_expose (GTK_CONTAINER (notebook),
1410                                         notebook->cur_page->child,
1411                                         event);
1412     }
1413
1414   return FALSE;
1415 }
1416
1417 static gboolean
1418 gtk_notebook_show_arrows (GtkNotebook *notebook)
1419 {
1420   gboolean show_arrow = FALSE;
1421   GList *children;
1422   
1423   if (!notebook->scrollable)
1424     return FALSE;
1425
1426   children = notebook->children;
1427   while (children)
1428     {
1429       GtkNotebookPage *page = children->data;
1430
1431       if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
1432         show_arrow = TRUE;
1433
1434       children = children->next;
1435     }
1436
1437   return show_arrow;
1438 }
1439
1440 static void
1441 gtk_notebook_get_arrow_rect (GtkNotebook  *notebook,
1442                              GdkRectangle *rectangle)
1443 {
1444   GdkRectangle event_window_pos;
1445
1446   if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
1447     {
1448       rectangle->width = 2 * ARROW_SIZE + ARROW_SPACING;
1449       rectangle->height = ARROW_SIZE;
1450
1451       switch (notebook->tab_pos)
1452         {
1453         case GTK_POS_LEFT:
1454         case GTK_POS_RIGHT:
1455           rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
1456           rectangle->y = event_window_pos.y + event_window_pos.height - rectangle->height;
1457           break;
1458         case GTK_POS_TOP:
1459         case GTK_POS_BOTTOM:
1460           rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
1461           rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
1462           break;
1463         }
1464     }
1465 }
1466
1467 static GtkArrowType
1468 gtk_notebook_get_arrow (GtkNotebook *notebook,
1469                         gint         x,
1470                         gint         y)
1471 {
1472   GdkRectangle arrow_rect;
1473   GdkRectangle event_window_pos;
1474
1475   if (gtk_notebook_show_arrows (notebook))
1476     {
1477       gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1478       gtk_notebook_get_arrow_rect (notebook, &arrow_rect);
1479       
1480       x -= arrow_rect.x;
1481       y -= arrow_rect.y;
1482       
1483       if (y >= 0 && y < arrow_rect.height)
1484         {
1485           if (x >= 0 && x < ARROW_SIZE + ARROW_SPACING / 2)
1486             return GTK_ARROW_LEFT;
1487           else if (x >= ARROW_SIZE + ARROW_SPACING / 2 && x < arrow_rect.width)
1488             return GTK_ARROW_RIGHT;
1489         }
1490     }
1491       
1492   return 0;
1493 }
1494
1495 static void
1496 gtk_notebook_do_arrow (GtkNotebook    *notebook,
1497                        GtkArrowType    arrow)
1498 {
1499   GtkWidget *widget = GTK_WIDGET (notebook);
1500   GtkDirectionType dir;
1501   
1502   if (!notebook->focus_tab ||
1503       gtk_notebook_search_page (notebook, notebook->focus_tab,
1504                                 arrow == GTK_ARROW_LEFT ? STEP_PREV : STEP_NEXT,
1505                                 TRUE))
1506     {
1507       if (notebook->tab_pos == GTK_POS_LEFT ||
1508           notebook->tab_pos == GTK_POS_RIGHT)
1509         dir = (arrow == GTK_ARROW_LEFT) ? GTK_DIR_UP : GTK_DIR_DOWN;
1510       else
1511         dir = (arrow == GTK_ARROW_LEFT) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
1512       gtk_widget_child_focus (widget, dir);
1513     }
1514 }
1515
1516 static gboolean
1517 gtk_notebook_arrow_button_press (GtkNotebook    *notebook,
1518                                  GtkArrowType    arrow,
1519                                  GdkEventButton *event)
1520 {
1521   GtkWidget *widget = GTK_WIDGET (notebook);
1522   
1523   if (!GTK_WIDGET_HAS_FOCUS (widget))
1524     gtk_widget_grab_focus (widget);
1525   
1526   notebook->button = event->button;
1527   notebook->click_child = arrow;
1528   
1529   if (event->button == 1)
1530     {
1531       gtk_notebook_do_arrow (notebook, arrow);
1532       
1533       if (!notebook->timer)
1534         {
1535           notebook->timer = gtk_timeout_add 
1536             (NOTEBOOK_INIT_SCROLL_DELAY, 
1537              (GtkFunction) gtk_notebook_timer, (gpointer) notebook);
1538           notebook->need_timer = TRUE;
1539         }
1540     }
1541   else if (event->button == 2)
1542     gtk_notebook_page_select (notebook, TRUE);
1543   else if (event->button == 3)
1544     gtk_notebook_switch_focus_tab (notebook,
1545                                    gtk_notebook_search_page (notebook,
1546                                                              NULL,
1547                                                              arrow == GTK_ARROW_LEFT ? STEP_NEXT : STEP_PREV,
1548                                                              TRUE));
1549   gtk_notebook_redraw_arrows (notebook);
1550
1551   return TRUE;
1552 }
1553
1554 static gboolean
1555 get_widget_coordinates (GtkWidget *widget,
1556                         GdkEvent  *event,
1557                         gint      *x,
1558                         gint      *y)
1559 {
1560   GdkWindow *window = ((GdkEventAny *)event)->window;
1561   gdouble tx, ty;
1562
1563   if (!gdk_event_get_coords (event, &tx, &ty))
1564     return FALSE;
1565
1566   while (window && window != widget->window)
1567     {
1568       gint window_x, window_y;
1569       
1570       gdk_window_get_position (window, &window_x, &window_y);
1571       tx += window_x;
1572       ty += window_y;
1573
1574       window = gdk_window_get_parent (window);
1575     }
1576
1577   if (window)
1578     {
1579       *x = tx;
1580       *y = ty;
1581
1582       return TRUE;
1583     }
1584   else
1585     return FALSE;
1586 }
1587
1588 static gboolean
1589 gtk_notebook_button_press (GtkWidget      *widget,
1590                            GdkEventButton *event)
1591 {
1592   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1593   GtkNotebookPage *page;
1594   GList *children;
1595   GtkArrowType arrow;
1596   gint num;
1597   gint x, y;
1598
1599   if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
1600       notebook->button)
1601     return FALSE;
1602
1603   if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
1604     return FALSE;
1605
1606   arrow = gtk_notebook_get_arrow (notebook, x, y);
1607   if (arrow)
1608     return gtk_notebook_arrow_button_press (notebook, arrow, event);
1609
1610   if (event->button == 3 && notebook->menu)
1611     {
1612       gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL, 
1613                       NULL, NULL, 3, event->time);
1614       return TRUE;
1615     }
1616
1617   if (event->button != 1)
1618     return FALSE;
1619   
1620   num = 0;
1621   children = notebook->children;
1622   while (children)
1623     {
1624       page = children->data;
1625       
1626       if (GTK_WIDGET_VISIBLE (page->child) &&
1627           page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
1628           (x >= page->allocation.x) &&
1629           (y >= page->allocation.y) &&
1630           (x <= (page->allocation.x + page->allocation.width)) &&
1631           (y <= (page->allocation.y + page->allocation.height)))
1632         {
1633           gboolean page_changed = page != notebook->cur_page;
1634           gboolean was_focus = gtk_widget_is_focus (widget);
1635           
1636           gtk_notebook_switch_focus_tab (notebook, children);
1637           gtk_widget_grab_focus (widget);
1638           
1639           if (page_changed && !was_focus)
1640             gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
1641           
1642           break;
1643         }
1644       children = children->next;
1645       num++;
1646     }
1647   if (!children && !GTK_WIDGET_HAS_FOCUS (widget))
1648     gtk_widget_grab_focus (widget);
1649   
1650   return TRUE;
1651 }
1652
1653 static gint
1654 gtk_notebook_button_release (GtkWidget      *widget,
1655                              GdkEventButton *event)
1656 {
1657   GtkNotebook *notebook;
1658
1659   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1660   g_return_val_if_fail (event != NULL, FALSE);
1661
1662   if (event->type != GDK_BUTTON_RELEASE)
1663     return FALSE;
1664
1665   notebook = GTK_NOTEBOOK (widget);
1666
1667   if (event->button == notebook->button)
1668     {
1669       guint click_child;
1670
1671       if (notebook->timer)
1672         {
1673           gtk_timeout_remove (notebook->timer);
1674           notebook->timer = 0;
1675           notebook->need_timer = FALSE;
1676         }
1677       click_child = notebook->click_child;
1678       notebook->click_child = 0;
1679       notebook->button = 0;
1680       gtk_notebook_redraw_arrows (notebook);
1681
1682       return TRUE;
1683     }
1684   else
1685     return FALSE;
1686 }
1687
1688 static gint
1689 gtk_notebook_enter_notify (GtkWidget        *widget,
1690                            GdkEventCrossing *event)
1691 {
1692   GtkNotebook *notebook;
1693   GtkArrowType arrow;
1694   gint x, y;
1695
1696   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1697   g_return_val_if_fail (event != NULL, FALSE);
1698
1699   notebook = GTK_NOTEBOOK (widget);
1700
1701   if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
1702     return FALSE;
1703
1704   arrow = gtk_notebook_get_arrow (notebook, x, y);
1705
1706   if (arrow != notebook->in_child)
1707     {
1708       notebook->in_child = arrow;
1709       gtk_notebook_redraw_arrows (notebook);
1710
1711       return TRUE;
1712     }
1713
1714   return TRUE;
1715 }
1716
1717 static gint
1718 gtk_notebook_leave_notify (GtkWidget        *widget,
1719                            GdkEventCrossing *event)
1720 {
1721   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1722   GtkArrowType arrow;
1723   gint x, y;
1724
1725   if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
1726     return FALSE;
1727
1728   arrow = gtk_notebook_get_arrow (notebook, x, y);
1729
1730   if (notebook->in_child)
1731     {
1732       notebook->in_child = 0;
1733       gtk_notebook_redraw_arrows (notebook);
1734     }
1735
1736   return TRUE;
1737 }
1738
1739 static gint
1740 gtk_notebook_motion_notify (GtkWidget      *widget,
1741                             GdkEventMotion *event)
1742 {
1743   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1744   GtkArrowType arrow;
1745   gint x, y;
1746   
1747   if (notebook->button)
1748     return FALSE;
1749
1750   if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
1751     return FALSE;
1752
1753   arrow = gtk_notebook_get_arrow (notebook, x, y);
1754
1755   if (arrow != notebook->in_child)
1756     {
1757       notebook->in_child = arrow;
1758       gtk_notebook_redraw_arrows (notebook);
1759     }
1760   
1761   return TRUE;
1762 }
1763
1764 static gint
1765 gtk_notebook_focus_in (GtkWidget     *widget,
1766                        GdkEventFocus *event)
1767 {
1768   GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
1769
1770   return (* GTK_WIDGET_CLASS (parent_class)->focus_in_event) (widget, event);
1771 }
1772
1773 static void
1774 gtk_notebook_draw_focus (GtkWidget *widget)
1775 {
1776   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1777
1778   if (GTK_WIDGET_DRAWABLE (widget) && notebook->show_tabs &&
1779       notebook->focus_tab)
1780     {
1781       GtkNotebookPage *page;
1782       GdkRectangle area;
1783       gint focus_width;
1784       
1785       gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
1786
1787       page = notebook->focus_tab->data;
1788
1789       area.x = page->tab_label->allocation.x - focus_width;
1790       area.y = page->tab_label->allocation.y - focus_width;
1791       area.width = page->tab_label->allocation.width + 2 * focus_width;
1792       area.height = page->tab_label->allocation.height + 2 * focus_width;
1793
1794       gtk_notebook_draw_tab (GTK_NOTEBOOK (widget), page, &area);
1795     }
1796 }
1797
1798 /* Private GtkContainer Methods :
1799  * 
1800  * gtk_notebook_set_child_arg
1801  * gtk_notebook_get_child_arg
1802  * gtk_notebook_add
1803  * gtk_notebook_remove
1804  * gtk_notebook_focus
1805  * gtk_notebook_set_focus_child
1806  * gtk_notebook_child_type
1807  * gtk_notebook_forall
1808  */
1809 static void
1810 gtk_notebook_set_child_property (GtkContainer    *container,
1811                                  GtkWidget       *child,
1812                                  guint            property_id,
1813                                  const GValue    *value,
1814                                  GParamSpec      *pspec)
1815 {
1816   gboolean expand;
1817   gboolean fill;
1818   GtkPackType pack_type;
1819
1820   /* not finding child's page is valid for menus or labels */
1821   if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
1822     return;
1823
1824   switch (property_id)
1825     {
1826     case CHILD_PROP_TAB_LABEL:
1827       /* a NULL pointer indicates a default_tab setting, otherwise
1828        * we need to set the associated label
1829        */
1830       gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
1831                                        g_value_get_string (value));
1832       break;
1833     case CHILD_PROP_MENU_LABEL:
1834       gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
1835                                         g_value_get_string (value));
1836       break;
1837     case CHILD_PROP_POSITION:
1838       gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
1839                                   g_value_get_int (value));
1840       break;
1841     case CHILD_PROP_TAB_EXPAND:
1842       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
1843                                             &expand, &fill, &pack_type);
1844       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
1845                                           g_value_get_boolean (value),
1846                                           fill, pack_type);
1847       break;
1848     case CHILD_PROP_TAB_FILL:
1849       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
1850                                             &expand, &fill, &pack_type);
1851       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
1852                                           expand,
1853                                           g_value_get_boolean (value),
1854                                           pack_type);
1855       break;
1856     case CHILD_PROP_TAB_PACK:
1857       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
1858                                             &expand, &fill, &pack_type);
1859       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
1860                                           expand, fill,
1861                                           g_value_get_enum (value));
1862       break;
1863     default:
1864       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
1865       break;
1866     }
1867 }
1868
1869 static void
1870 gtk_notebook_get_child_property (GtkContainer    *container,
1871                                  GtkWidget       *child,
1872                                  guint            property_id,
1873                                  GValue          *value,
1874                                  GParamSpec      *pspec)
1875 {
1876   GList *list;
1877   GtkNotebook *notebook;
1878   GtkWidget *label;
1879   gboolean expand;
1880   gboolean fill;
1881   GtkPackType pack_type;
1882
1883   notebook = GTK_NOTEBOOK (container);
1884
1885   /* not finding child's page is valid for menus or labels */
1886   list = gtk_notebook_find_child (notebook, child, NULL);
1887   if (!list)
1888     {
1889       /* nothing to set on labels or menus */
1890       g_param_value_set_default (pspec, value);
1891       return;
1892     }
1893
1894   switch (property_id)
1895     {
1896     case CHILD_PROP_TAB_LABEL:
1897       label = gtk_notebook_get_tab_label (notebook, child);
1898
1899       if (label && GTK_IS_LABEL (label))
1900         g_value_set_string (value, GTK_LABEL (label)->label);
1901       else
1902         g_value_set_string (value, NULL);
1903       break;
1904     case CHILD_PROP_MENU_LABEL:
1905       label = gtk_notebook_get_menu_label (notebook, child);
1906
1907       if (label && GTK_IS_LABEL (label))
1908         g_value_set_string (value, GTK_LABEL (label)->label);
1909       else
1910         g_value_set_string (value, NULL);
1911       break;
1912     case CHILD_PROP_POSITION:
1913       g_value_set_int (value, g_list_position (notebook->children, list));
1914       break;
1915     case CHILD_PROP_TAB_EXPAND:
1916         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
1917                                               &expand, NULL, NULL);
1918         g_value_set_boolean (value, expand);
1919       break;
1920     case CHILD_PROP_TAB_FILL:
1921         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
1922                                               NULL, &fill, NULL);
1923         g_value_set_boolean (value, fill);
1924       break;
1925     case CHILD_PROP_TAB_PACK:
1926         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
1927                                               NULL, NULL, &pack_type);
1928         g_value_set_enum (value, pack_type);
1929       break;
1930     default:
1931       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
1932       break;
1933     }
1934 }
1935
1936 static void
1937 gtk_notebook_add (GtkContainer *container,
1938                   GtkWidget    *widget)
1939 {
1940   g_return_if_fail (GTK_IS_NOTEBOOK (container));
1941
1942   gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget, 
1943                                  NULL, NULL, -1);
1944 }
1945
1946 static void
1947 gtk_notebook_remove (GtkContainer *container,
1948                      GtkWidget    *widget)
1949 {
1950   GtkNotebook *notebook;
1951   GtkNotebookPage *page;
1952   GList *children;
1953   guint page_num;
1954
1955   g_return_if_fail (GTK_IS_NOTEBOOK (container));
1956   g_return_if_fail (widget != NULL);
1957
1958   notebook = GTK_NOTEBOOK (container);
1959
1960   children = notebook->children;
1961   page_num = 0;
1962   while (children)
1963     {
1964       page = children->data;
1965       if (page->child == widget)
1966         {
1967           gtk_notebook_real_remove (notebook, children, FALSE);
1968           break;
1969         }
1970       page_num++;
1971       children = children->next;
1972     }
1973 }
1974
1975 static gboolean
1976 focus_tabs_in (GtkNotebook *notebook)
1977 {
1978   if (notebook->show_tabs && notebook->cur_page)
1979     {
1980       gtk_widget_grab_focus (GTK_WIDGET (notebook));
1981
1982       gtk_notebook_switch_focus_tab (notebook,
1983                                      g_list_find (notebook->children,
1984                                                   notebook->cur_page));
1985
1986       return TRUE;
1987     }
1988   else
1989     return FALSE;
1990 }
1991
1992 static gboolean
1993 focus_tabs_move (GtkNotebook     *notebook,
1994                  GtkDirectionType direction,
1995                  gint             search_direction)
1996 {
1997   GList *new_page;
1998
1999   new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
2000                                        search_direction, TRUE);
2001   if (new_page)
2002     gtk_notebook_switch_focus_tab (notebook, new_page);
2003   else
2004     gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
2005   
2006   return TRUE;
2007 }
2008
2009 static gboolean
2010 focus_child_in (GtkNotebook     *notebook,
2011                 GtkDirectionType direction)
2012 {
2013   if (notebook->cur_page)
2014     return gtk_widget_child_focus (notebook->cur_page->child, direction);
2015   else
2016     return FALSE;
2017 }
2018
2019 /* Focus in the notebook can either be on the pages, or on
2020  * the tabs.
2021  */
2022 static gint
2023 gtk_notebook_focus (GtkWidget        *widget,
2024                     GtkDirectionType  direction)
2025 {
2026   GtkWidget *old_focus_child;
2027   GtkNotebook *notebook;
2028   GtkDirectionType effective_direction;
2029
2030   gboolean widget_is_focus;
2031   GtkContainer *container;
2032
2033   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2034
2035   container = GTK_CONTAINER (widget);
2036   notebook = GTK_NOTEBOOK (container);
2037
2038   if (notebook->focus_out)
2039     {
2040       notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
2041       return FALSE;
2042     }
2043
2044   widget_is_focus = gtk_widget_is_focus (widget);
2045   old_focus_child = container->focus_child; 
2046
2047   effective_direction = get_effective_direction (notebook, direction);
2048
2049   if (old_focus_child)          /* Focus on page child */
2050     {
2051       if (gtk_widget_child_focus (old_focus_child, direction))
2052         return TRUE;
2053       
2054       switch (effective_direction)
2055         {
2056         case GTK_DIR_TAB_BACKWARD:
2057         case GTK_DIR_UP:
2058           /* Focus onto the tabs */
2059           return focus_tabs_in (notebook);
2060         case GTK_DIR_DOWN:
2061         case GTK_DIR_TAB_FORWARD:
2062         case GTK_DIR_LEFT:
2063         case GTK_DIR_RIGHT:
2064           return FALSE;
2065         }
2066     }
2067   else if (widget_is_focus)     /* Focus was on tabs */
2068     {
2069       switch (effective_direction)
2070         {
2071         case GTK_DIR_TAB_BACKWARD:
2072         case GTK_DIR_UP:
2073           return FALSE;
2074         case GTK_DIR_TAB_FORWARD:
2075         case GTK_DIR_DOWN:
2076           /* We use TAB_FORWARD rather than direction so that we focus a more
2077            * predictable widget for the user; users may be using arrow focusing
2078            * in this situation even if they don't usually use arrow focusing.
2079            */
2080           return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
2081         case GTK_DIR_LEFT:
2082           return focus_tabs_move (notebook, direction, STEP_PREV);
2083         case GTK_DIR_RIGHT:
2084           return focus_tabs_move (notebook, direction, STEP_NEXT);
2085         }
2086     }
2087   else /* Focus was not on widget */
2088     {
2089       switch (effective_direction)
2090         {
2091         case GTK_DIR_TAB_FORWARD:
2092         case GTK_DIR_DOWN:
2093           if (focus_tabs_in (notebook))
2094             return TRUE;
2095           if (focus_child_in (notebook, direction))
2096             return TRUE;
2097           return FALSE;
2098         case GTK_DIR_TAB_BACKWARD:
2099         case GTK_DIR_UP:
2100           if (focus_child_in (notebook, direction))
2101             return TRUE;
2102           if (focus_tabs_in (notebook))
2103             return TRUE;
2104           return FALSE;
2105         case GTK_DIR_LEFT:
2106         case GTK_DIR_RIGHT:
2107           return focus_child_in (notebook, direction);
2108         }
2109     }
2110
2111   g_assert_not_reached ();
2112   return FALSE;
2113 }  
2114
2115 static void
2116 gtk_notebook_set_focus_child (GtkContainer *container,
2117                               GtkWidget    *child)
2118 {
2119   GtkNotebook *notebook = GTK_NOTEBOOK (container);
2120   GtkWidget *page_child;
2121   GtkWidget *toplevel;
2122
2123   /* If the old focus widget was within a page of the notebook,
2124    * (child may either be NULL or not in this case), record it
2125    * for future use if we switch to the page with a mnemonic.
2126    */
2127
2128   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
2129   if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
2130     {
2131       page_child = GTK_WINDOW (toplevel)->focus_widget; 
2132       while (page_child)
2133         {
2134           if (page_child->parent == GTK_WIDGET (container))
2135             {
2136               GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
2137               if (list != NULL) 
2138                 {
2139                   GtkNotebookPage *page = list->data;
2140               
2141                   if (page->last_focus_child)
2142                     g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
2143                   
2144                   page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
2145                   g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
2146               
2147                   break;
2148                 }
2149             }
2150
2151           page_child = page_child->parent;
2152         }
2153     }
2154   
2155   if (child)
2156     {
2157       g_return_if_fail (GTK_IS_WIDGET (child));
2158
2159       notebook->child_has_focus = TRUE;
2160       if (!notebook->focus_tab)
2161         {
2162           GList *children;
2163           GtkNotebookPage *page;
2164
2165           children = notebook->children;
2166           while (children)
2167             {
2168               page = children->data;
2169               if (page->child == child || page->tab_label == child)
2170                 gtk_notebook_switch_focus_tab (notebook, children);
2171               children = children->next;
2172             }
2173         }
2174     }
2175
2176   parent_class->set_focus_child (container, child);
2177 }
2178
2179 static void
2180 gtk_notebook_forall (GtkContainer *container,
2181                      gboolean      include_internals,
2182                      GtkCallback   callback,
2183                      gpointer      callback_data)
2184 {
2185   GtkNotebook *notebook;
2186   GList *children;
2187
2188   g_return_if_fail (GTK_IS_NOTEBOOK (container));
2189   g_return_if_fail (callback != NULL);
2190
2191   notebook = GTK_NOTEBOOK (container);
2192
2193   children = notebook->children;
2194   while (children)
2195     {
2196       GtkNotebookPage *page;
2197       
2198       page = children->data;
2199       children = children->next;
2200       (* callback) (page->child, callback_data);
2201       if (include_internals)
2202         {
2203           if (page->tab_label)
2204             (* callback) (page->tab_label, callback_data);
2205           if (page->menu_label)
2206             (* callback) (page->menu_label, callback_data);
2207         }
2208     }
2209 }
2210
2211 static GType
2212 gtk_notebook_child_type (GtkContainer     *container)
2213 {
2214   return GTK_TYPE_WIDGET;
2215 }
2216
2217 /* Private GtkNotebook Functions:
2218  *
2219  * gtk_notebook_redraw_tabs
2220  * gtk_notebook_real_remove
2221  * gtk_notebook_update_labels
2222  * gtk_notebook_timer
2223  * gtk_notebook_page_compare
2224  * gtk_notebook_real_page_position
2225  * gtk_notebook_search_page
2226  */
2227 static void
2228 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
2229 {
2230   GtkWidget *widget;
2231   GtkNotebookPage *page;
2232   GdkRectangle redraw_rect;
2233   gint border;
2234
2235   widget = GTK_WIDGET (notebook);
2236   border = GTK_CONTAINER (notebook)->border_width;
2237
2238   if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
2239     return;
2240
2241   page = notebook->first_tab->data;
2242
2243   redraw_rect.x = border;
2244   redraw_rect.y = border;
2245
2246   switch (notebook->tab_pos)
2247     {
2248     case GTK_POS_BOTTOM:
2249       redraw_rect.y = (widget->allocation.height - border -
2250                        page->allocation.height -
2251                        widget->style->ythickness);
2252       if (page != notebook->cur_page)
2253         redraw_rect.y -= widget->style->ythickness;
2254       /* fall through */
2255     case GTK_POS_TOP:
2256       redraw_rect.width = widget->allocation.width - 2 * border;
2257       redraw_rect.height = (page->allocation.height +
2258                             widget->style->ythickness);
2259       if (page != notebook->cur_page)
2260         redraw_rect.height += widget->style->ythickness;
2261       break;
2262     case GTK_POS_RIGHT:
2263       redraw_rect.x = (widget->allocation.width - border -
2264                        page->allocation.width -
2265                        widget->style->xthickness);
2266       if (page != notebook->cur_page)
2267         redraw_rect.x -= widget->style->xthickness;
2268       /* fall through */
2269     case GTK_POS_LEFT:
2270       redraw_rect.width = (page->allocation.width +
2271                            widget->style->xthickness);
2272       redraw_rect.height = widget->allocation.height - 2 * border;
2273       if (page != notebook->cur_page)
2274         redraw_rect.width += widget->style->xthickness;
2275       break;
2276     }
2277
2278   redraw_rect.x += widget->allocation.x;
2279   redraw_rect.y += widget->allocation.y;
2280
2281   gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
2282 }
2283
2284 static void
2285 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
2286 {
2287   if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
2288     {
2289       GdkRectangle rect;
2290
2291       gtk_notebook_get_arrow_rect (notebook, &rect);
2292       gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window, &rect, FALSE);
2293     }
2294 }
2295
2296 static gint
2297 gtk_notebook_timer (GtkNotebook *notebook)
2298 {
2299   gboolean retval = FALSE;
2300
2301   GDK_THREADS_ENTER ();
2302
2303   if (notebook->timer)
2304     {
2305       gtk_notebook_do_arrow (notebook, notebook->click_child);
2306
2307       if (notebook->need_timer) 
2308         {
2309           notebook->need_timer = FALSE;
2310           notebook->timer = gtk_timeout_add (NOTEBOOK_SCROLL_DELAY,
2311                                              (GtkFunction) gtk_notebook_timer, 
2312                                              (gpointer) notebook);
2313         }
2314       else
2315         retval = TRUE;
2316     }
2317
2318   GDK_THREADS_LEAVE ();
2319
2320   return retval;
2321 }
2322
2323 static gint
2324 gtk_notebook_page_compare (gconstpointer a,
2325                            gconstpointer b)
2326 {
2327   return (((GtkNotebookPage *) a)->child != b);
2328 }
2329
2330 static GList*
2331 gtk_notebook_find_child (GtkNotebook *notebook,
2332                          GtkWidget   *child,
2333                          const gchar *function)
2334 {
2335   GList *list = g_list_find_custom (notebook->children, child,
2336                                     gtk_notebook_page_compare);
2337
2338 #ifndef G_DISABLE_CHECKS
2339   if (!list && function)
2340     g_warning ("%s: unable to find child %p in notebook %p",
2341                function, child, notebook);
2342 #endif
2343
2344   return list;
2345 }
2346
2347 static void
2348 gtk_notebook_remove_tab_label (GtkNotebook     *notebook,
2349                                GtkNotebookPage *page)
2350 {
2351   if (page->tab_label)
2352     {
2353       if (page->mnemonic_activate_signal)
2354         g_signal_handler_disconnect (page->tab_label,
2355                                      page->mnemonic_activate_signal);
2356       page->mnemonic_activate_signal = 0;
2357
2358       gtk_widget_unparent (page->tab_label);
2359     }
2360 }
2361
2362 static void
2363 gtk_notebook_real_remove (GtkNotebook *notebook,
2364                           GList       *list,
2365                           gboolean     destroying)
2366 {
2367   GtkNotebookPage *page;
2368   GList * next_list;
2369   gint need_resize = FALSE;
2370
2371   next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
2372   if (!next_list)
2373     next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
2374
2375   if (notebook->cur_page == list->data)
2376     { 
2377       notebook->cur_page = NULL;
2378       if (next_list && !destroying)
2379         gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
2380     }
2381
2382   if (list == notebook->first_tab)
2383     notebook->first_tab = next_list;
2384   if (list == notebook->focus_tab && !destroying)
2385     gtk_notebook_switch_focus_tab (notebook, next_list);
2386
2387   page = list->data;
2388   
2389   if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
2390     need_resize = TRUE;
2391
2392   gtk_widget_unparent (page->child);
2393
2394   gtk_notebook_remove_tab_label (notebook, page);
2395   
2396   if (notebook->menu)
2397     {
2398       gtk_container_remove (GTK_CONTAINER (notebook->menu), 
2399                             page->menu_label->parent);
2400       gtk_widget_queue_resize (notebook->menu);
2401     }
2402   if (!page->default_menu)
2403     g_object_unref (page->menu_label);
2404   
2405   notebook->children = g_list_remove_link (notebook->children, list);
2406   g_list_free (list);
2407
2408   if (page->last_focus_child)
2409     {
2410       g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
2411       page->last_focus_child = NULL;
2412     }
2413   
2414   g_free (page);
2415
2416   if (!notebook->children && notebook->show_tabs &&
2417       GTK_WIDGET_MAPPED (notebook))
2418     gdk_window_hide (notebook->event_window);
2419
2420   gtk_notebook_update_labels (notebook);
2421   if (need_resize)
2422     gtk_widget_queue_resize (GTK_WIDGET (notebook));
2423 }
2424
2425 static void
2426 gtk_notebook_update_labels (GtkNotebook *notebook)
2427 {
2428   GtkNotebookPage *page;
2429   GList *list;
2430   gchar string[32];
2431   gint page_num = 1;
2432
2433   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
2434        list;
2435        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
2436     {
2437       page = list->data;
2438       g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
2439       if (notebook->show_tabs)
2440         {
2441           if (page->default_tab)
2442             {
2443               if (!page->tab_label)
2444                 {
2445                   page->tab_label = gtk_label_new (string);
2446                   gtk_widget_set_parent (page->tab_label,
2447                                          GTK_WIDGET (notebook));
2448                 }
2449               else
2450                 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
2451             }
2452
2453           if (GTK_WIDGET_VISIBLE (page->child) &&
2454               !GTK_WIDGET_VISIBLE (page->tab_label))
2455             gtk_widget_show (page->tab_label);
2456           else if (!GTK_WIDGET_VISIBLE (page->child) &&
2457                    GTK_WIDGET_VISIBLE (page->tab_label))
2458             gtk_widget_hide (page->tab_label);
2459         }
2460       if (notebook->menu && page->default_menu)
2461         {
2462           if (page->tab_label && GTK_IS_LABEL (page->tab_label))
2463             gtk_label_set_text (GTK_LABEL (page->menu_label),
2464                            GTK_LABEL (page->tab_label)->label);
2465           else
2466             gtk_label_set_text (GTK_LABEL (page->menu_label), string);
2467         }
2468     }  
2469 }
2470
2471 static gint
2472 gtk_notebook_real_page_position (GtkNotebook *notebook,
2473                                  GList       *list)
2474 {
2475   GList *work;
2476   gint count_start;
2477
2478   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
2479   g_return_val_if_fail (list != NULL, -1);
2480
2481   for (work = notebook->children, count_start = 0;
2482        work && work != list; work = work->next)
2483     if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
2484       count_start++;
2485
2486   if (!work)
2487     return -1;
2488
2489   if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
2490     return count_start;
2491
2492   return (count_start + g_list_length (list) - 1);
2493 }
2494
2495 static GList *
2496 gtk_notebook_search_page (GtkNotebook *notebook,
2497                           GList       *list,
2498                           gint         direction,
2499                           gboolean     find_visible)
2500 {
2501   GtkNotebookPage *page = NULL;
2502   GList *old_list = NULL;
2503   gint flag = 0;
2504
2505   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
2506
2507   switch (direction)
2508     {
2509     case STEP_PREV:
2510       flag = GTK_PACK_END;
2511       break;
2512
2513     case STEP_NEXT:
2514       flag = GTK_PACK_START;
2515       break;
2516     }
2517
2518   if (list)
2519     page = list->data;
2520
2521   if (!page || page->pack == flag)
2522     {
2523       if (list)
2524         {
2525           old_list = list;
2526           list = list->next;
2527         }
2528       else
2529         list = notebook->children;
2530
2531       while (list)
2532         {
2533           page = list->data;
2534           if (page->pack == flag &&
2535               (!find_visible || GTK_WIDGET_VISIBLE (page->child)))
2536             return list;
2537           old_list = list;
2538           list = list->next;
2539         }
2540       list = old_list;
2541     }
2542   else
2543     {
2544       old_list = list;
2545       list = list->prev;
2546     }
2547   while (list)
2548     {
2549       page = list->data;
2550       if (page->pack != flag &&
2551           (!find_visible || GTK_WIDGET_VISIBLE (page->child)))
2552         return list;
2553       old_list = list;
2554       list = list->prev;
2555     }
2556   return NULL;
2557 }
2558
2559 /* Private GtkNotebook Drawing Functions:
2560  *
2561  * gtk_notebook_paint
2562  * gtk_notebook_draw_tab
2563  * gtk_notebook_draw_arrow
2564  */
2565 static void
2566 gtk_notebook_paint (GtkWidget    *widget,
2567                     GdkRectangle *area)
2568 {
2569   GtkNotebook *notebook;
2570   GtkNotebookPage *page;
2571   GList *children;
2572   gboolean showarrow;
2573   gint width, height;
2574   gint x, y;
2575   gint border_width = GTK_CONTAINER (widget)->border_width;
2576   gint gap_x = 0, gap_width = 0;
2577    
2578   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
2579   g_return_if_fail (area != NULL);
2580
2581   if (!GTK_WIDGET_DRAWABLE (widget))
2582     return;
2583
2584   notebook = GTK_NOTEBOOK (widget);
2585
2586   if ((!notebook->show_tabs && !notebook->show_border) ||
2587       !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
2588     return;
2589
2590   x = widget->allocation.x + border_width;
2591   y = widget->allocation.y + border_width;
2592   width = widget->allocation.width - border_width * 2;
2593   height = widget->allocation.height - border_width * 2;
2594
2595   if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
2596     {
2597       gtk_paint_box (widget->style, widget->window,
2598                      GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2599                      area, widget, "notebook",
2600                      x, y, width, height);
2601       return;
2602     }
2603
2604
2605   if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
2606     {
2607       page = notebook->first_tab->data;
2608
2609       switch (notebook->tab_pos)
2610         {
2611         case GTK_POS_TOP:
2612           y += page->allocation.height + widget->style->ythickness;
2613         case GTK_POS_BOTTOM:
2614           height -= page->allocation.height + widget->style->ythickness;
2615           break;
2616         case GTK_POS_LEFT:
2617           x += page->allocation.width + widget->style->xthickness;
2618         case GTK_POS_RIGHT:
2619           width -= page->allocation.width + widget->style->xthickness;
2620           break;
2621         }
2622       gtk_paint_box (widget->style, widget->window,
2623                      GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2624                      area, widget, "notebook",
2625                      x, y, width, height);
2626     }
2627   else
2628     {
2629       switch (notebook->tab_pos)
2630         {
2631         case GTK_POS_TOP:
2632           y += notebook->cur_page->allocation.height;
2633         case GTK_POS_BOTTOM:
2634           height -= notebook->cur_page->allocation.height;
2635           break;
2636         case GTK_POS_LEFT:
2637           x += notebook->cur_page->allocation.width;
2638         case GTK_POS_RIGHT:
2639           width -= notebook->cur_page->allocation.width;
2640           break;
2641         }
2642
2643       switch (notebook->tab_pos)
2644         {
2645         case GTK_POS_TOP:
2646         case GTK_POS_BOTTOM:
2647           gap_x = (notebook->cur_page->allocation.x - widget->allocation.x - border_width);
2648           gap_width = notebook->cur_page->allocation.width;
2649           break;
2650         case GTK_POS_LEFT:
2651         case GTK_POS_RIGHT:
2652           gap_x = (notebook->cur_page->allocation.y - widget->allocation.y - border_width);
2653           gap_width = notebook->cur_page->allocation.height;
2654           break;
2655         }
2656       gtk_paint_box_gap(widget->style, widget->window,
2657                         GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2658                         area, widget, "notebook",
2659                         x, y, width, height,
2660                         notebook->tab_pos, gap_x, gap_width);
2661     }
2662
2663   showarrow = FALSE;
2664   children = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
2665   while (children)
2666     {
2667       page = children->data;
2668       children = gtk_notebook_search_page (notebook, children,
2669                                            STEP_PREV, TRUE);
2670       if (!GTK_WIDGET_VISIBLE (page->child))
2671         continue;
2672       if (!GTK_WIDGET_MAPPED (page->tab_label))
2673         showarrow = TRUE;
2674       else if (page != notebook->cur_page)
2675         gtk_notebook_draw_tab (notebook, page, area);
2676     }
2677
2678   if (showarrow && notebook->scrollable) 
2679     {
2680       gtk_notebook_draw_arrow (notebook, GTK_ARROW_LEFT);
2681       gtk_notebook_draw_arrow (notebook, GTK_ARROW_RIGHT);
2682     }
2683   gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
2684 }
2685
2686 static void
2687 gtk_notebook_draw_tab (GtkNotebook     *notebook,
2688                        GtkNotebookPage *page,
2689                        GdkRectangle    *area)
2690 {
2691   GdkRectangle child_area;
2692   GdkRectangle page_area;
2693   GtkStateType state_type;
2694   GtkPositionType gap_side;
2695   
2696   g_return_if_fail (notebook != NULL);
2697   g_return_if_fail (page != NULL);
2698   g_return_if_fail (area != NULL);
2699
2700   if (!GTK_WIDGET_MAPPED (page->tab_label) ||
2701       (page->allocation.width == 0) || (page->allocation.height == 0))
2702     return;
2703
2704   page_area.x = page->allocation.x;
2705   page_area.y = page->allocation.y;
2706   page_area.width = page->allocation.width;
2707   page_area.height = page->allocation.height;
2708
2709   if (gdk_rectangle_intersect (&page_area, area, &child_area))
2710     {
2711       GtkWidget *widget;
2712
2713       widget = GTK_WIDGET (notebook);
2714       gap_side = 0;
2715       switch (notebook->tab_pos)
2716         {
2717         case GTK_POS_TOP:
2718           gap_side = GTK_POS_BOTTOM;
2719           break;
2720         case GTK_POS_BOTTOM:
2721           gap_side = GTK_POS_TOP;
2722           break;
2723         case GTK_POS_LEFT:
2724           gap_side = GTK_POS_RIGHT;
2725           break;
2726         case GTK_POS_RIGHT:
2727           gap_side = GTK_POS_LEFT;
2728           break;
2729         }
2730       
2731       if (notebook->cur_page == page)
2732         state_type = GTK_STATE_NORMAL;
2733       else 
2734         state_type = GTK_STATE_ACTIVE;
2735       gtk_paint_extension(widget->style, widget->window,
2736                           state_type, GTK_SHADOW_OUT,
2737                           area, widget, "tab",
2738                           page_area.x, page_area.y,
2739                           page_area.width, page_area.height,
2740                           gap_side);
2741       if ((GTK_WIDGET_HAS_FOCUS (widget)) &&
2742           notebook->focus_tab && (notebook->focus_tab->data == page))
2743         {
2744           gint focus_width;
2745           
2746           gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2747           
2748           gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
2749                            area, widget, "tab",
2750                            page->tab_label->allocation.x - focus_width,
2751                            page->tab_label->allocation.y - focus_width,
2752                            page->tab_label->allocation.width + 2 * focus_width,
2753                            page->tab_label->allocation.height + 2 * focus_width);
2754         }
2755       if (gtk_widget_intersect (page->tab_label, area, &child_area) &&
2756           GTK_WIDGET_DRAWABLE (page->tab_label))
2757         {
2758           GdkEvent *expose_event = gdk_event_new (GDK_EXPOSE);
2759
2760           /* This is a lame hack since all this code needs rewriting anyhow */
2761           
2762           expose_event->expose.window = g_object_ref (page->tab_label->window);
2763           expose_event->expose.area = child_area;
2764           expose_event->expose.region = gdk_region_rectangle (&child_area);
2765           expose_event->expose.send_event = TRUE;
2766           expose_event->expose.count = 0;
2767
2768           gtk_container_propagate_expose (GTK_CONTAINER (notebook), page->tab_label, (GdkEventExpose *)expose_event);
2769
2770           gdk_event_free (expose_event);
2771         }
2772     }
2773 }
2774
2775 static void
2776 gtk_notebook_draw_arrow (GtkNotebook *notebook,
2777                          guint        arrow)
2778 {
2779   GtkStateType state_type;
2780   GtkShadowType shadow_type;
2781   GtkWidget *widget;
2782   GdkRectangle arrow_rect;
2783
2784   gtk_notebook_get_arrow_rect (notebook, &arrow_rect);
2785
2786   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
2787
2788   widget = GTK_WIDGET(notebook);
2789
2790   if (GTK_WIDGET_DRAWABLE (notebook))
2791     {
2792       if (notebook->in_child == arrow)
2793         {
2794           if (notebook->click_child == arrow)
2795             state_type = GTK_STATE_ACTIVE;
2796           else
2797             state_type = GTK_STATE_PRELIGHT;
2798         }
2799       else
2800         state_type = GTK_STATE_NORMAL;
2801
2802       if (notebook->click_child == arrow)
2803         shadow_type = GTK_SHADOW_IN;
2804       else
2805         shadow_type = GTK_SHADOW_OUT;
2806
2807       if (arrow == GTK_ARROW_LEFT)
2808         {
2809           if (notebook->focus_tab &&
2810               !gtk_notebook_search_page (notebook, notebook->focus_tab,
2811                                          STEP_PREV, TRUE))
2812             {
2813               shadow_type = GTK_SHADOW_ETCHED_IN;
2814               state_type = GTK_STATE_INSENSITIVE;
2815             }
2816
2817           if (notebook->tab_pos == GTK_POS_LEFT ||
2818               notebook->tab_pos == GTK_POS_RIGHT)
2819             arrow = GTK_ARROW_UP;
2820
2821           gtk_paint_arrow (widget->style, widget->window, state_type, 
2822                            shadow_type, NULL, GTK_WIDGET(notebook), "notebook",
2823                            arrow, TRUE, 
2824                            arrow_rect.x, arrow_rect.y, ARROW_SIZE, ARROW_SIZE);
2825         }
2826       else
2827         {
2828           if (notebook->focus_tab &&
2829               !gtk_notebook_search_page (notebook, notebook->focus_tab,
2830                                          STEP_NEXT, TRUE))
2831             {
2832               shadow_type = GTK_SHADOW_ETCHED_IN;
2833               state_type = GTK_STATE_INSENSITIVE;
2834             }
2835
2836           if (notebook->tab_pos == GTK_POS_LEFT ||
2837               notebook->tab_pos == GTK_POS_RIGHT)
2838             arrow = GTK_ARROW_DOWN;
2839
2840            gtk_paint_arrow (widget->style, widget->window, state_type, 
2841                             shadow_type, NULL, GTK_WIDGET(notebook), "notebook",
2842                             arrow, TRUE, arrow_rect.x + ARROW_SIZE + ARROW_SPACING,
2843                             arrow_rect.y, ARROW_SIZE, ARROW_SIZE);
2844         }
2845     }
2846 }
2847
2848 /* Private GtkNotebook Size Allocate Functions:
2849  *
2850  * gtk_notebook_pages_allocate
2851  * gtk_notebook_page_allocate
2852  * gtk_notebook_calc_tabs
2853  */
2854 static void
2855 gtk_notebook_pages_allocate (GtkNotebook   *notebook)
2856 {
2857   GtkWidget    *widget = GTK_WIDGET (notebook);
2858   GtkContainer *container = GTK_CONTAINER (notebook);
2859   GtkNotebookPage *page = NULL;
2860   GtkAllocation *allocation = &widget->allocation;
2861   GtkAllocation child_allocation;
2862   GList *children = NULL;
2863   GList *last_child = NULL;
2864   gboolean showarrow = FALSE;
2865   gint tab_space = 0; 
2866   gint delta; 
2867   gint x = 0;
2868   gint y = 0;
2869   gint i;
2870   gint n = 1;
2871   gint old_fill = 0;
2872   gint new_fill = 0;
2873
2874   if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
2875     return;
2876
2877   child_allocation.x = widget->allocation.x + container->border_width;
2878   child_allocation.y = widget->allocation.y + container->border_width;
2879
2880   switch (notebook->tab_pos)
2881     {
2882     case GTK_POS_BOTTOM:
2883       child_allocation.y = (widget->allocation.y +
2884                             allocation->height -
2885                             notebook->cur_page->requisition.height -
2886                             container->border_width);
2887       /* fall through */
2888     case GTK_POS_TOP:
2889       child_allocation.height = notebook->cur_page->requisition.height;
2890       break;
2891       
2892     case GTK_POS_RIGHT:
2893       child_allocation.x = (widget->allocation.x +
2894                             allocation->width -
2895                             notebook->cur_page->requisition.width -
2896                             container->border_width);
2897       /* fall through */
2898     case GTK_POS_LEFT:
2899       child_allocation.width = notebook->cur_page->requisition.width;
2900       break;
2901     }
2902   
2903   if (notebook->scrollable) 
2904     {
2905       GList *focus_tab;
2906       
2907       children = notebook->children;
2908       
2909       if (notebook->focus_tab)
2910         focus_tab = notebook->focus_tab;
2911       else if (notebook->first_tab)
2912         focus_tab = notebook->first_tab;
2913       else
2914         focus_tab = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
2915
2916       switch (notebook->tab_pos)
2917         {
2918         case GTK_POS_TOP:
2919         case GTK_POS_BOTTOM:
2920           while (children)
2921             {
2922               page = children->data;
2923               children = children->next;
2924
2925               if (GTK_WIDGET_VISIBLE (page->child))
2926                 tab_space += page->requisition.width;
2927             }
2928           if (tab_space >
2929               allocation->width - 2 * container->border_width - TAB_OVERLAP) 
2930             {
2931               showarrow = TRUE;
2932               page = focus_tab->data; 
2933
2934               tab_space = (allocation->width - TAB_OVERLAP -
2935                            page->requisition.width -
2936                            2 * (container->border_width + ARROW_SPACING +
2937                                 ARROW_SIZE));
2938               x = (allocation->width - 2 * ARROW_SIZE - ARROW_SPACING -
2939                    container->border_width);
2940
2941               page = notebook->children->data;
2942               if (notebook->tab_pos == GTK_POS_TOP)
2943                 y = (container->border_width +
2944                      (page->requisition.height - ARROW_SIZE) / 2);
2945               else
2946                 y = (allocation->height - container->border_width - 
2947                      ARROW_SIZE - (page->requisition.height - ARROW_SIZE) / 2);
2948             }
2949           break;
2950         case GTK_POS_LEFT:
2951         case GTK_POS_RIGHT:
2952           while (children)
2953             {
2954               page = children->data;
2955               children = children->next;
2956
2957               if (GTK_WIDGET_VISIBLE (page->child))
2958                 tab_space += page->requisition.height;
2959             }
2960           if (tab_space >
2961               (allocation->height - 2 * container->border_width - TAB_OVERLAP))
2962             {
2963               showarrow = TRUE;
2964               page = focus_tab->data; 
2965               tab_space = (allocation->height -
2966                            ARROW_SIZE - ARROW_SPACING - TAB_OVERLAP -
2967                            2 * container->border_width -
2968                            page->requisition.height);
2969               y = allocation->height - container->border_width - ARROW_SIZE;  
2970
2971               page = notebook->children->data;
2972               if (notebook->tab_pos == GTK_POS_LEFT)
2973                 x = (container->border_width +
2974                      (page->requisition.width -
2975                       (2 * ARROW_SIZE - ARROW_SPACING)) / 2); 
2976               else
2977                 x = (allocation->width - container->border_width -
2978                      (2 * ARROW_SIZE - ARROW_SPACING) -
2979                      (page->requisition.width -
2980                       (2 * ARROW_SIZE - ARROW_SPACING)) / 2);
2981             }
2982           break;
2983         }
2984       if (showarrow) /* first_tab <- focus_tab */
2985         { 
2986           if (tab_space <= 0)
2987             {
2988               notebook->first_tab = focus_tab;
2989               last_child = gtk_notebook_search_page (notebook, focus_tab,
2990                                                      STEP_NEXT, TRUE);
2991             }
2992           else
2993             {
2994               children = NULL;
2995               if (notebook->first_tab && notebook->first_tab != focus_tab)
2996                 {
2997                   /* Is first_tab really predecessor of focus_tab  ? */
2998                   page = notebook->first_tab->data;
2999                   if (GTK_WIDGET_VISIBLE (page->child))
3000                     for (children = focus_tab;
3001                          children && children != notebook->first_tab;
3002                          children = gtk_notebook_search_page (notebook,
3003                                                               children,
3004                                                               STEP_PREV,
3005                                                               TRUE));
3006                 }
3007               if (!children)
3008                 notebook->first_tab = focus_tab;
3009               else
3010                 gtk_notebook_calc_tabs (notebook,
3011                                         gtk_notebook_search_page (notebook,
3012                                                                   focus_tab,
3013                                                                   STEP_PREV,
3014                                                                   TRUE), 
3015                                         &(notebook->first_tab), &tab_space,
3016                                         STEP_PREV);
3017
3018               if (tab_space <= 0)
3019                 {
3020                   notebook->first_tab =
3021                     gtk_notebook_search_page (notebook, notebook->first_tab,
3022                                               STEP_NEXT, TRUE);
3023                   if (!notebook->first_tab)
3024                     notebook->first_tab = focus_tab;
3025                   last_child = gtk_notebook_search_page (notebook, focus_tab,
3026                                                          STEP_NEXT, TRUE); 
3027                 }
3028               else /* focus_tab -> end */   
3029                 {
3030                   if (!notebook->first_tab)
3031                     notebook->first_tab = gtk_notebook_search_page (notebook,
3032                                                                     NULL,
3033                                                                     STEP_NEXT,
3034                                                                     TRUE);
3035                   children = NULL;
3036                   gtk_notebook_calc_tabs (notebook,
3037                                           gtk_notebook_search_page (notebook,
3038                                                                     focus_tab,
3039                                                                     STEP_NEXT,
3040                                                                     TRUE),
3041                                           &children, &tab_space, STEP_NEXT);
3042
3043                   if (tab_space <= 0) 
3044                     last_child = children;
3045                   else /* start <- first_tab */
3046                     {
3047                       last_child = NULL;
3048                       children = NULL;
3049                       gtk_notebook_calc_tabs
3050                         (notebook,
3051                          gtk_notebook_search_page (notebook,
3052                                                    notebook->first_tab,
3053                                                    STEP_PREV,
3054                                                    TRUE),
3055                          &children, &tab_space, STEP_PREV);
3056                       notebook->first_tab = gtk_notebook_search_page(notebook,
3057                                                                      children,
3058                                                                      STEP_NEXT,
3059                                                                      TRUE);
3060                     }
3061                 }
3062             }
3063
3064           if (tab_space < 0) 
3065             {
3066               tab_space = -tab_space;
3067               n = 0;
3068               for (children = notebook->first_tab;
3069                    children && children != last_child;
3070                    children = gtk_notebook_search_page (notebook, children,
3071                                                         STEP_NEXT, TRUE))
3072                 n++;
3073             }
3074           else 
3075             tab_space = 0;
3076
3077           /*unmap all non-visible tabs*/
3078           for (children = gtk_notebook_search_page (notebook, NULL,
3079                                                     STEP_NEXT, TRUE);
3080                children && children != notebook->first_tab;
3081                children = gtk_notebook_search_page (notebook, children,
3082                                                     STEP_NEXT, TRUE))
3083             {
3084               page = children->data;
3085               if (page->tab_label)
3086                 gtk_widget_set_child_visible (page->tab_label, FALSE);
3087             }
3088           for (children = last_child; children;
3089                children = gtk_notebook_search_page (notebook, children,
3090                                                     STEP_NEXT, TRUE))
3091             {
3092               page = children->data;
3093               if (page->tab_label)
3094                 gtk_widget_set_child_visible (page->tab_label, FALSE);
3095             }
3096         }
3097       else /* !showarrow */
3098         {
3099           notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
3100                                                           STEP_NEXT, TRUE);
3101           tab_space = 0;
3102         }
3103     }
3104
3105   if (!showarrow)
3106     {
3107       gint c = 0;
3108
3109       n = 0;
3110       children = notebook->children;
3111       switch (notebook->tab_pos)
3112         {
3113         case GTK_POS_TOP:
3114         case GTK_POS_BOTTOM:
3115           while (children)
3116             {
3117               page = children->data;
3118               children = children->next;
3119
3120               if (GTK_WIDGET_VISIBLE (page->child))
3121                 {
3122                   c++;
3123                   tab_space += page->requisition.width;
3124                   if (page->expand)
3125                     n++;
3126                 }
3127             }
3128           tab_space -= allocation->width;
3129           break;
3130         case GTK_POS_LEFT:
3131         case GTK_POS_RIGHT:
3132           while (children)
3133             {
3134               page = children->data;
3135               children = children->next;
3136
3137               if (GTK_WIDGET_VISIBLE (page->child))
3138                 {
3139                   c++;
3140                   tab_space += page->requisition.height;
3141                   if (page->expand)
3142                     n++;
3143                 }
3144             }
3145           tab_space -= allocation->height;
3146         }
3147       tab_space += 2 * container->border_width + TAB_OVERLAP;
3148       tab_space *= -1;
3149       notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
3150                                                       STEP_NEXT, TRUE);
3151       if (notebook->homogeneous && n)
3152         n = c;
3153     }
3154   
3155   children = notebook->first_tab;
3156   i = 1;
3157   while (children)
3158     {
3159       if (children == last_child)
3160         {
3161           /* FIXME double check */
3162           goto done;
3163         }
3164
3165       page = children->data;
3166       if (!showarrow && page->pack != GTK_PACK_START)
3167         break;
3168       children = gtk_notebook_search_page (notebook, children, STEP_NEXT,TRUE);
3169       
3170       delta = 0;
3171       if (n && (showarrow || page->expand || notebook->homogeneous))
3172         {
3173           new_fill = (tab_space * i++) / n;
3174           delta = new_fill - old_fill;
3175           old_fill = new_fill;
3176         }
3177       
3178       switch (notebook->tab_pos)
3179         {
3180         case GTK_POS_TOP:
3181         case GTK_POS_BOTTOM:
3182           child_allocation.width = (page->requisition.width +
3183                                     TAB_OVERLAP + delta);
3184           break;
3185         case GTK_POS_LEFT:
3186         case GTK_POS_RIGHT:
3187           child_allocation.height = (page->requisition.height +
3188                                      TAB_OVERLAP + delta);
3189           break;
3190         }
3191
3192       gtk_notebook_page_allocate (notebook, page, &child_allocation);
3193           
3194       switch (notebook->tab_pos)
3195         {
3196         case GTK_POS_TOP:
3197         case GTK_POS_BOTTOM:
3198           child_allocation.x += child_allocation.width - TAB_OVERLAP;
3199           break;
3200         case GTK_POS_LEFT:
3201         case GTK_POS_RIGHT:
3202           child_allocation.y += child_allocation.height - TAB_OVERLAP;
3203           break;
3204         }
3205
3206       if (page->tab_label)
3207         gtk_widget_set_child_visible (page->tab_label, TRUE);
3208     }
3209
3210   if (children)
3211     {
3212       children = notebook->children;
3213       switch (notebook->tab_pos)
3214         {
3215         case GTK_POS_TOP:
3216         case GTK_POS_BOTTOM:
3217           child_allocation.x = (allocation->x + allocation->width -
3218                                 container->border_width);
3219           break;
3220         case GTK_POS_LEFT:
3221         case GTK_POS_RIGHT:
3222           child_allocation.y = (allocation->y + allocation->height -
3223                                 container->border_width);
3224           break;
3225         }
3226
3227       while (children != last_child)
3228         {
3229           page = children->data;
3230           children = children->next;
3231
3232           if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
3233             continue;
3234
3235           delta = 0;
3236           if (n && (page->expand || notebook->homogeneous))
3237             {
3238               new_fill = (tab_space * i++) / n;
3239               delta = new_fill - old_fill;
3240               old_fill = new_fill;
3241             }
3242
3243           switch (notebook->tab_pos)
3244             {
3245             case GTK_POS_TOP:
3246             case GTK_POS_BOTTOM:
3247               child_allocation.width = (page->requisition.width +
3248                                         TAB_OVERLAP + delta);
3249               child_allocation.x -= child_allocation.width;
3250               break;
3251             case GTK_POS_LEFT:
3252             case GTK_POS_RIGHT:
3253               child_allocation.height = (page->requisition.height +
3254                                          TAB_OVERLAP + delta);
3255               child_allocation.y -= child_allocation.height;
3256               break;
3257             }
3258
3259           gtk_notebook_page_allocate (notebook, page, &child_allocation);
3260
3261           switch (notebook->tab_pos)
3262             {
3263             case GTK_POS_TOP:
3264             case GTK_POS_BOTTOM:
3265               child_allocation.x += TAB_OVERLAP;
3266               break;
3267             case GTK_POS_LEFT:
3268             case GTK_POS_RIGHT:
3269               child_allocation.y += TAB_OVERLAP;
3270               break;
3271             }
3272
3273           if (page->tab_label)
3274             gtk_widget_set_child_visible (page->tab_label, TRUE);
3275         }
3276     }
3277
3278  done:
3279   gtk_notebook_redraw_tabs (notebook);  
3280 }
3281
3282 static void
3283 gtk_notebook_page_allocate (GtkNotebook     *notebook,
3284                             GtkNotebookPage *page,
3285                             GtkAllocation   *allocation)
3286 {
3287   GtkWidget *widget = GTK_WIDGET (notebook);
3288   GtkAllocation child_allocation;
3289   GtkRequisition tab_requisition;
3290   gint xthickness;
3291   gint ythickness;
3292   gint padding;
3293   gint focus_width;
3294
3295   gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3296   
3297   xthickness = widget->style->xthickness;
3298   ythickness = widget->style->ythickness;
3299
3300   /* If the size of the notebook tabs change, we need to queue
3301    * a redraw on the tab area
3302    */
3303   if ((allocation->width != page->allocation.width) ||
3304       (allocation->height != page->allocation.height))
3305     {
3306       gint x, y, width, height, border_width;
3307
3308       border_width = GTK_CONTAINER (notebook)->border_width;
3309
3310       switch (notebook->tab_pos)
3311        {
3312        case GTK_POS_TOP:
3313          width = widget->allocation.width;
3314          height = MAX (page->allocation.height, allocation->height) + ythickness;
3315          x = 0;                              
3316          y = border_width;
3317          break;
3318
3319        case GTK_POS_BOTTOM:
3320          width = widget->allocation.width + xthickness;
3321          height = MAX (page->allocation.height, allocation->height) + ythickness;
3322          x = 0;                              
3323          y = widget->allocation.height - height - border_width;
3324          break;
3325
3326        case GTK_POS_LEFT:
3327          width = MAX (page->allocation.width, allocation->width) + xthickness;
3328          height = widget->allocation.height;
3329          x = border_width;
3330          y = 0;
3331          break;
3332
3333        case GTK_POS_RIGHT:
3334        default:                /* quiet gcc */
3335          width = MAX (page->allocation.width, allocation->width) + xthickness;
3336          height = widget->allocation.height;
3337          x = widget->allocation.width - width - border_width;
3338          y = 0;
3339          break;
3340        }
3341
3342       gtk_widget_queue_draw_area (widget, x, y, width, height);
3343     }
3344
3345   page->allocation = *allocation;
3346   gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
3347
3348   if (notebook->cur_page != page)
3349     {
3350       switch (notebook->tab_pos)
3351         {
3352         case GTK_POS_TOP:
3353           page->allocation.y += ythickness;
3354         case GTK_POS_BOTTOM:
3355           if (page->allocation.height > ythickness)
3356             page->allocation.height -= ythickness;
3357           break;
3358         case GTK_POS_LEFT:
3359           page->allocation.x += xthickness;
3360         case GTK_POS_RIGHT:
3361           if (page->allocation.width > xthickness)
3362             page->allocation.width -= xthickness;
3363           break;
3364         }
3365     }
3366
3367   switch (notebook->tab_pos)
3368     {
3369     case GTK_POS_TOP:
3370     case GTK_POS_BOTTOM:
3371       padding = TAB_CURVATURE + focus_width + notebook->tab_hborder;
3372       if (page->fill)
3373         {
3374           child_allocation.x = (xthickness + focus_width +
3375                                 notebook->tab_hborder);
3376           child_allocation.width = MAX (1, (page->allocation.width -
3377                                             2 * child_allocation.x));
3378           child_allocation.x += page->allocation.x;
3379         }
3380       else
3381         {
3382           child_allocation.x = (page->allocation.x +
3383                                 (page->allocation.width -
3384                                  tab_requisition.width) / 2);
3385           child_allocation.width = tab_requisition.width;
3386         }
3387       child_allocation.y = (notebook->tab_vborder + focus_width +
3388                             page->allocation.y);
3389       if (notebook->tab_pos == GTK_POS_TOP)
3390         child_allocation.y += ythickness;
3391       child_allocation.height = MAX (1, (((gint) page->allocation.height) - ythickness -
3392                                          2 * (notebook->tab_vborder + focus_width)));
3393       break;
3394     case GTK_POS_LEFT:
3395     case GTK_POS_RIGHT:
3396       padding = TAB_CURVATURE + focus_width + notebook->tab_vborder;
3397       if (page->fill)
3398         {
3399           child_allocation.y = ythickness + padding;
3400           child_allocation.height = MAX (1, (page->allocation.height -
3401                                              2 * child_allocation.y));
3402           child_allocation.y += page->allocation.y;
3403         }
3404       else
3405         {
3406           child_allocation.y = (page->allocation.y + (page->allocation.height -
3407                                                       tab_requisition.height) / 2);
3408           child_allocation.height = tab_requisition.height;
3409         }
3410       child_allocation.x = page->allocation.x + notebook->tab_hborder + focus_width;
3411       if (notebook->tab_pos == GTK_POS_LEFT)
3412         child_allocation.x += xthickness;
3413       child_allocation.width = MAX (1, (((gint) page->allocation.width) - xthickness -
3414                                         2 * (notebook->tab_hborder + focus_width)));
3415       break;
3416     }
3417
3418   if (page->tab_label)
3419     gtk_widget_size_allocate (page->tab_label, &child_allocation);
3420 }
3421
3422 static void 
3423 gtk_notebook_calc_tabs (GtkNotebook  *notebook, 
3424                         GList        *start, 
3425                         GList       **end,
3426                         gint         *tab_space,
3427                         guint         direction)
3428 {
3429   GtkNotebookPage *page = NULL;
3430   GList *children;
3431   GList *last_list = NULL;
3432   gboolean pack;
3433
3434   if (!start)
3435     return;
3436
3437   children = start;
3438   pack = GTK_NOTEBOOK_PAGE (start)->pack;
3439   if (pack == GTK_PACK_END)
3440     direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
3441
3442   while (1)
3443     {
3444       switch (notebook->tab_pos)
3445         {
3446         case GTK_POS_TOP:
3447         case GTK_POS_BOTTOM:
3448           while (children)
3449             {
3450               page = children->data;
3451               if (GTK_WIDGET_VISIBLE (page->child))
3452                 {
3453                   if (page->pack == pack)
3454                     {
3455                       *tab_space -= page->requisition.width;
3456                       if (*tab_space < 0 || children == *end)
3457                         {
3458                           if (*tab_space < 0) 
3459                             {
3460                               *tab_space = - (*tab_space +
3461                                               page->requisition.width);
3462                               *end = children;
3463                             }
3464                           return;
3465                         }
3466                     }
3467                   last_list = children;
3468                 }
3469               if (direction == STEP_NEXT)
3470                 children = children->next;
3471               else
3472                 children = children->prev;
3473             }
3474           break;
3475         case GTK_POS_LEFT:
3476         case GTK_POS_RIGHT:
3477           while (children)
3478             {
3479               page = children->data;
3480               if (GTK_WIDGET_VISIBLE (page->child))
3481                 {
3482                   if (page->pack == pack)
3483                     {
3484                       *tab_space -= page->requisition.height;
3485                       if (*tab_space < 0 || children == *end)
3486                         {
3487                           if (*tab_space < 0)
3488                             {
3489                               *tab_space = - (*tab_space +
3490                                               page->requisition.height);
3491                               *end = children;
3492                             }
3493                           return;
3494                         }
3495                     }
3496                   last_list = children;
3497                 }
3498               if (direction == STEP_NEXT)
3499                 children = children->next;
3500               else
3501                 children = children->prev;
3502             }
3503           break;
3504         }
3505       if (direction == STEP_PREV)
3506         return;
3507       pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
3508       direction = STEP_PREV;
3509       children = last_list;
3510     }
3511 }
3512
3513 /* Private GtkNotebook Page Switch Methods:
3514  *
3515  * gtk_notebook_real_switch_page
3516  */
3517 static void
3518 gtk_notebook_real_switch_page (GtkNotebook     *notebook,
3519                                GtkNotebookPage *page,
3520                                guint            page_num)
3521 {
3522   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3523   g_return_if_fail (page != NULL);
3524
3525   if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
3526     return;
3527
3528   if (notebook->cur_page)
3529     gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
3530   
3531   notebook->cur_page = page;
3532
3533   if (!notebook->focus_tab ||
3534       notebook->focus_tab->data != (gpointer) notebook->cur_page)
3535     notebook->focus_tab = 
3536       g_list_find (notebook->children, notebook->cur_page);
3537
3538   gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
3539
3540   /* If the focus was on the previous page, move it to the first
3541    * element on the new page, if possible, or if not, to the
3542    * notebook itself.
3543    */
3544   if (notebook->child_has_focus)
3545     {
3546       if (notebook->cur_page->last_focus_child &&
3547           gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
3548         gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
3549       else
3550         if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
3551           gtk_widget_grab_focus (GTK_WIDGET (notebook));
3552     }
3553   
3554   gtk_widget_queue_resize (GTK_WIDGET (notebook));
3555   g_object_notify (G_OBJECT (notebook), "page");
3556 }
3557
3558 /* Private GtkNotebook Page Switch Functions:
3559  *
3560  * gtk_notebook_switch_page
3561  * gtk_notebook_page_select
3562  * gtk_notebook_switch_focus_tab
3563  * gtk_notebook_menu_switch_page
3564  */
3565 static void
3566 gtk_notebook_switch_page (GtkNotebook     *notebook,
3567                           GtkNotebookPage *page,
3568                           gint             page_num)
3569
3570   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3571   g_return_if_fail (page != NULL);
3572  
3573   if (notebook->cur_page == page)
3574     return;
3575
3576   if (page_num < 0)
3577     page_num = g_list_index (notebook->children, page);
3578
3579   g_signal_emit (notebook,
3580                  notebook_signals[SWITCH_PAGE],
3581                  0,
3582                  page,
3583                  page_num);
3584 }
3585
3586 static gint
3587 gtk_notebook_page_select (GtkNotebook *notebook,
3588                           gboolean     move_focus)
3589 {
3590   GtkNotebookPage *page;
3591   GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
3592
3593   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
3594
3595   if (!notebook->focus_tab)
3596     return FALSE;
3597
3598   page = notebook->focus_tab->data;
3599   gtk_notebook_switch_page (notebook, page, -1);
3600
3601   if (move_focus)
3602     {
3603       switch (notebook->tab_pos)
3604         {
3605         case GTK_POS_TOP:
3606           dir = GTK_DIR_DOWN;
3607           break;
3608         case GTK_POS_BOTTOM:
3609           dir = GTK_DIR_UP;
3610           break;
3611         case GTK_POS_LEFT:
3612           dir = GTK_DIR_RIGHT;
3613           break;
3614         case GTK_POS_RIGHT:
3615           dir = GTK_DIR_LEFT;
3616           break;
3617         }
3618
3619       if (gtk_widget_child_focus (page->child, dir))
3620         return TRUE;
3621     }
3622   return FALSE;
3623 }
3624
3625 static void
3626 gtk_notebook_switch_focus_tab (GtkNotebook *notebook, 
3627                                GList       *new_child)
3628 {
3629   GList *old_child;
3630   GtkNotebookPage *old_page = NULL;
3631   GtkNotebookPage *page;
3632
3633   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3634
3635   if (notebook->focus_tab == new_child)
3636     return;
3637
3638   old_child = notebook->focus_tab;
3639   notebook->focus_tab = new_child;
3640
3641   if (notebook->scrollable)
3642     gtk_notebook_redraw_arrows (notebook);
3643
3644   if (!notebook->show_tabs || !notebook->focus_tab)
3645     return;
3646
3647   if (old_child)
3648     old_page = old_child->data;
3649
3650   page = notebook->focus_tab->data;
3651   if (GTK_WIDGET_MAPPED (page->tab_label))
3652     gtk_notebook_redraw_tabs (notebook);
3653   else
3654     gtk_notebook_pages_allocate (notebook);
3655   
3656   gtk_notebook_switch_page (notebook, page,
3657                             g_list_index (notebook->children, page));
3658 }
3659
3660 static void
3661 gtk_notebook_menu_switch_page (GtkWidget       *widget,
3662                                GtkNotebookPage *page)
3663 {
3664   GtkNotebook *notebook;
3665   GList *children;
3666   guint page_num;
3667
3668   g_return_if_fail (widget != NULL);
3669   g_return_if_fail (page != NULL);
3670
3671   notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
3672                            (GTK_MENU (widget->parent)));
3673
3674   if (notebook->cur_page == page)
3675     return;
3676
3677   page_num = 0;
3678   children = notebook->children;
3679   while (children && children->data != page)
3680     {
3681       children = children->next;
3682       page_num++;
3683     }
3684
3685   g_signal_emit (notebook,
3686                  notebook_signals[SWITCH_PAGE],
3687                  0,
3688                  page,
3689                  page_num);
3690 }
3691
3692 /* Private GtkNotebook Menu Functions:
3693  *
3694  * gtk_notebook_menu_item_create
3695  * gtk_notebook_menu_label_unparent
3696  * gtk_notebook_menu_detacher
3697  */
3698 static void
3699 gtk_notebook_menu_item_create (GtkNotebook *notebook, 
3700                                GList       *list)
3701 {       
3702   GtkNotebookPage *page;
3703   GtkWidget *menu_item;
3704
3705   page = list->data;
3706   if (page->default_menu)
3707     {
3708       if (page->tab_label && GTK_IS_LABEL (page->tab_label))
3709         page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
3710       else
3711         page->menu_label = gtk_label_new ("");
3712       gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
3713     }
3714
3715   gtk_widget_show (page->menu_label);
3716   menu_item = gtk_menu_item_new ();
3717   gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
3718   gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
3719                          gtk_notebook_real_page_position (notebook, list));
3720   g_signal_connect (menu_item, "activate",
3721                     G_CALLBACK (gtk_notebook_menu_switch_page), page);
3722   if (GTK_WIDGET_VISIBLE (page->child))
3723     gtk_widget_show (menu_item);
3724 }
3725
3726 static void
3727 gtk_notebook_menu_label_unparent (GtkWidget *widget, 
3728                                   gpointer  data)
3729 {
3730   gtk_widget_unparent (GTK_BIN(widget)->child);
3731   GTK_BIN(widget)->child = NULL;
3732 }
3733
3734 static void
3735 gtk_notebook_menu_detacher (GtkWidget *widget,
3736                             GtkMenu   *menu)
3737 {
3738   GtkNotebook *notebook;
3739
3740   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
3741
3742   notebook = GTK_NOTEBOOK (widget);
3743   g_return_if_fail (notebook->menu == (GtkWidget*) menu);
3744
3745   notebook->menu = NULL;
3746 }
3747
3748 /* Private GtkNotebook Setter Functions:
3749  *
3750  * gtk_notebook_set_homogeneous_tabs_internal
3751  * gtk_notebook_set_tab_border_internal
3752  * gtk_notebook_set_tab_hborder_internal
3753  * gtk_notebook_set_tab_vborder_internal
3754  */
3755 static void
3756 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
3757                                             gboolean     homogeneous)
3758 {
3759   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3760
3761   if (homogeneous == notebook->homogeneous)
3762     return;
3763
3764   notebook->homogeneous = homogeneous;
3765   gtk_widget_queue_resize (GTK_WIDGET (notebook));
3766
3767   g_object_notify (G_OBJECT (notebook), "homogeneous");
3768 }
3769
3770 static void
3771 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
3772                                       guint        border_width)
3773 {
3774   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3775
3776   notebook->tab_hborder = border_width;
3777   notebook->tab_vborder = border_width;
3778
3779   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
3780     gtk_widget_queue_resize (GTK_WIDGET (notebook));
3781
3782   g_object_freeze_notify (G_OBJECT (notebook));
3783   g_object_notify (G_OBJECT (notebook), "tab_hborder");
3784   g_object_notify (G_OBJECT (notebook), "tab_vborder");
3785   g_object_thaw_notify (G_OBJECT (notebook));
3786 }
3787
3788 static void
3789 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
3790                                        guint        tab_hborder)
3791 {
3792   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3793
3794   if (notebook->tab_hborder == tab_hborder)
3795     return;
3796
3797   notebook->tab_hborder = tab_hborder;
3798
3799   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
3800     gtk_widget_queue_resize (GTK_WIDGET (notebook));
3801
3802   g_object_notify (G_OBJECT (notebook), "tab_hborder");
3803 }
3804
3805 static void
3806 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
3807                                        guint        tab_vborder)
3808 {
3809   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3810
3811   if (notebook->tab_vborder == tab_vborder)
3812     return;
3813
3814   notebook->tab_vborder = tab_vborder;
3815
3816   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
3817     gtk_widget_queue_resize (GTK_WIDGET (notebook));
3818
3819   g_object_notify (G_OBJECT (notebook), "tab_vborder");
3820 }
3821
3822 /* Public GtkNotebook Page Insert/Remove Methods :
3823  *
3824  * gtk_notebook_append_page
3825  * gtk_notebook_append_page_menu
3826  * gtk_notebook_prepend_page
3827  * gtk_notebook_prepend_page_menu
3828  * gtk_notebook_insert_page
3829  * gtk_notebook_insert_page_menu
3830  * gtk_notebook_remove_page
3831  */
3832 /**
3833  * gtk_notebook_append_page:
3834  * @notebook: a #GtkNotebook
3835  * @child: the #GtkWidget to use as the contents of the page.
3836  * @tab_label: the #GtkWidget to be used as the label for the page,
3837  *             or %NULL to use the default label, 'page N'.
3838  * 
3839  * Appends a page to @notebook.
3840  **/
3841 void
3842 gtk_notebook_append_page (GtkNotebook *notebook,
3843                           GtkWidget   *child,
3844                           GtkWidget   *tab_label)
3845 {
3846   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3847   g_return_if_fail (GTK_IS_WIDGET (child));
3848   g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
3849   
3850   gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
3851 }
3852
3853 /**
3854  * gtk_notebook_append_page_menu:
3855  * @notebook: a #GtkNotebook
3856  * @child: the #GtkWidget to use as the contents of the page.
3857  * @tab_label: the #GtkWidget to be used as the label for the page,
3858  *             or %NULL to use the default label, 'page N'.
3859  * @menu_label: the widget to use as a label for the page-switch
3860  *              menu, if that is enabled. If %NULL, and @tab_label
3861  *              is a #GtkLabel or %NULL, then the menu label will be
3862  *              a newly created label with the same text as @tab_label;
3863  *              If @tab_label is not a #GtkLabel, @menu_label must be
3864  *              specified if the page-switch menu is to be used.
3865  * 
3866  * Appends a page to @notebook, specifying the widget to use as the
3867  * label in the popup menu.
3868  **/
3869 void
3870 gtk_notebook_append_page_menu (GtkNotebook *notebook,
3871                                GtkWidget   *child,
3872                                GtkWidget   *tab_label,
3873                                GtkWidget   *menu_label)
3874 {
3875   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3876   g_return_if_fail (GTK_IS_WIDGET (child));
3877   g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
3878   g_return_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label));
3879   
3880   gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
3881 }
3882
3883 /**
3884  * gtk_notebook_prepend_page:
3885  * @notebook: a #GtkNotebook
3886  * @child: the #GtkWidget to use as the contents of the page.
3887  * @tab_label: the #GtkWidget to be used as the label for the page,
3888  *             or %NULL to use the default label, 'page N'.
3889  *
3890  * Prepends a page to @notebook.
3891  **/
3892 void
3893 gtk_notebook_prepend_page (GtkNotebook *notebook,
3894                            GtkWidget   *child,
3895                            GtkWidget   *tab_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   
3901   gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
3902 }
3903
3904 /**
3905  * gtk_notebook_prepend_page_menu:
3906  * @notebook: a #GtkNotebook
3907  * @child: the #GtkWidget to use as the contents of the page.
3908  * @tab_label: the #GtkWidget to be used as the label for the page,
3909  *             or %NULL to use the default label, 'page N'.
3910  * @menu_label: the widget to use as a label for the page-switch
3911  *              menu, if that is enabled. If %NULL, and @tab_label
3912  *              is a #GtkLabel or %NULL, then the menu label will be
3913  *              a newly created label with the same text as @tab_label;
3914  *              If @tab_label is not a #GtkLabel, @menu_label must be
3915  *              specified if the page-switch menu is to be used.
3916  * 
3917  * Prepends a page to @notebook, specifying the widget to use as the
3918  * label in the popup menu.
3919  **/
3920 void
3921 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
3922                                 GtkWidget   *child,
3923                                 GtkWidget   *tab_label,
3924                                 GtkWidget   *menu_label)
3925 {
3926   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3927   g_return_if_fail (GTK_IS_WIDGET (child));
3928   g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
3929   g_return_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label));
3930   
3931   gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
3932 }
3933
3934 /**
3935  * gtk_notebook_insert_page:
3936  * @notebook: a #GtkNotebook
3937  * @child: the #GtkWidget to use as the contents of the page.
3938  * @tab_label: the #GtkWidget to be used as the label for the page,
3939  *             or %NULL to use the default label, 'page N'.
3940  * @position: the index (starting at 0) at which to insert the page,
3941  *            or -1 to append the page after all other pages.
3942  * 
3943  * Insert a page into @notebook at the given position
3944  **/
3945 void
3946 gtk_notebook_insert_page (GtkNotebook *notebook,
3947                           GtkWidget   *child,
3948                           GtkWidget   *tab_label,
3949                           gint         position)
3950 {
3951   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3952   g_return_if_fail (GTK_IS_WIDGET (child));
3953   g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
3954   
3955   gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
3956 }
3957
3958
3959 static gint
3960 gtk_notebook_page_compare_tab (gconstpointer a,
3961                                gconstpointer b)
3962 {
3963   return (((GtkNotebookPage *) a)->tab_label != b);
3964 }
3965
3966 static gboolean
3967 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
3968                                             gboolean overload,
3969                                             gpointer data)
3970 {
3971   GtkNotebook *notebook = GTK_NOTEBOOK (data);
3972   GList *list;
3973   
3974   list = g_list_find_custom (notebook->children, child,
3975                              gtk_notebook_page_compare_tab);
3976   if (list)
3977     {
3978       GtkNotebookPage *page = list->data;
3979
3980       gtk_widget_grab_focus (GTK_WIDGET (notebook));    /* Do this first to avoid focusing new page */
3981       gtk_notebook_switch_page (notebook, page,  -1);
3982       focus_tabs_in (notebook);
3983     }
3984
3985   return TRUE;
3986 }
3987
3988 /**
3989  * gtk_notebook_insert_page_menu:
3990  * @notebook: a #GtkNotebook
3991  * @child: the #GtkWidget to use as the contents of the page.
3992  * @tab_label: the #GtkWidget to be used as the label for the page,
3993  *             or %NULL to use the default label, 'page N'.
3994  * @menu_label: the widget to use as a label for the page-switch
3995  *              menu, if that is enabled. If %NULL, and @tab_label
3996  *              is a #GtkLabel or %NULL, then the menu label will be
3997  *              a newly created label with the same text as @tab_label;
3998  *              If @tab_label is not a #GtkLabel, @menu_label must be
3999  *              specified if the page-switch menu is to be used.
4000  * @position: the index (starting at 0) at which to insert the page,
4001  *            or -1 to append the page after all other pages.
4002  * 
4003  * Insert a page into @notebook at the given position, specifying
4004  * the widget to use as the label in the popup menu.
4005  **/
4006 void
4007 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
4008                                GtkWidget   *child,
4009                                GtkWidget   *tab_label,
4010                                GtkWidget   *menu_label,
4011                                gint         position)
4012 {
4013   GtkNotebookPage *page;
4014   gint nchildren;
4015
4016   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4017   g_return_if_fail (GTK_IS_WIDGET (child));
4018   g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label));
4019   g_return_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label));
4020
4021   gtk_widget_freeze_child_notify (child);
4022   
4023   page = g_new (GtkNotebookPage, 1);
4024   page->child = child;
4025   page->last_focus_child = NULL;
4026   page->requisition.width = 0;
4027   page->requisition.height = 0;
4028   page->allocation.x = 0;
4029   page->allocation.y = 0;
4030   page->allocation.width = 0;
4031   page->allocation.height = 0;
4032   page->default_menu = FALSE;
4033   page->default_tab = FALSE;
4034   page->mnemonic_activate_signal = 0;
4035    
4036   nchildren = g_list_length (notebook->children);
4037   if ((position < 0) || (position > nchildren))
4038     position = nchildren;
4039
4040   notebook->children = g_list_insert (notebook->children, page, position);
4041
4042   if (!tab_label)
4043     {
4044       page->default_tab = TRUE;
4045       if (notebook->show_tabs)
4046         tab_label = gtk_label_new ("");
4047     }
4048   page->tab_label = tab_label;
4049   page->menu_label = menu_label;
4050   page->expand = FALSE;
4051   page->fill = TRUE;
4052   page->pack = GTK_PACK_START;
4053
4054   if (!menu_label)
4055     page->default_menu = TRUE;
4056   else  
4057     {
4058       g_object_ref (page->menu_label);
4059       gtk_object_sink (GTK_OBJECT (page->menu_label));
4060     }
4061
4062   if (notebook->menu)
4063     gtk_notebook_menu_item_create (notebook,
4064                                    g_list_find (notebook->children, page));
4065
4066   gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4067   if (tab_label)
4068     gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4069
4070   gtk_notebook_update_labels (notebook);
4071
4072   if (!notebook->first_tab)
4073     notebook->first_tab = notebook->children;
4074
4075   if (!notebook->cur_page)
4076     gtk_widget_set_child_visible (child, TRUE);
4077   else
4078     gtk_widget_set_child_visible (child, FALSE);
4079   
4080   if (tab_label)
4081     {
4082       if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
4083         gtk_widget_show (tab_label);
4084       else
4085         gtk_widget_hide (tab_label);
4086     }
4087
4088   if (!notebook->cur_page)
4089     {
4090       gtk_notebook_switch_page (notebook, page, 0);
4091       gtk_notebook_switch_focus_tab (notebook, NULL);
4092     }
4093
4094   if (tab_label)
4095     page->mnemonic_activate_signal =
4096       g_signal_connect (tab_label,
4097                         "mnemonic_activate",
4098                         G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4099                         notebook);
4100
4101   if (notebook->show_tabs && GTK_WIDGET_MAPPED (notebook))
4102     gdk_window_show_unraised (notebook->event_window);
4103
4104   gtk_widget_child_notify (child, "tab_expand");
4105   gtk_widget_child_notify (child, "tab_fill");
4106   gtk_widget_child_notify (child, "tab_pack");
4107   gtk_widget_child_notify (child, "tab_label");
4108   gtk_widget_child_notify (child, "menu_label");
4109   gtk_widget_child_notify (child, "position");
4110   gtk_widget_thaw_child_notify (child);
4111 }
4112
4113 /**
4114  * gtk_notebook_remove_page:
4115  * @notebook: a #GtkNotebook.
4116  * @page_num: the index of a notebook page, starting
4117  *            from 0. If -1, the last page will
4118  *            be removed.
4119  * 
4120  * Removes a page from the notebook given its index
4121  * in the notebook.
4122  **/
4123 void
4124 gtk_notebook_remove_page (GtkNotebook *notebook,
4125                           gint         page_num)
4126 {
4127   GList *list;
4128   
4129   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4130   
4131   if (page_num >= 0)
4132     {
4133       list = g_list_nth (notebook->children, page_num);
4134       if (list)
4135         gtk_notebook_real_remove (notebook, list, FALSE);
4136     }
4137   else
4138     {
4139       list = g_list_last (notebook->children);
4140       if (list)
4141         gtk_notebook_real_remove (notebook, list, FALSE);
4142     }
4143 }
4144
4145 /* Public GtkNotebook Page Switch Methods :
4146  * gtk_notebook_get_current_page
4147  * gtk_notebook_page_num
4148  * gtk_notebook_set_current_page
4149  * gtk_notebook_next_page
4150  * gtk_notebook_prev_page
4151  */
4152 /**
4153  * gtk_notebook_get_current_page:
4154  * @notebook: a #GtkNotebook
4155  * 
4156  * Returns the page number of the current page.
4157  * 
4158  * Return value: the index (starting from 0) of the current
4159  * page in the notebook. If the notebook has no pages, then
4160  * -1 will be returned.
4161  **/
4162 gint
4163 gtk_notebook_get_current_page (GtkNotebook *notebook)
4164 {
4165   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4166
4167   if (!notebook->cur_page)
4168     return -1;
4169
4170   return g_list_index (notebook->children, notebook->cur_page);
4171 }
4172
4173 /**
4174  * gtk_notebook_get_nth_page:
4175  * @notebook: a #GtkNotebook
4176  * @page_num: the index of a page in the noteobok, or -1
4177  *            to get the last page.
4178  * 
4179  * Returns the child widget contained in page number @page_num.
4180  * 
4181  * Return value: the child widget, or %NULL if @page_num is
4182  * out of bounds.
4183  **/
4184 GtkWidget*
4185 gtk_notebook_get_nth_page (GtkNotebook *notebook,
4186                            gint         page_num)
4187 {
4188   GtkNotebookPage *page;
4189   GList *list;
4190
4191   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4192
4193   if (page_num >= 0)
4194     list = g_list_nth (notebook->children, page_num);
4195   else
4196     list = g_list_last (notebook->children);
4197
4198   if (list)
4199     {
4200       page = list->data;
4201       return page->child;
4202     }
4203
4204   return NULL;
4205 }
4206
4207 /**
4208  * gtk_notebook_get_n_pages:
4209  * @notebook: a #GtkNotebook
4210  * 
4211  * Gets the number of pages in a notebook.
4212  * 
4213  * Return value: the number of pages in the notebook.
4214  *
4215  * Since: 2.2
4216  **/
4217 gint
4218 gtk_notebook_get_n_pages (GtkNotebook *notebook)
4219 {
4220   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
4221
4222   return g_list_length (notebook->children);
4223 }
4224
4225 /**
4226  * gtk_notebook_page_num:
4227  * @notebook: a #GtkNotebook
4228  * @child: a #GtkWidget
4229  * 
4230  * Finds the index of the page which contains the given child
4231  * widget.
4232  * 
4233  * Return value: the index of the page containing @child, or
4234  *   -1 if @child is not in the notebook.
4235  **/
4236 gint
4237 gtk_notebook_page_num (GtkNotebook      *notebook,
4238                        GtkWidget        *child)
4239 {
4240   GList *children;
4241   gint num;
4242
4243   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4244
4245   num = 0;
4246   children = notebook->children;
4247   while (children)
4248     {
4249       GtkNotebookPage *page =  children->data;
4250       
4251       if (page->child == child)
4252         return num;
4253
4254       children = children->next;
4255       num++;
4256     }
4257
4258   return -1;
4259 }
4260
4261 /**
4262  * gtk_notebook_set_current_page:
4263  * @notebook: a #GtkNotebook
4264  * @page_num: index of the page to switch to, starting from 0.
4265  *            If negative, the last page will be used. If greater
4266  *            than the number of pages in the notebook, nothing
4267  *            will be done.
4268  *                
4269  * Switches to the page number @page_num.
4270  **/
4271 void
4272 gtk_notebook_set_current_page (GtkNotebook *notebook,
4273                                gint         page_num)
4274 {
4275   GList *list;
4276
4277   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4278
4279   if (page_num >= 0)
4280     list = g_list_nth (notebook->children, page_num);
4281   else
4282     list = g_list_last (notebook->children);
4283
4284   page_num = g_list_index (notebook->children, list);
4285
4286   if (list)
4287     gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
4288 }
4289
4290 /**
4291  * gtk_notebook_next_page:
4292  * @notebook: a #GtkNotebook
4293  * 
4294  * Switches to the next page. Nothing happens if the current page is
4295  * the last page.
4296  **/
4297 void
4298 gtk_notebook_next_page (GtkNotebook *notebook)
4299 {
4300   GList *list;
4301
4302   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4303
4304   list = g_list_find (notebook->children, notebook->cur_page);
4305   if (!list)
4306     return;
4307
4308   list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4309   if (!list)
4310     return;
4311
4312   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
4313 }
4314
4315 /**
4316  * gtk_notebook_prev_page:
4317  * @notebook: a #GtkNotebook
4318  * 
4319  * Switches to the previous page. Nothing happens if the current page
4320  * is the first page.
4321  **/
4322 void
4323 gtk_notebook_prev_page (GtkNotebook *notebook)
4324 {
4325   GList *list;
4326
4327   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4328
4329   list = g_list_find (notebook->children, notebook->cur_page);
4330   if (!list)
4331     return;
4332
4333   list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4334   if (!list)
4335     return;
4336
4337   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
4338 }
4339
4340 /* Public GtkNotebook/Tab Style Functions
4341  *
4342  * gtk_notebook_set_show_border
4343  * gtk_notebook_set_show_tabs
4344  * gtk_notebook_set_tab_pos
4345  * gtk_notebook_set_homogeneous_tabs
4346  * gtk_notebook_set_tab_border
4347  * gtk_notebook_set_tab_hborder
4348  * gtk_notebook_set_tab_vborder
4349  * gtk_notebook_set_scrollable
4350  */
4351 /**
4352  * gtk_notebook_set_show_border:
4353  * @notebook: a #GtkNotebook
4354  * @show_border: %TRUE if a bevel should be drawn around the notebook.
4355  * 
4356  * Sets whether a bevel will be drawn around the notebook pages.
4357  * This only has a visual effect when the tabs are not shown.
4358  * See gtk_notebook_set_show_tabs().
4359  **/
4360 void
4361 gtk_notebook_set_show_border (GtkNotebook *notebook,
4362                               gboolean     show_border)
4363 {
4364   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4365
4366   if (notebook->show_border != show_border)
4367     {
4368       notebook->show_border = show_border;
4369
4370       if (GTK_WIDGET_VISIBLE (notebook))
4371         gtk_widget_queue_resize (GTK_WIDGET (notebook));
4372       
4373       g_object_notify (G_OBJECT (notebook), "show_border");
4374     }
4375 }
4376
4377 /**
4378  * gtk_notebook_get_show_border:
4379  * @notebook: a #GtkNotebook
4380  *
4381  * Returns whether a bevel will be drawn around the notebook pages. See
4382  * gtk_notebook_set_show_border().
4383  *
4384  * Return value: %TRUE if the bevel is drawn
4385  **/
4386 gboolean
4387 gtk_notebook_get_show_border (GtkNotebook *notebook)
4388 {
4389   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
4390
4391   return notebook->show_border;
4392 }
4393
4394 /**
4395  * gtk_notebook_set_show_tabs:
4396  * @notebook: a #GtkNotebook
4397  * @show_tabs: %TRUE if the tabs should be shown.
4398  * 
4399  * Sets whether to show the tabs for the notebook or not.
4400  **/
4401 void
4402 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
4403                             gboolean     show_tabs)
4404 {
4405   GtkNotebookPage *page;
4406   GList *children;
4407
4408   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4409
4410   show_tabs = show_tabs != FALSE;
4411
4412   if (notebook->show_tabs == show_tabs)
4413     return;
4414
4415   notebook->show_tabs = show_tabs;
4416   children = notebook->children;
4417
4418   if (!show_tabs)
4419     {
4420       GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
4421       
4422       while (children)
4423         {
4424           page = children->data;
4425           children = children->next;
4426           if (page->default_tab)
4427             {
4428               gtk_widget_destroy (page->tab_label);
4429               page->tab_label = NULL;
4430             }
4431           else
4432             gtk_widget_hide (page->tab_label);
4433         }
4434     }
4435   else
4436     {
4437       GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
4438       gtk_notebook_update_labels (notebook);
4439     }
4440   gtk_widget_queue_resize (GTK_WIDGET (notebook));
4441
4442   g_object_notify (G_OBJECT (notebook), "show_tabs");
4443 }
4444
4445 /**
4446  * gtk_notebook_get_show_tabs:
4447  * @notebook: a #GtkNotebook
4448  *
4449  * Returns whether the tabs of the notebook are shown. See
4450  * gtk_notebook_set_show_tabs().
4451  *
4452  * Return value: %TRUE if the tabs are shown
4453  **/
4454 gboolean
4455 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
4456 {
4457   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
4458
4459   return notebook->show_tabs;
4460 }
4461
4462 /**
4463  * gtk_notebook_set_tab_pos:
4464  * @notebook: a #GtkNotebook.
4465  * @pos: the edge to draw the tabs at.
4466  * 
4467  * Sets the edge at which the tabs for switching pages in the
4468  * notebook are drawn.
4469  **/
4470 void
4471 gtk_notebook_set_tab_pos (GtkNotebook     *notebook,
4472                           GtkPositionType  pos)
4473 {
4474   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4475
4476   if (notebook->tab_pos != pos)
4477     {
4478       notebook->tab_pos = pos;
4479       if (GTK_WIDGET_VISIBLE (notebook))
4480         gtk_widget_queue_resize (GTK_WIDGET (notebook));
4481     }
4482
4483   g_object_notify (G_OBJECT (notebook), "tab_pos");
4484 }
4485
4486 /**
4487  * gtk_notebook_get_tab_pos:
4488  * @notebook: a #GtkNotebook
4489  *
4490  * Gets the edge at which the tabs for switching pages in the
4491  * notebook are drawn.
4492  *
4493  * Return value: the edge at which the tabs are drawn
4494  **/
4495 GtkPositionType
4496 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
4497 {
4498   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
4499
4500   return notebook->tab_pos;
4501 }
4502
4503 /**
4504  * gtk_notebook_set_homogeneous_tabs:
4505  * @notebook: a #GtkNotebook
4506  * @homogeneous: %TRUE if all tabs should be the same size.
4507  * 
4508  * Sets whether the tabs must have all the same size or not.
4509  **/
4510 void
4511 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
4512                                    gboolean     homogeneous)
4513 {
4514   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4515
4516   gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
4517 }
4518
4519 /**
4520  * gtk_notebook_set_tab_border:
4521  * @notebook: a #GtkNotebook
4522  * @border_width: width of the border around the tab labels.
4523  * 
4524  * Sets the width the border around the tab labels
4525  * in a notebook. This is equivalent to calling
4526  * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
4527  * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
4528  **/
4529 void
4530 gtk_notebook_set_tab_border (GtkNotebook *notebook,
4531                              guint        border_width)
4532 {
4533   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4534
4535   gtk_notebook_set_tab_border_internal (notebook, border_width);
4536 }
4537
4538 /**
4539  * gtk_notebook_set_tab_hborder:
4540  * @notebook: a #GtkNotebook
4541  * @tab_hborder: width of the horizontal border of tab labels.
4542  * 
4543  * Sets the width of the horizontal border of tab labels.
4544  **/
4545 void
4546 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
4547                               guint        tab_hborder)
4548 {
4549   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4550
4551   gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
4552 }
4553
4554 /**
4555  * gtk_notebook_set_tab_vborder:
4556  * @notebook: a #GtkNotebook
4557  * @tab_vborder: width of the vertical border of tab labels.
4558  * 
4559  * Sets the width of the vertical border of tab labels.
4560  **/
4561 void
4562 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
4563                               guint        tab_vborder)
4564 {
4565   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4566
4567   gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
4568 }
4569
4570 /**
4571  * gtk_notebook_set_scrollable:
4572  * @notebook: a #GtkNotebook
4573  * @scrollable: %TRUE if scroll arrows should be added
4574  * 
4575  * Sets whether the tab label area will have arrows for scrolling if
4576  * there are too many tabs to fit in the area.
4577  **/
4578 void
4579 gtk_notebook_set_scrollable (GtkNotebook *notebook,
4580                              gboolean     scrollable)
4581 {
4582   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4583
4584   scrollable = (scrollable != FALSE);
4585
4586   if (scrollable != notebook->scrollable)
4587     {
4588       notebook->scrollable = scrollable;
4589
4590       if (GTK_WIDGET_VISIBLE (notebook))
4591         gtk_widget_queue_resize (GTK_WIDGET (notebook));
4592
4593       g_object_notify (G_OBJECT (notebook), "scrollable");
4594     }
4595 }
4596
4597 /**
4598  * gtk_notebook_get_scrollable:
4599  * @notebook: a #GtkNotebook
4600  *
4601  * Returns whether the tab label area has arrows for scrolling. See
4602  * gtk_notebook_set_scrollable().
4603  *
4604  * Return value: %TRUE if arrows for scrolling are present
4605  **/
4606 gboolean
4607 gtk_notebook_get_scrollable (GtkNotebook *notebook)
4608 {
4609   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
4610
4611   return notebook->scrollable;
4612 }
4613
4614 /* Public GtkNotebook Popup Menu Methods:
4615  *
4616  * gtk_notebook_popup_enable
4617  * gtk_notebook_popup_disable
4618  */
4619
4620
4621 /**
4622  * gtk_notebook_popup_enable:
4623  * @notebook: a #GtkNotebook
4624  * 
4625  * Enables the popup menu: if the user clicks with the right mouse button on
4626  * the bookmarks, a menu with all the pages will be popped up.
4627  **/
4628 void
4629 gtk_notebook_popup_enable (GtkNotebook *notebook)
4630 {
4631   GList *list;
4632
4633   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4634
4635   if (notebook->menu)
4636     return;
4637
4638   notebook->menu = gtk_menu_new ();
4639   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4640        list;
4641        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4642     gtk_notebook_menu_item_create (notebook, list);
4643
4644   gtk_notebook_update_labels (notebook);
4645   gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
4646                              GTK_WIDGET (notebook),
4647                              gtk_notebook_menu_detacher);
4648
4649   g_object_notify (G_OBJECT (notebook), "enable_popup");
4650 }
4651
4652 /**
4653  * gtk_notebook_popup_disable:
4654  * @notebook: a #GtkNotebook
4655  * 
4656  * Disables the popup menu.
4657  **/
4658 void       
4659 gtk_notebook_popup_disable  (GtkNotebook *notebook)
4660 {
4661   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4662
4663   if (!notebook->menu)
4664     return;
4665
4666   gtk_container_foreach (GTK_CONTAINER (notebook->menu),
4667                          (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
4668   gtk_widget_destroy (notebook->menu);
4669
4670   g_object_notify (G_OBJECT (notebook), "enable_popup");
4671 }
4672
4673 /* Public GtkNotebook Page Properties Functions:
4674  *
4675  * gtk_notebook_get_tab_label
4676  * gtk_notebook_set_tab_label
4677  * gtk_notebook_set_tab_label_text
4678  * gtk_notebook_get_menu_label
4679  * gtk_notebook_set_menu_label
4680  * gtk_notebook_set_menu_label_text
4681  * gtk_notebook_set_tab_label_packing
4682  * gtk_notebook_query_tab_label_packing
4683  */
4684
4685 /**
4686  * gtk_notebook_get_tab_label:
4687  * @notebook: a #GtkNotebook
4688  * @child: the page
4689  * 
4690  * Returns the tab label widget for the page @child. %NULL is returned
4691  * if @child is not in @notebook or if no tab label has specifically
4692  * been set for @child.
4693  * 
4694  * Return value: the tab label
4695  **/
4696 GtkWidget *
4697 gtk_notebook_get_tab_label (GtkNotebook *notebook,
4698                             GtkWidget   *child)
4699 {
4700   GList *list;
4701
4702   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4703   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
4704
4705   list = CHECK_FIND_CHILD (notebook, child);
4706   if (!list)  
4707     return NULL;
4708
4709   if (GTK_NOTEBOOK_PAGE (list)->default_tab)
4710     return NULL;
4711
4712   return GTK_NOTEBOOK_PAGE (list)->tab_label;
4713 }  
4714
4715 /**
4716  * gtk_notebook_set_tab_label:
4717  * @notebook: a #GtkNotebook
4718  * @child: the page
4719  * @tab_label: the tab label widget to use, or %NULL for default tab
4720  *             label.
4721  * 
4722  * Changes the tab label for @child. If %NULL is specified
4723  * for @tab_label, then the page will have the label 'page N'.
4724  **/
4725 void
4726 gtk_notebook_set_tab_label (GtkNotebook *notebook,
4727                             GtkWidget   *child,
4728                             GtkWidget   *tab_label)
4729 {
4730   GtkNotebookPage *page;
4731   GList *list;
4732
4733   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4734   g_return_if_fail (GTK_IS_WIDGET (child));
4735
4736   list = CHECK_FIND_CHILD (notebook, child);
4737   if (!list)  
4738     return;
4739
4740   /* a NULL pointer indicates a default_tab setting, otherwise
4741    * we need to set the associated label
4742    */
4743   page = list->data;
4744   
4745   if (page->tab_label == tab_label)
4746     return;
4747   
4748
4749   gtk_notebook_remove_tab_label (notebook, page);
4750   
4751   if (tab_label)
4752     {
4753       page->default_tab = FALSE;
4754       page->tab_label = tab_label;
4755       gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
4756     }
4757   else
4758     {
4759       page->default_tab = TRUE;
4760       page->tab_label = NULL;
4761
4762       if (notebook->show_tabs)
4763         {
4764           gchar string[32];
4765
4766           g_snprintf (string, sizeof(string), _("Page %u"), 
4767                       gtk_notebook_real_page_position (notebook, list));
4768           page->tab_label = gtk_label_new (string);
4769           gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
4770         }
4771     }
4772
4773   if (page->tab_label)
4774     page->mnemonic_activate_signal =
4775       g_signal_connect (page->tab_label,
4776                         "mnemonic_activate",
4777                         G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4778                         notebook);
4779
4780   if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
4781     {
4782       gtk_widget_show (page->tab_label);
4783       gtk_widget_queue_resize (GTK_WIDGET (notebook));
4784     }
4785   gtk_widget_child_notify (child, "tab_label");
4786 }
4787
4788 /**
4789  * gtk_notebook_set_tab_label_text:
4790  * @notebook: a #GtkNotebook
4791  * @child: the page
4792  * @tab_text: the label text
4793  * 
4794  * Creates a new label and sets it as the tab label for the page
4795  * containing @child.
4796  **/
4797 void
4798 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
4799                                  GtkWidget   *child,
4800                                  const gchar *tab_text)
4801 {
4802   GtkWidget *tab_label = NULL;
4803
4804   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4805
4806   if (tab_text)
4807     tab_label = gtk_label_new (tab_text);
4808   gtk_notebook_set_tab_label (notebook, child, tab_label);
4809   gtk_widget_child_notify (child, "tab_label");
4810 }
4811
4812 /**
4813  * gtk_notebook_get_tab_label_text:
4814  * @notebook: a #GtkNotebook
4815  * @child: a widget contained in a page of @notebook
4816  *
4817  * Retrieves the text of the tab label for the page containing
4818  *    @child.
4819  *
4820  * Returns value: the text of the tab label, or %NULL if the
4821  *                tab label widget is not a #GtkLabel. The
4822  *                string is owned by the widget and must not
4823  *                be freed.
4824  **/
4825 G_CONST_RETURN gchar *
4826 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
4827                                  GtkWidget   *child)
4828 {
4829   GtkWidget *tab_label;
4830
4831   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4832   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
4833
4834   tab_label = gtk_notebook_get_tab_label (notebook, child);
4835
4836   if (tab_label && GTK_IS_LABEL (tab_label))
4837     return gtk_label_get_text (GTK_LABEL (tab_label));
4838   else
4839     return NULL;
4840 }
4841
4842 /**
4843  * gtk_notebook_get_menu_label:
4844  * @notebook: a #GtkNotebook
4845  * @child: a widget contained in a page of @notebook
4846  * 
4847  * Retrieves the menu label widget of the page containing @child.
4848  * 
4849  * Return value: the menu label, or %NULL if the
4850  *               notebook page does not have a menu label other
4851  *               than the default (the tab label).
4852  **/
4853 GtkWidget*
4854 gtk_notebook_get_menu_label (GtkNotebook *notebook,
4855                              GtkWidget   *child)
4856 {
4857   GList *list;
4858
4859   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4860   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
4861
4862   list = CHECK_FIND_CHILD (notebook, child);
4863   if (!list)  
4864     return NULL;
4865
4866   if (GTK_NOTEBOOK_PAGE (list)->default_menu)
4867     return NULL;
4868
4869   return GTK_NOTEBOOK_PAGE (list)->menu_label;
4870 }  
4871
4872 /**
4873  * gtk_notebook_set_menu_label:
4874  * @notebook: a #GtkNotebook
4875  * @child: the child widget
4876  * @menu_label: the menu label, or NULL for default
4877  * 
4878  * Changes the menu label for the page containing @child. 
4879  **/
4880 void
4881 gtk_notebook_set_menu_label (GtkNotebook *notebook,
4882                              GtkWidget   *child,
4883                              GtkWidget   *menu_label)
4884 {
4885   GtkNotebookPage *page;
4886   GList *list;
4887
4888   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4889   g_return_if_fail (GTK_IS_WIDGET (child));
4890
4891   list = CHECK_FIND_CHILD (notebook, child);
4892   if (!list)  
4893     return;
4894
4895   page = list->data;
4896   if (page->menu_label)
4897     {
4898       if (notebook->menu)
4899         gtk_container_remove (GTK_CONTAINER (notebook->menu), 
4900                               page->menu_label->parent);
4901
4902       if (!page->default_menu)
4903         g_object_unref (page->menu_label);
4904     }
4905
4906   if (menu_label)
4907     {
4908       page->menu_label = menu_label;
4909       g_object_ref (page->menu_label);
4910       gtk_object_sink (GTK_OBJECT(page->menu_label));
4911       page->default_menu = FALSE;
4912     }
4913   else
4914     page->default_menu = TRUE;
4915
4916   if (notebook->menu)
4917     gtk_notebook_menu_item_create (notebook, list);
4918   gtk_widget_child_notify (child, "menu_label");
4919 }
4920
4921 /**
4922  * gtk_notebook_set_menu_label_text:
4923  * @notebook: a #GtkNotebook
4924  * @child: the child widget
4925  * @menu_text: the label text
4926  * 
4927  * Creates a new label and sets it as the menu label of @child.
4928  **/
4929 void
4930 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
4931                                   GtkWidget   *child,
4932                                   const gchar *menu_text)
4933 {
4934   GtkWidget *menu_label = NULL;
4935
4936   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4937
4938   if (menu_text)
4939     menu_label = gtk_label_new (menu_text);
4940   gtk_notebook_set_menu_label (notebook, child, menu_label);
4941   gtk_widget_child_notify (child, "menu_label");
4942 }
4943
4944 /**
4945  * gtk_notebook_get_menu_label_text:
4946  * @notebook: a #GtkNotebook
4947  * @child: the child widget of a page of the notebook.
4948  *
4949  * Retrieves the text of the menu label for the page containing
4950  *    @child.
4951  *
4952  * Returns value: the text of the tab label, or %NULL if the
4953  *                widget does not have a menu label other than
4954  *                the default menu label, or the menu label widget
4955  *                is not a #GtkLabel. The string is owned by
4956  *                the widget and must not be freed.
4957  **/
4958 G_CONST_RETURN gchar *
4959 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
4960                                   GtkWidget *child)
4961 {
4962   GtkWidget *menu_label;
4963
4964   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4965   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
4966  
4967   menu_label = gtk_notebook_get_menu_label (notebook, child);
4968
4969   if (menu_label && GTK_IS_LABEL (menu_label))
4970     return gtk_label_get_text (GTK_LABEL (menu_label));
4971   else
4972     return NULL;
4973 }
4974   
4975 /* Helper function called when pages are reordered
4976  */
4977 static void
4978 gtk_notebook_child_reordered (GtkNotebook     *notebook,
4979                               GtkNotebookPage *page)
4980 {
4981   if (notebook->menu)
4982     {
4983       GtkWidget *menu_item;
4984       
4985       menu_item = page->menu_label->parent;
4986       gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
4987       gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
4988       gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
4989     }
4990   
4991   gtk_notebook_update_labels (notebook);
4992 }
4993
4994 /**
4995  * gtk_notebook_set_tab_label_packing:
4996  * @notebook: a #GtkNotebook
4997  * @child: the child widget
4998  * @expand: whether to expand the bookmark or not
4999  * @fill: whether the bookmark should fill the allocated area or not
5000  * @pack_type: the position of the bookmark
5001  * 
5002  * Sets the packing parameters for the tab label of the page
5003  * containing @child. See gtk_box_pack_start() for the exact meaning
5004  * of the parameters.
5005  **/
5006 void
5007 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
5008                                     GtkWidget   *child,
5009                                     gboolean     expand,
5010                                     gboolean     fill,
5011                                     GtkPackType  pack_type)
5012 {
5013   GtkNotebookPage *page;
5014   GList *list;
5015
5016   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5017   g_return_if_fail (GTK_IS_WIDGET (child));
5018
5019   list = CHECK_FIND_CHILD (notebook, child);
5020   if (!list)  
5021     return;
5022
5023   page = list->data;
5024   expand = expand != FALSE;
5025   fill = fill != FALSE;
5026   if (page->pack == pack_type && page->expand == expand && page->fill == fill)
5027     return;
5028
5029   gtk_widget_freeze_child_notify (child);
5030   page->expand = expand;
5031   gtk_widget_child_notify (child, "tab_expand");
5032   page->fill = fill;
5033   gtk_widget_child_notify (child, "tab_fill");
5034   if (page->pack != pack_type)
5035     {
5036       page->pack = pack_type;
5037       gtk_notebook_child_reordered (notebook, page);
5038     }
5039   gtk_widget_child_notify (child, "tab_pack");
5040   gtk_widget_child_notify (child, "position");
5041   if (notebook->show_tabs)
5042     gtk_notebook_pages_allocate (notebook);
5043   gtk_widget_thaw_child_notify (child);
5044 }  
5045
5046 /**
5047  * gtk_notebook_query_tab_label_packing:
5048  * @notebook: a #GtkNotebook
5049  * @child: the page
5050  * @expand: location to store the expand value (or NULL)
5051  * @fill: location to store the fill value (or NULL)
5052  * @pack_type: location to store the pack_type (or NULL)
5053  * 
5054  * Query the packing attributes for the tab label of the page
5055  * containing @child.
5056  **/
5057 void
5058 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
5059                                       GtkWidget   *child,
5060                                       gboolean    *expand,
5061                                       gboolean    *fill,
5062                                       GtkPackType *pack_type)
5063 {
5064   GList *list;
5065
5066   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5067   g_return_if_fail (GTK_IS_WIDGET (child));
5068
5069   list = CHECK_FIND_CHILD (notebook, child);
5070   if (!list)
5071     return;
5072
5073   if (expand)
5074     *expand = GTK_NOTEBOOK_PAGE (list)->expand;
5075   if (fill)
5076     *fill = GTK_NOTEBOOK_PAGE (list)->fill;
5077   if (pack_type)
5078     *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
5079 }
5080
5081 /**
5082  * gtk_notebook_reorder_child:
5083  * @notebook: a #GtkNotebook
5084  * @child: the child to move
5085  * @position: the new position, or -1 to move to the end
5086  * 
5087  * Reorders the page containing @child, so that it appears in position
5088  * @position. If @position is greater than or equal to the number of
5089  * children in the list or negative, @child will be moved to the end
5090  * of the list.
5091  **/
5092 void
5093 gtk_notebook_reorder_child (GtkNotebook *notebook,
5094                             GtkWidget   *child,
5095                             gint         position)
5096 {
5097   GList *list, *new_list;
5098   GtkNotebookPage *page;
5099   gint old_pos;
5100   gint max_pos;
5101
5102   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5103   g_return_if_fail (GTK_IS_WIDGET (child));
5104
5105   list = CHECK_FIND_CHILD (notebook, child);
5106   if (!list)
5107     return;
5108
5109   max_pos = g_list_length (notebook->children) - 1;
5110   if (position < 0 || position > max_pos)
5111     position = max_pos;
5112
5113   old_pos = g_list_position (notebook->children, list);
5114
5115   if (old_pos == position)
5116     return;
5117
5118   page = list->data;
5119   notebook->children = g_list_delete_link (notebook->children, list);
5120
5121   notebook->children = g_list_insert (notebook->children, page, position);
5122   new_list = g_list_nth (notebook->children, position);
5123
5124   /* Fix up GList references in GtkNotebook structure */
5125   if (notebook->first_tab == list)
5126     notebook->first_tab = new_list;
5127   if (notebook->focus_tab == list)
5128     notebook->focus_tab = new_list;
5129
5130   gtk_widget_freeze_child_notify (child);
5131
5132   /* Move around the menu items if necesary */
5133   gtk_notebook_child_reordered (notebook, page);
5134   gtk_widget_child_notify (child, "tab_pack");
5135   gtk_widget_child_notify (child, "position");
5136   
5137   if (notebook->show_tabs)
5138     gtk_notebook_pages_allocate (notebook);
5139
5140   gtk_widget_thaw_child_notify (child);
5141 }