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