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