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