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