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