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