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