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