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