]> Pileus Git - ~andy/gtk/blob - gtk/gtknotebook.c
Add scroll events to the event mask, set a scroll_event handler. Handle
[~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 childs 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 childs 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 childs 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 childs 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   if ((vis_pages != 0) != notebook->have_visible_child)
1518     {
1519       notebook->have_visible_child = (vis_pages != 0);
1520       if (notebook->show_tabs)
1521         gtk_widget_queue_draw (widget);
1522     }
1523 }
1524
1525 static gint
1526 gtk_notebook_expose (GtkWidget      *widget,
1527                      GdkEventExpose *event)
1528 {
1529   GtkNotebook *notebook;
1530   GdkRectangle child_area;
1531    
1532   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1533   g_return_val_if_fail (event != NULL, FALSE);
1534
1535   if (GTK_WIDGET_DRAWABLE (widget))
1536     {
1537       notebook = GTK_NOTEBOOK (widget);
1538
1539       gtk_notebook_paint (widget, &event->area);
1540       if (notebook->show_tabs)
1541         {
1542           if (notebook->cur_page && 
1543               gtk_widget_intersect (notebook->cur_page->tab_label, 
1544                                     &event->area, &child_area))
1545             gtk_notebook_draw_focus (widget);
1546         }
1547
1548       
1549       if (notebook->cur_page)
1550         gtk_container_propagate_expose (GTK_CONTAINER (notebook),
1551                                         notebook->cur_page->child,
1552                                         event);
1553     }
1554
1555   return FALSE;
1556 }
1557
1558 static gboolean
1559 gtk_notebook_show_arrows (GtkNotebook *notebook)
1560 {
1561   gboolean show_arrow = FALSE;
1562   GList *children;
1563   
1564   if (!notebook->scrollable)
1565     return FALSE;
1566
1567   children = notebook->children;
1568   while (children)
1569     {
1570       GtkNotebookPage *page = children->data;
1571
1572       if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
1573         show_arrow = TRUE;
1574
1575       children = children->next;
1576     }
1577
1578   return show_arrow;
1579 }
1580
1581 static void
1582 gtk_notebook_get_arrow_rect (GtkNotebook     *notebook,
1583                              GdkRectangle    *rectangle,
1584                              GtkNotebookArrow arrow)
1585 {
1586   GdkRectangle event_window_pos;
1587   gboolean before = ARROW_IS_BEFORE (arrow);
1588   gboolean left = ARROW_IS_LEFT (arrow);
1589
1590   if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
1591     {
1592       rectangle->width = ARROW_SIZE;
1593       rectangle->height = ARROW_SIZE;
1594
1595       switch (notebook->tab_pos)
1596         {
1597         case GTK_POS_LEFT:
1598         case GTK_POS_RIGHT:
1599           if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
1600               (!before && (notebook->has_after_previous != notebook->has_after_next))) 
1601           rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
1602           else if (left)
1603             rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
1604           else 
1605             rectangle->x = event_window_pos.x + event_window_pos.width / 2;
1606           rectangle->y = event_window_pos.y;
1607           if (!before)
1608             rectangle->y += event_window_pos.height - rectangle->height;
1609           break;
1610         case GTK_POS_TOP:
1611         case GTK_POS_BOTTOM:
1612           if (before)
1613             {
1614               if (left || !notebook->has_before_previous)
1615                 rectangle->x = event_window_pos.x;
1616               else
1617                 rectangle->x = event_window_pos.x + rectangle->width;
1618             }
1619           else
1620             {
1621               if (!left || !notebook->has_after_next)
1622                 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
1623               else
1624                 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
1625             }
1626           rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
1627           break;
1628         }
1629     }
1630 }
1631
1632 static GtkNotebookArrow
1633 gtk_notebook_get_arrow (GtkNotebook *notebook,
1634                         gint         x,
1635                         gint         y)
1636 {
1637   GdkRectangle arrow_rect;
1638   GdkRectangle event_window_pos;
1639   gint i;
1640   gint x0, y0;
1641   GtkNotebookArrow arrow[4];
1642
1643   arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
1644   arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
1645   arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
1646   arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
1647
1648   if (gtk_notebook_show_arrows (notebook))
1649     {
1650       gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1651       for (i = 0; i < 4; i++) 
1652         { 
1653           if (arrow[i] == ARROW_NONE)
1654             continue;
1655       
1656           gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
1657       
1658           x0 = x - arrow_rect.x;
1659           y0 = y - arrow_rect.y;
1660           
1661           if (y0 >= 0 && y0 < arrow_rect.height &&
1662               x0 >= 0 && x0 < arrow_rect.width)
1663             return arrow[i];
1664         }
1665     }
1666
1667   return ARROW_NONE;
1668 }
1669
1670 static void
1671 gtk_notebook_do_arrow (GtkNotebook     *notebook,
1672                        GtkNotebookArrow arrow)
1673 {
1674   GtkWidget *widget = GTK_WIDGET (notebook);
1675   GtkDirectionType dir;
1676   gboolean is_rtl, left;
1677
1678   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1679   left = (ARROW_IS_LEFT (arrow) && !is_rtl) || 
1680          (!ARROW_IS_LEFT (arrow) && is_rtl);
1681   
1682   if (!notebook->focus_tab ||
1683       gtk_notebook_search_page (notebook, notebook->focus_tab,
1684                                 left ? STEP_PREV : STEP_NEXT,
1685                                 TRUE))
1686     {
1687       if (notebook->tab_pos == GTK_POS_LEFT ||
1688           notebook->tab_pos == GTK_POS_RIGHT)
1689         dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
1690       else
1691         dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
1692       gtk_widget_child_focus (widget, dir);
1693     }
1694 }
1695
1696 static gboolean
1697 gtk_notebook_arrow_button_press (GtkNotebook      *notebook,
1698                                  GtkNotebookArrow  arrow,
1699                                  GdkEventButton   *event)
1700 {
1701   GtkWidget *widget = GTK_WIDGET (notebook);
1702   gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1703   gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) || 
1704                   (!ARROW_IS_LEFT (arrow) && is_rtl);
1705
1706   if (!GTK_WIDGET_HAS_FOCUS (widget))
1707     gtk_widget_grab_focus (widget);
1708   
1709   notebook->button = event->button;
1710   notebook->click_child = arrow;
1711   
1712   if (event->button == 1)
1713     {
1714       gtk_notebook_do_arrow (notebook, arrow);
1715       
1716       if (!notebook->timer)
1717         {
1718           notebook->timer = g_timeout_add (NOTEBOOK_INIT_SCROLL_DELAY, 
1719                                            (GSourceFunc) gtk_notebook_timer, 
1720                                            (gpointer) notebook);
1721           notebook->need_timer = TRUE;
1722         }
1723     }
1724   else if (event->button == 2)
1725     gtk_notebook_page_select (notebook, TRUE);
1726   else if (event->button == 3)
1727     gtk_notebook_switch_focus_tab (notebook,
1728                                    gtk_notebook_search_page (notebook,
1729                                                              NULL,
1730                                                              left ? STEP_NEXT : STEP_PREV,
1731                                                              TRUE));
1732   gtk_notebook_redraw_arrows (notebook);
1733
1734   return TRUE;
1735 }
1736
1737 static gboolean
1738 get_widget_coordinates (GtkWidget *widget,
1739                         GdkEvent  *event,
1740                         gint      *x,
1741                         gint      *y)
1742 {
1743   GdkWindow *window = ((GdkEventAny *)event)->window;
1744   gdouble tx, ty;
1745
1746   if (!gdk_event_get_coords (event, &tx, &ty))
1747     return FALSE;
1748
1749   while (window && window != widget->window)
1750     {
1751       gint window_x, window_y;
1752       
1753       gdk_window_get_position (window, &window_x, &window_y);
1754       tx += window_x;
1755       ty += window_y;
1756
1757       window = gdk_window_get_parent (window);
1758     }
1759
1760   if (window)
1761     {
1762       *x = tx;
1763       *y = ty;
1764
1765       return TRUE;
1766     }
1767   else
1768     return FALSE;
1769 }
1770
1771 static gboolean
1772 gtk_notebook_scroll (GtkWidget      *widget,
1773                      GdkEventScroll *event)
1774 {
1775   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1776
1777   switch (event->direction)
1778     {
1779     case GDK_SCROLL_RIGHT:
1780     case GDK_SCROLL_DOWN:
1781       gtk_notebook_next_page (notebook);
1782       break;
1783     case GDK_SCROLL_LEFT:
1784     case GDK_SCROLL_UP:
1785       gtk_notebook_prev_page (notebook);
1786       break;
1787     }
1788
1789   return TRUE;
1790 }
1791
1792 static gboolean
1793 gtk_notebook_button_press (GtkWidget      *widget,
1794                            GdkEventButton *event)
1795 {
1796   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1797   GtkNotebookPage *page;
1798   GList *children;
1799   GtkNotebookArrow arrow;
1800   gint num;
1801   gint x, y;
1802
1803   if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
1804       notebook->button)
1805     return FALSE;
1806
1807   if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
1808     return FALSE;
1809
1810   arrow = gtk_notebook_get_arrow (notebook, x, y);
1811   if (arrow)
1812     return gtk_notebook_arrow_button_press (notebook, arrow, event);
1813
1814   if (event->button == 3 && notebook->menu)
1815     {
1816       gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL, 
1817                       NULL, NULL, 3, event->time);
1818       return TRUE;
1819     }
1820
1821   if (event->button != 1)
1822     return FALSE;
1823   
1824   num = 0;
1825   children = notebook->children;
1826   while (children)
1827     {
1828       page = children->data;
1829       
1830       if (GTK_WIDGET_VISIBLE (page->child) &&
1831           page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
1832           (x >= page->allocation.x) &&
1833           (y >= page->allocation.y) &&
1834           (x <= (page->allocation.x + page->allocation.width)) &&
1835           (y <= (page->allocation.y + page->allocation.height)))
1836         {
1837           gboolean page_changed = page != notebook->cur_page;
1838           gboolean was_focus = gtk_widget_is_focus (widget);
1839           
1840           gtk_notebook_switch_focus_tab (notebook, children);
1841           gtk_widget_grab_focus (widget);
1842           
1843           if (page_changed && !was_focus)
1844             gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
1845           
1846           break;
1847         }
1848       children = children->next;
1849       num++;
1850     }
1851   
1852   return TRUE;
1853 }
1854
1855 static void 
1856 stop_scrolling (GtkNotebook *notebook)
1857 {
1858   if (notebook->timer)
1859     {
1860       g_source_remove (notebook->timer);
1861       notebook->timer = 0;
1862       notebook->need_timer = FALSE;
1863     }
1864   notebook->click_child = 0;
1865   notebook->button = 0;
1866   gtk_notebook_redraw_arrows (notebook);
1867 }
1868
1869 static gint
1870 gtk_notebook_button_release (GtkWidget      *widget,
1871                              GdkEventButton *event)
1872 {
1873   GtkNotebook *notebook;
1874
1875   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1876   g_return_val_if_fail (event != NULL, FALSE);
1877
1878   if (event->type != GDK_BUTTON_RELEASE)
1879     return FALSE;
1880
1881   notebook = GTK_NOTEBOOK (widget);
1882
1883   if (event->button == notebook->button)
1884     {
1885       stop_scrolling (notebook);
1886
1887       return TRUE;
1888     }
1889   else
1890     return FALSE;
1891 }
1892
1893 static gint
1894 gtk_notebook_enter_notify (GtkWidget        *widget,
1895                            GdkEventCrossing *event)
1896 {
1897   GtkNotebook *notebook;
1898   GtkNotebookArrow arrow;
1899   gint x, y;
1900
1901   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1902   g_return_val_if_fail (event != NULL, FALSE);
1903
1904   notebook = GTK_NOTEBOOK (widget);
1905
1906   if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
1907     return FALSE;
1908
1909   arrow = gtk_notebook_get_arrow (notebook, x, y);
1910
1911   if (arrow != notebook->in_child)
1912     {
1913       notebook->in_child = arrow;
1914       gtk_notebook_redraw_arrows (notebook);
1915
1916       return TRUE;
1917     }
1918
1919   return TRUE;
1920 }
1921
1922 static gint
1923 gtk_notebook_leave_notify (GtkWidget        *widget,
1924                            GdkEventCrossing *event)
1925 {
1926   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1927   GtkNotebookArrow arrow;
1928   gint x, y;
1929
1930   if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
1931     return FALSE;
1932
1933   arrow = gtk_notebook_get_arrow (notebook, x, y);
1934
1935   if (notebook->in_child)
1936     {
1937       notebook->in_child = 0;
1938       gtk_notebook_redraw_arrows (notebook);
1939     }
1940
1941   return TRUE;
1942 }
1943
1944 static gint
1945 gtk_notebook_motion_notify (GtkWidget      *widget,
1946                             GdkEventMotion *event)
1947 {
1948   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1949   GtkNotebookArrow arrow;
1950   gint x, y;
1951   
1952   if (notebook->button)
1953     return FALSE;
1954
1955   if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
1956     return FALSE;
1957
1958   arrow = gtk_notebook_get_arrow (notebook, x, y);
1959
1960   if (arrow != notebook->in_child)
1961     {
1962       notebook->in_child = arrow;
1963       gtk_notebook_redraw_arrows (notebook);
1964     }
1965   
1966   return TRUE;
1967 }
1968
1969 static void
1970 gtk_notebook_grab_notify (GtkWidget *widget,
1971                           gboolean   was_grabbed)
1972 {
1973   if (!was_grabbed)
1974     stop_scrolling (GTK_NOTEBOOK (widget));
1975 }
1976
1977 static void
1978 gtk_notebook_state_changed (GtkWidget    *widget,
1979                             GtkStateType  previous_state)
1980 {
1981   if (!GTK_WIDGET_IS_SENSITIVE (widget)) 
1982     stop_scrolling (GTK_NOTEBOOK (widget));
1983 }
1984
1985 static gint
1986 gtk_notebook_focus_in (GtkWidget     *widget,
1987                        GdkEventFocus *event)
1988 {
1989   GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
1990
1991   gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
1992   
1993   return FALSE;
1994 }
1995
1996 static gint
1997 gtk_notebook_focus_out (GtkWidget     *widget,
1998                         GdkEventFocus *event)
1999 {
2000   gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2001
2002   return FALSE;
2003 }
2004
2005 static void
2006 gtk_notebook_draw_focus (GtkWidget *widget)
2007 {
2008   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2009
2010   if (GTK_WIDGET_DRAWABLE (widget) && notebook->show_tabs &&
2011       notebook->focus_tab)
2012     {
2013       GtkNotebookPage *page;
2014       GdkRectangle area;
2015       gint focus_width;
2016       
2017       gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2018
2019       page = notebook->focus_tab->data;
2020
2021       area.x = page->tab_label->allocation.x - focus_width;
2022       area.y = page->tab_label->allocation.y - focus_width;
2023       area.width = page->tab_label->allocation.width + 2 * focus_width;
2024       area.height = page->tab_label->allocation.height + 2 * focus_width;
2025
2026       gtk_notebook_draw_tab (GTK_NOTEBOOK (widget), page, &area);
2027     }
2028 }
2029
2030 static void
2031 gtk_notebook_style_set  (GtkWidget *widget,
2032                          GtkStyle  *previous)
2033 {
2034   GtkNotebook *notebook;
2035
2036   gboolean has_before_previous;
2037   gboolean has_before_next;
2038   gboolean has_after_previous;
2039   gboolean has_after_next;
2040
2041   notebook = GTK_NOTEBOOK (widget);
2042   
2043   gtk_widget_style_get (widget,
2044                         "has_backward_stepper", &has_before_previous,
2045                         "has_secondary_forward_stepper", &has_before_next,
2046                         "has_secondary_backward_stepper", &has_after_previous,
2047                         "has_forward_stepper", &has_after_next,
2048                         NULL);
2049   
2050   notebook->has_before_previous = has_before_previous;
2051   notebook->has_before_next = has_before_next;
2052   notebook->has_after_previous = has_after_previous;
2053   notebook->has_after_next = has_after_next;
2054   
2055   (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous);
2056 }
2057
2058 /* Private GtkContainer Methods :
2059  * 
2060  * gtk_notebook_set_child_arg
2061  * gtk_notebook_get_child_arg
2062  * gtk_notebook_add
2063  * gtk_notebook_remove
2064  * gtk_notebook_focus
2065  * gtk_notebook_set_focus_child
2066  * gtk_notebook_child_type
2067  * gtk_notebook_forall
2068  */
2069 static void
2070 gtk_notebook_set_child_property (GtkContainer    *container,
2071                                  GtkWidget       *child,
2072                                  guint            property_id,
2073                                  const GValue    *value,
2074                                  GParamSpec      *pspec)
2075 {
2076   gboolean expand;
2077   gboolean fill;
2078   GtkPackType pack_type;
2079
2080   /* not finding child's page is valid for menus or labels */
2081   if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
2082     return;
2083
2084   switch (property_id)
2085     {
2086     case CHILD_PROP_TAB_LABEL:
2087       /* a NULL pointer indicates a default_tab setting, otherwise
2088        * we need to set the associated label
2089        */
2090       gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
2091                                        g_value_get_string (value));
2092       break;
2093     case CHILD_PROP_MENU_LABEL:
2094       gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
2095                                         g_value_get_string (value));
2096       break;
2097     case CHILD_PROP_POSITION:
2098       gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
2099                                   g_value_get_int (value));
2100       break;
2101     case CHILD_PROP_TAB_EXPAND:
2102       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
2103                                             &expand, &fill, &pack_type);
2104       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
2105                                           g_value_get_boolean (value),
2106                                           fill, pack_type);
2107       break;
2108     case CHILD_PROP_TAB_FILL:
2109       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
2110                                             &expand, &fill, &pack_type);
2111       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
2112                                           expand,
2113                                           g_value_get_boolean (value),
2114                                           pack_type);
2115       break;
2116     case CHILD_PROP_TAB_PACK:
2117       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
2118                                             &expand, &fill, &pack_type);
2119       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
2120                                           expand, fill,
2121                                           g_value_get_enum (value));
2122       break;
2123     default:
2124       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2125       break;
2126     }
2127 }
2128
2129 static void
2130 gtk_notebook_get_child_property (GtkContainer    *container,
2131                                  GtkWidget       *child,
2132                                  guint            property_id,
2133                                  GValue          *value,
2134                                  GParamSpec      *pspec)
2135 {
2136   GList *list;
2137   GtkNotebook *notebook;
2138   GtkWidget *label;
2139   gboolean expand;
2140   gboolean fill;
2141   GtkPackType pack_type;
2142
2143   notebook = GTK_NOTEBOOK (container);
2144
2145   /* not finding child's page is valid for menus or labels */
2146   list = gtk_notebook_find_child (notebook, child, NULL);
2147   if (!list)
2148     {
2149       /* nothing to set on labels or menus */
2150       g_param_value_set_default (pspec, value);
2151       return;
2152     }
2153
2154   switch (property_id)
2155     {
2156     case CHILD_PROP_TAB_LABEL:
2157       label = gtk_notebook_get_tab_label (notebook, child);
2158
2159       if (label && GTK_IS_LABEL (label))
2160         g_value_set_string (value, GTK_LABEL (label)->label);
2161       else
2162         g_value_set_string (value, NULL);
2163       break;
2164     case CHILD_PROP_MENU_LABEL:
2165       label = gtk_notebook_get_menu_label (notebook, child);
2166
2167       if (label && GTK_IS_LABEL (label))
2168         g_value_set_string (value, GTK_LABEL (label)->label);
2169       else
2170         g_value_set_string (value, NULL);
2171       break;
2172     case CHILD_PROP_POSITION:
2173       g_value_set_int (value, g_list_position (notebook->children, list));
2174       break;
2175     case CHILD_PROP_TAB_EXPAND:
2176         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
2177                                               &expand, NULL, NULL);
2178         g_value_set_boolean (value, expand);
2179       break;
2180     case CHILD_PROP_TAB_FILL:
2181         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
2182                                               NULL, &fill, NULL);
2183         g_value_set_boolean (value, fill);
2184       break;
2185     case CHILD_PROP_TAB_PACK:
2186         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
2187                                               NULL, NULL, &pack_type);
2188         g_value_set_enum (value, pack_type);
2189       break;
2190     default:
2191       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
2192       break;
2193     }
2194 }
2195
2196 static void
2197 gtk_notebook_add (GtkContainer *container,
2198                   GtkWidget    *widget)
2199 {
2200   g_return_if_fail (GTK_IS_NOTEBOOK (container));
2201
2202   gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget, 
2203                                  NULL, NULL, -1);
2204 }
2205
2206 static void
2207 gtk_notebook_remove (GtkContainer *container,
2208                      GtkWidget    *widget)
2209 {
2210   GtkNotebook *notebook;
2211   GtkNotebookPage *page;
2212   GList *children;
2213
2214   g_return_if_fail (GTK_IS_NOTEBOOK (container));
2215   g_return_if_fail (widget != NULL);
2216
2217   notebook = GTK_NOTEBOOK (container);
2218
2219   children = notebook->children;
2220   while (children)
2221     {
2222       page = children->data;
2223       if (page->child == widget)
2224         {
2225           gtk_notebook_real_remove (notebook, children, FALSE);
2226           break;
2227         }
2228       children = children->next;
2229     }
2230 }
2231
2232 static gboolean
2233 focus_tabs_in (GtkNotebook *notebook)
2234 {
2235   if (notebook->show_tabs && notebook->cur_page)
2236     {
2237       gtk_widget_grab_focus (GTK_WIDGET (notebook));
2238
2239       gtk_notebook_switch_focus_tab (notebook,
2240                                      g_list_find (notebook->children,
2241                                                   notebook->cur_page));
2242
2243       return TRUE;
2244     }
2245   else
2246     return FALSE;
2247 }
2248
2249 static gboolean
2250 focus_tabs_move (GtkNotebook     *notebook,
2251                  GtkDirectionType direction,
2252                  gint             search_direction)
2253 {
2254   GList *new_page;
2255
2256   new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
2257                                        search_direction, TRUE);
2258   if (new_page)
2259     gtk_notebook_switch_focus_tab (notebook, new_page);
2260   else
2261     gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
2262   
2263   return TRUE;
2264 }
2265
2266 static gboolean
2267 focus_child_in (GtkNotebook     *notebook,
2268                 GtkDirectionType direction)
2269 {
2270   if (notebook->cur_page)
2271     return gtk_widget_child_focus (notebook->cur_page->child, direction);
2272   else
2273     return FALSE;
2274 }
2275
2276 /* Focus in the notebook can either be on the pages, or on
2277  * the tabs.
2278  */
2279 static gint
2280 gtk_notebook_focus (GtkWidget        *widget,
2281                     GtkDirectionType  direction)
2282 {
2283   GtkWidget *old_focus_child;
2284   GtkNotebook *notebook;
2285   GtkDirectionType effective_direction;
2286
2287   gboolean widget_is_focus;
2288   GtkContainer *container;
2289
2290   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2291
2292   container = GTK_CONTAINER (widget);
2293   notebook = GTK_NOTEBOOK (container);
2294
2295   if (notebook->focus_out)
2296     {
2297       notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
2298       return FALSE;
2299     }
2300
2301   widget_is_focus = gtk_widget_is_focus (widget);
2302   old_focus_child = container->focus_child; 
2303
2304   effective_direction = get_effective_direction (notebook, direction);
2305
2306   if (old_focus_child)          /* Focus on page child */
2307     {
2308       if (gtk_widget_child_focus (old_focus_child, direction))
2309         return TRUE;
2310       
2311       switch (effective_direction)
2312         {
2313         case GTK_DIR_TAB_BACKWARD:
2314         case GTK_DIR_UP:
2315           /* Focus onto the tabs */
2316           return focus_tabs_in (notebook);
2317         case GTK_DIR_DOWN:
2318         case GTK_DIR_TAB_FORWARD:
2319         case GTK_DIR_LEFT:
2320         case GTK_DIR_RIGHT:
2321           return FALSE;
2322         }
2323     }
2324   else if (widget_is_focus)     /* Focus was on tabs */
2325     {
2326       switch (effective_direction)
2327         {
2328         case GTK_DIR_TAB_BACKWARD:
2329         case GTK_DIR_UP:
2330           return FALSE;
2331         case GTK_DIR_TAB_FORWARD:
2332         case GTK_DIR_DOWN:
2333           /* We use TAB_FORWARD rather than direction so that we focus a more
2334            * predictable widget for the user; users may be using arrow focusing
2335            * in this situation even if they don't usually use arrow focusing.
2336            */
2337           return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
2338         case GTK_DIR_LEFT:
2339           return focus_tabs_move (notebook, direction, STEP_PREV);
2340         case GTK_DIR_RIGHT:
2341           return focus_tabs_move (notebook, direction, STEP_NEXT);
2342         }
2343     }
2344   else /* Focus was not on widget */
2345     {
2346       switch (effective_direction)
2347         {
2348         case GTK_DIR_TAB_FORWARD:
2349         case GTK_DIR_DOWN:
2350           if (focus_tabs_in (notebook))
2351             return TRUE;
2352           if (focus_child_in (notebook, direction))
2353             return TRUE;
2354           return FALSE;
2355         case GTK_DIR_TAB_BACKWARD:
2356         case GTK_DIR_UP:
2357           if (focus_child_in (notebook, direction))
2358             return TRUE;
2359           if (focus_tabs_in (notebook))
2360             return TRUE;
2361           return FALSE;
2362         case GTK_DIR_LEFT:
2363         case GTK_DIR_RIGHT:
2364           return focus_child_in (notebook, direction);
2365         }
2366     }
2367
2368   g_assert_not_reached ();
2369   return FALSE;
2370 }  
2371
2372 static void
2373 gtk_notebook_set_focus_child (GtkContainer *container,
2374                               GtkWidget    *child)
2375 {
2376   GtkNotebook *notebook = GTK_NOTEBOOK (container);
2377   GtkWidget *page_child;
2378   GtkWidget *toplevel;
2379
2380   /* If the old focus widget was within a page of the notebook,
2381    * (child may either be NULL or not in this case), record it
2382    * for future use if we switch to the page with a mnemonic.
2383    */
2384
2385   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
2386   if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
2387     {
2388       page_child = GTK_WINDOW (toplevel)->focus_widget; 
2389       while (page_child)
2390         {
2391           if (page_child->parent == GTK_WIDGET (container))
2392             {
2393               GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
2394               if (list != NULL) 
2395                 {
2396                   GtkNotebookPage *page = list->data;
2397               
2398                   if (page->last_focus_child)
2399                     g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
2400                   
2401                   page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
2402                   g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
2403               
2404                   break;
2405                 }
2406             }
2407
2408           page_child = page_child->parent;
2409         }
2410     }
2411   
2412   if (child)
2413     {
2414       g_return_if_fail (GTK_IS_WIDGET (child));
2415
2416       notebook->child_has_focus = TRUE;
2417       if (!notebook->focus_tab)
2418         {
2419           GList *children;
2420           GtkNotebookPage *page;
2421
2422           children = notebook->children;
2423           while (children)
2424             {
2425               page = children->data;
2426               if (page->child == child || page->tab_label == child)
2427                 gtk_notebook_switch_focus_tab (notebook, children);
2428               children = children->next;
2429             }
2430         }
2431     }
2432
2433   parent_class->set_focus_child (container, child);
2434 }
2435
2436 static void
2437 gtk_notebook_forall (GtkContainer *container,
2438                      gboolean      include_internals,
2439                      GtkCallback   callback,
2440                      gpointer      callback_data)
2441 {
2442   GtkNotebook *notebook;
2443   GList *children;
2444
2445   g_return_if_fail (GTK_IS_NOTEBOOK (container));
2446   g_return_if_fail (callback != NULL);
2447
2448   notebook = GTK_NOTEBOOK (container);
2449
2450   children = notebook->children;
2451   while (children)
2452     {
2453       GtkNotebookPage *page;
2454       
2455       page = children->data;
2456       children = children->next;
2457       (* callback) (page->child, callback_data);
2458       if (include_internals)
2459         {
2460           if (page->tab_label)
2461             (* callback) (page->tab_label, callback_data);
2462         }
2463     }
2464 }
2465
2466 static GType
2467 gtk_notebook_child_type (GtkContainer     *container)
2468 {
2469   return GTK_TYPE_WIDGET;
2470 }
2471
2472 /* Private GtkNotebook Functions:
2473  *
2474  * gtk_notebook_redraw_tabs
2475  * gtk_notebook_real_remove
2476  * gtk_notebook_update_labels
2477  * gtk_notebook_timer
2478  * gtk_notebook_page_compare
2479  * gtk_notebook_real_page_position
2480  * gtk_notebook_search_page
2481  */
2482 static void
2483 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
2484 {
2485   GtkWidget *widget;
2486   GtkNotebookPage *page;
2487   GdkRectangle redraw_rect;
2488   gint border;
2489   gint tab_pos = get_effective_tab_pos (notebook);
2490
2491   widget = GTK_WIDGET (notebook);
2492   border = GTK_CONTAINER (notebook)->border_width;
2493
2494   if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
2495     return;
2496
2497   page = notebook->first_tab->data;
2498
2499   redraw_rect.x = border;
2500   redraw_rect.y = border;
2501
2502   switch (tab_pos)
2503     {
2504     case GTK_POS_BOTTOM:
2505       redraw_rect.y = (widget->allocation.height - border -
2506                        page->allocation.height -
2507                        widget->style->ythickness);
2508       if (page != notebook->cur_page)
2509         redraw_rect.y -= widget->style->ythickness;
2510       /* fall through */
2511     case GTK_POS_TOP:
2512       redraw_rect.width = widget->allocation.width - 2 * border;
2513       redraw_rect.height = (page->allocation.height +
2514                             widget->style->ythickness);
2515       if (page != notebook->cur_page)
2516         redraw_rect.height += widget->style->ythickness;
2517       break;
2518     case GTK_POS_RIGHT:
2519       redraw_rect.x = (widget->allocation.width - border -
2520                        page->allocation.width -
2521                        widget->style->xthickness);
2522       if (page != notebook->cur_page)
2523         redraw_rect.x -= widget->style->xthickness;
2524       /* fall through */
2525     case GTK_POS_LEFT:
2526       redraw_rect.width = (page->allocation.width +
2527                            widget->style->xthickness);
2528       redraw_rect.height = widget->allocation.height - 2 * border;
2529       if (page != notebook->cur_page)
2530         redraw_rect.width += widget->style->xthickness;
2531       break;
2532     }
2533
2534   redraw_rect.x += widget->allocation.x;
2535   redraw_rect.y += widget->allocation.y;
2536
2537   gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
2538 }
2539
2540 static void
2541 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
2542 {
2543   if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
2544     {
2545       GdkRectangle rect;
2546       gint i;
2547       GtkNotebookArrow arrow[4];
2548
2549       arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2550       arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2551       arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2552       arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2553
2554       for (i = 0; i < 4; i++) 
2555         {
2556           if (arrow[i] == ARROW_NONE)
2557             continue;
2558           
2559           gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
2560           gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window, 
2561                                       &rect, FALSE);
2562         }
2563     }
2564 }
2565
2566 static gint
2567 gtk_notebook_timer (GtkNotebook *notebook)
2568 {
2569   gboolean retval = FALSE;
2570
2571   GDK_THREADS_ENTER ();
2572
2573   if (notebook->timer)
2574     {
2575       gtk_notebook_do_arrow (notebook, notebook->click_child);
2576
2577       if (notebook->need_timer) 
2578         {
2579           notebook->need_timer = FALSE;
2580           notebook->timer = g_timeout_add (NOTEBOOK_SCROLL_DELAY,
2581                                            (GSourceFunc) gtk_notebook_timer, 
2582                                            (gpointer) notebook);
2583         }
2584       else
2585         retval = TRUE;
2586     }
2587
2588   GDK_THREADS_LEAVE ();
2589
2590   return retval;
2591 }
2592
2593 static gint
2594 gtk_notebook_page_compare (gconstpointer a,
2595                            gconstpointer b)
2596 {
2597   return (((GtkNotebookPage *) a)->child != b);
2598 }
2599
2600 static GList*
2601 gtk_notebook_find_child (GtkNotebook *notebook,
2602                          GtkWidget   *child,
2603                          const gchar *function)
2604 {
2605   GList *list = g_list_find_custom (notebook->children, child,
2606                                     gtk_notebook_page_compare);
2607
2608 #ifndef G_DISABLE_CHECKS
2609   if (!list && function)
2610     g_warning ("%s: unable to find child %p in notebook %p",
2611                function, child, notebook);
2612 #endif
2613
2614   return list;
2615 }
2616
2617 static void
2618 gtk_notebook_remove_tab_label (GtkNotebook     *notebook,
2619                                GtkNotebookPage *page)
2620 {
2621   if (page->tab_label)
2622     {
2623       if (page->mnemonic_activate_signal)
2624         g_signal_handler_disconnect (page->tab_label,
2625                                      page->mnemonic_activate_signal);
2626       page->mnemonic_activate_signal = 0;
2627
2628       gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
2629       gtk_widget_unparent (page->tab_label);
2630     }
2631 }
2632
2633 static void
2634 gtk_notebook_real_remove (GtkNotebook *notebook,
2635                           GList       *list,
2636                           gboolean     destroying)
2637 {
2638   GtkNotebookPage *page;
2639   GList * next_list;
2640   gint need_resize = FALSE;
2641
2642   next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
2643   if (!next_list)
2644     next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
2645
2646   if (notebook->cur_page == list->data)
2647     { 
2648       notebook->cur_page = NULL;
2649       if (next_list && !destroying)
2650         gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
2651     }
2652
2653   if (list == notebook->first_tab)
2654     notebook->first_tab = next_list;
2655   if (list == notebook->focus_tab && !destroying)
2656     gtk_notebook_switch_focus_tab (notebook, next_list);
2657
2658   page = list->data;
2659   
2660   if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
2661     need_resize = TRUE;
2662
2663   gtk_widget_unparent (page->child);
2664
2665   gtk_notebook_remove_tab_label (notebook, page);
2666   
2667   if (notebook->menu)
2668     {
2669       gtk_container_remove (GTK_CONTAINER (notebook->menu), 
2670                             page->menu_label->parent);
2671       gtk_widget_queue_resize (notebook->menu);
2672     }
2673   if (!page->default_menu)
2674     g_object_unref (page->menu_label);
2675   
2676   notebook->children = g_list_remove_link (notebook->children, list);
2677   g_list_free (list);
2678
2679   if (page->last_focus_child)
2680     {
2681       g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
2682       page->last_focus_child = NULL;
2683     }
2684   
2685   g_free (page);
2686
2687   gtk_notebook_update_labels (notebook);
2688   if (need_resize)
2689     gtk_widget_queue_resize (GTK_WIDGET (notebook));
2690 }
2691
2692 static void
2693 gtk_notebook_update_labels (GtkNotebook *notebook)
2694 {
2695   GtkNotebookPage *page;
2696   GList *list;
2697   gchar string[32];
2698   gint page_num = 1;
2699
2700   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
2701        list;
2702        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
2703     {
2704       page = list->data;
2705       g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
2706       if (notebook->show_tabs)
2707         {
2708           if (page->default_tab)
2709             {
2710               if (!page->tab_label)
2711                 {
2712                   page->tab_label = gtk_label_new (string);
2713                   gtk_widget_set_parent (page->tab_label,
2714                                          GTK_WIDGET (notebook));
2715                 }
2716               else
2717                 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
2718             }
2719
2720           if (GTK_WIDGET_VISIBLE (page->child) &&
2721               !GTK_WIDGET_VISIBLE (page->tab_label))
2722             gtk_widget_show (page->tab_label);
2723           else if (!GTK_WIDGET_VISIBLE (page->child) &&
2724                    GTK_WIDGET_VISIBLE (page->tab_label))
2725             gtk_widget_hide (page->tab_label);
2726         }
2727       if (notebook->menu && page->default_menu)
2728         {
2729           if (page->tab_label && GTK_IS_LABEL (page->tab_label))
2730             gtk_label_set_text (GTK_LABEL (page->menu_label),
2731                            GTK_LABEL (page->tab_label)->label);
2732           else
2733             gtk_label_set_text (GTK_LABEL (page->menu_label), string);
2734         }
2735     }  
2736 }
2737
2738 static gint
2739 gtk_notebook_real_page_position (GtkNotebook *notebook,
2740                                  GList       *list)
2741 {
2742   GList *work;
2743   gint count_start;
2744
2745   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
2746   g_return_val_if_fail (list != NULL, -1);
2747
2748   for (work = notebook->children, count_start = 0;
2749        work && work != list; work = work->next)
2750     if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
2751       count_start++;
2752
2753   if (!work)
2754     return -1;
2755
2756   if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
2757     return count_start;
2758
2759   return (count_start + g_list_length (list) - 1);
2760 }
2761
2762 static GList *
2763 gtk_notebook_search_page (GtkNotebook *notebook,
2764                           GList       *list,
2765                           gint         direction,
2766                           gboolean     find_visible)
2767 {
2768   GtkNotebookPage *page = NULL;
2769   GList *old_list = NULL;
2770   gint flag = 0;
2771
2772   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
2773
2774   switch (direction)
2775     {
2776     case STEP_PREV:
2777       flag = GTK_PACK_END;
2778       break;
2779
2780     case STEP_NEXT:
2781       flag = GTK_PACK_START;
2782       break;
2783     }
2784
2785   if (list)
2786     page = list->data;
2787
2788   if (!page || page->pack == flag)
2789     {
2790       if (list)
2791         {
2792           old_list = list;
2793           list = list->next;
2794         }
2795       else
2796         list = notebook->children;
2797
2798       while (list)
2799         {
2800           page = list->data;
2801           if (page->pack == flag &&
2802               (!find_visible || GTK_WIDGET_VISIBLE (page->child)))
2803             return list;
2804           old_list = list;
2805           list = list->next;
2806         }
2807       list = old_list;
2808     }
2809   else
2810     {
2811       old_list = list;
2812       list = list->prev;
2813     }
2814   while (list)
2815     {
2816       page = list->data;
2817       if (page->pack != flag &&
2818           (!find_visible || GTK_WIDGET_VISIBLE (page->child)))
2819         return list;
2820       old_list = list;
2821       list = list->prev;
2822     }
2823   return NULL;
2824 }
2825
2826 /* Private GtkNotebook Drawing Functions:
2827  *
2828  * gtk_notebook_paint
2829  * gtk_notebook_draw_tab
2830  * gtk_notebook_draw_arrow
2831  */
2832 static void
2833 gtk_notebook_paint (GtkWidget    *widget,
2834                     GdkRectangle *area)
2835 {
2836   GtkNotebook *notebook;
2837   GtkNotebookPage *page;
2838   GList *children;
2839   gboolean showarrow;
2840   gint width, height;
2841   gint x, y;
2842   gint border_width = GTK_CONTAINER (widget)->border_width;
2843   gint gap_x = 0, gap_width = 0, step = STEP_PREV;
2844   gboolean is_rtl;
2845   gint tab_pos;
2846    
2847   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
2848   g_return_if_fail (area != NULL);
2849
2850   if (!GTK_WIDGET_DRAWABLE (widget))
2851     return;
2852
2853   notebook = GTK_NOTEBOOK (widget);
2854   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2855   tab_pos = get_effective_tab_pos (notebook);
2856
2857   if ((!notebook->show_tabs && !notebook->show_border) ||
2858       !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
2859     return;
2860
2861   x = widget->allocation.x + border_width;
2862   y = widget->allocation.y + border_width;
2863   width = widget->allocation.width - border_width * 2;
2864   height = widget->allocation.height - border_width * 2;
2865
2866   if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
2867     {
2868       gtk_paint_box (widget->style, widget->window,
2869                      GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2870                      area, widget, "notebook",
2871                      x, y, width, height);
2872       return;
2873     }
2874
2875
2876   if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
2877     {
2878       page = notebook->first_tab->data;
2879
2880       switch (tab_pos)
2881         {
2882         case GTK_POS_TOP:
2883           y += page->allocation.height + widget->style->ythickness;
2884         case GTK_POS_BOTTOM:
2885           height -= page->allocation.height + widget->style->ythickness;
2886           break;
2887         case GTK_POS_LEFT:
2888           x += page->allocation.width + widget->style->xthickness;
2889         case GTK_POS_RIGHT:
2890           width -= page->allocation.width + widget->style->xthickness;
2891           break;
2892         }
2893       gtk_paint_box (widget->style, widget->window,
2894                      GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2895                      area, widget, "notebook",
2896                      x, y, width, height);
2897     }
2898   else
2899     {
2900       switch (tab_pos)
2901         {
2902         case GTK_POS_TOP:
2903           y += notebook->cur_page->allocation.height;
2904         case GTK_POS_BOTTOM:
2905           height -= notebook->cur_page->allocation.height;
2906           break;
2907         case GTK_POS_LEFT:
2908           x += notebook->cur_page->allocation.width;
2909         case GTK_POS_RIGHT:
2910           width -= notebook->cur_page->allocation.width;
2911           break;
2912         }
2913
2914       switch (tab_pos)
2915         {
2916         case GTK_POS_TOP:
2917         case GTK_POS_BOTTOM:
2918           gap_x = (notebook->cur_page->allocation.x - widget->allocation.x - border_width);
2919           gap_width = notebook->cur_page->allocation.width;
2920           step = is_rtl ? STEP_NEXT : STEP_PREV;
2921           break;
2922         case GTK_POS_LEFT:
2923         case GTK_POS_RIGHT:
2924           gap_x = (notebook->cur_page->allocation.y - widget->allocation.y - border_width);
2925           gap_width = notebook->cur_page->allocation.height;
2926           step = STEP_PREV;
2927           break;
2928         }
2929       gtk_paint_box_gap (widget->style, widget->window,
2930                          GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2931                          area, widget, "notebook",
2932                          x, y, width, height,
2933                          tab_pos, gap_x, gap_width);
2934     }
2935
2936   showarrow = FALSE;
2937   children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
2938   while (children)
2939     {
2940       page = children->data;
2941       children = gtk_notebook_search_page (notebook, children,
2942                                            step, TRUE);
2943       if (!GTK_WIDGET_VISIBLE (page->child))
2944         continue;
2945       if (!GTK_WIDGET_MAPPED (page->tab_label))
2946         showarrow = TRUE;
2947       else if (page != notebook->cur_page)
2948         gtk_notebook_draw_tab (notebook, page, area);
2949     }
2950
2951   if (showarrow && notebook->scrollable) 
2952     {
2953       if (notebook->has_before_previous)
2954         gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
2955       if (notebook->has_before_next)
2956         gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
2957       if (notebook->has_after_previous)
2958         gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
2959       if (notebook->has_after_next)
2960         gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
2961     }
2962   gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
2963 }
2964
2965 static void
2966 gtk_notebook_draw_tab (GtkNotebook     *notebook,
2967                        GtkNotebookPage *page,
2968                        GdkRectangle    *area)
2969 {
2970   GdkRectangle child_area;
2971   GdkRectangle page_area;
2972   GtkStateType state_type;
2973   GtkPositionType gap_side;
2974   gint tab_pos = get_effective_tab_pos (notebook);
2975   
2976   g_return_if_fail (notebook != NULL);
2977   g_return_if_fail (page != NULL);
2978   g_return_if_fail (area != NULL);
2979
2980   if (!GTK_WIDGET_MAPPED (page->tab_label) ||
2981       (page->allocation.width == 0) || (page->allocation.height == 0))
2982     return;
2983
2984   page_area.x = page->allocation.x;
2985   page_area.y = page->allocation.y;
2986   page_area.width = page->allocation.width;
2987   page_area.height = page->allocation.height;
2988
2989   if (gdk_rectangle_intersect (&page_area, area, &child_area))
2990     {
2991       GtkWidget *widget;
2992
2993       widget = GTK_WIDGET (notebook);
2994       gap_side = 0;
2995       switch (tab_pos)
2996         {
2997         case GTK_POS_TOP:
2998           gap_side = GTK_POS_BOTTOM;
2999           break;
3000         case GTK_POS_BOTTOM:
3001           gap_side = GTK_POS_TOP;
3002           break;
3003         case GTK_POS_LEFT:
3004           gap_side = GTK_POS_RIGHT;
3005           break;
3006         case GTK_POS_RIGHT:
3007           gap_side = GTK_POS_LEFT;
3008           break;
3009         }
3010       
3011       if (notebook->cur_page == page)
3012         state_type = GTK_STATE_NORMAL;
3013       else 
3014         state_type = GTK_STATE_ACTIVE;
3015       gtk_paint_extension(widget->style, widget->window,
3016                           state_type, GTK_SHADOW_OUT,
3017                           area, widget, "tab",
3018                           page_area.x, page_area.y,
3019                           page_area.width, page_area.height,
3020                           gap_side);
3021       if ((GTK_WIDGET_HAS_FOCUS (widget)) &&
3022           notebook->focus_tab && (notebook->focus_tab->data == page))
3023         {
3024           gint focus_width;
3025           
3026           gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3027           
3028           gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
3029                            area, widget, "tab",
3030                            page->tab_label->allocation.x - focus_width,
3031                            page->tab_label->allocation.y - focus_width,
3032                            page->tab_label->allocation.width + 2 * focus_width,
3033                            page->tab_label->allocation.height + 2 * focus_width);
3034         }
3035       if (gtk_widget_intersect (page->tab_label, area, &child_area) &&
3036           GTK_WIDGET_DRAWABLE (page->tab_label))
3037         {
3038           GdkEvent *expose_event = gdk_event_new (GDK_EXPOSE);
3039
3040           /* This is a lame hack since all this code needs rewriting anyhow */
3041           
3042           expose_event->expose.window = g_object_ref (page->tab_label->window);
3043           expose_event->expose.area = child_area;
3044           expose_event->expose.region = gdk_region_rectangle (&child_area);
3045           expose_event->expose.send_event = TRUE;
3046           expose_event->expose.count = 0;
3047
3048           gtk_container_propagate_expose (GTK_CONTAINER (notebook), page->tab_label, (GdkEventExpose *)expose_event);
3049
3050           gdk_event_free (expose_event);
3051         }
3052     }
3053 }
3054
3055 static void
3056 gtk_notebook_draw_arrow (GtkNotebook      *notebook,
3057                          GtkNotebookArrow  nbarrow)
3058 {
3059   GtkStateType state_type;
3060   GtkShadowType shadow_type;
3061   GtkWidget *widget;
3062   GdkRectangle arrow_rect;
3063   GtkArrowType arrow;
3064   gboolean is_rtl, left;
3065
3066   gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
3067
3068   widget = GTK_WIDGET (notebook);
3069
3070   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3071   left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
3072          (!ARROW_IS_LEFT (nbarrow) && is_rtl); 
3073
3074   if (GTK_WIDGET_DRAWABLE (notebook))
3075     {
3076       if (notebook->in_child == nbarrow)
3077         {
3078           if (notebook->click_child == nbarrow)
3079             state_type = GTK_STATE_ACTIVE;
3080           else
3081             state_type = GTK_STATE_PRELIGHT;
3082         }
3083       else
3084         state_type = GTK_WIDGET_STATE (widget);
3085
3086       if (notebook->click_child == nbarrow)
3087         shadow_type = GTK_SHADOW_IN;
3088       else
3089         shadow_type = GTK_SHADOW_OUT;
3090
3091       if (notebook->focus_tab &&
3092           !gtk_notebook_search_page (notebook, notebook->focus_tab,
3093                                       left? STEP_PREV : STEP_NEXT, TRUE))
3094         {
3095           shadow_type = GTK_SHADOW_ETCHED_IN;
3096           state_type = GTK_STATE_INSENSITIVE;
3097         }
3098       
3099       if (notebook->tab_pos == GTK_POS_LEFT ||
3100           notebook->tab_pos == GTK_POS_RIGHT)
3101         arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
3102       else
3103         arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
3104       
3105       gtk_paint_arrow (widget->style, widget->window, state_type, 
3106                        shadow_type, NULL, widget, "notebook",
3107                        arrow, TRUE, arrow_rect.x, arrow_rect.y, 
3108                        ARROW_SIZE, ARROW_SIZE);
3109     }
3110 }
3111
3112 /* Private GtkNotebook Size Allocate Functions:
3113  *
3114  * gtk_notebook_pages_allocate
3115  * gtk_notebook_page_allocate
3116  * gtk_notebook_calc_tabs
3117  */
3118 static void
3119 gtk_notebook_pages_allocate (GtkNotebook   *notebook)
3120 {
3121   GtkWidget    *widget = GTK_WIDGET (notebook);
3122   GtkContainer *container = GTK_CONTAINER (notebook);
3123   GtkNotebookPage *page = NULL;
3124   GtkAllocation *allocation = &widget->allocation;
3125   GtkAllocation child_allocation;
3126   GList *children = NULL;
3127   GList *last_child = NULL;
3128   gboolean showarrow = FALSE;
3129   gint tab_space = 0; 
3130   gint delta; 
3131   gint i;
3132   gint n = 1;
3133   gint old_fill = 0;
3134   gint new_fill = 0;
3135   gint tab_pos = get_effective_tab_pos (notebook);
3136   gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL &&
3137                      (tab_pos == GTK_POS_TOP || tab_pos == GTK_POS_BOTTOM));
3138   gint memo_x;
3139
3140   if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
3141     return;
3142
3143   child_allocation.x = widget->allocation.x + container->border_width;
3144   child_allocation.y = widget->allocation.y + container->border_width;
3145
3146   switch (tab_pos)
3147     {
3148     case GTK_POS_BOTTOM:
3149       child_allocation.y = (widget->allocation.y +
3150                             allocation->height -
3151                             notebook->cur_page->requisition.height -
3152                             container->border_width);
3153       /* fall through */
3154     case GTK_POS_TOP:
3155       child_allocation.height = notebook->cur_page->requisition.height;
3156       break;
3157       
3158     case GTK_POS_RIGHT:
3159       child_allocation.x = (widget->allocation.x +
3160                             allocation->width -
3161                             notebook->cur_page->requisition.width -
3162                             container->border_width);
3163       /* fall through */
3164     case GTK_POS_LEFT:
3165       child_allocation.width = notebook->cur_page->requisition.width;
3166       break;
3167     }
3168   
3169   if (notebook->scrollable) 
3170     {
3171       GList *focus_tab;
3172       
3173       children = notebook->children;
3174       
3175       if (notebook->focus_tab)
3176         focus_tab = notebook->focus_tab;
3177       else if (notebook->first_tab)
3178         focus_tab = notebook->first_tab;
3179       else
3180         focus_tab = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
3181
3182       switch (tab_pos)
3183         {
3184         case GTK_POS_TOP:
3185         case GTK_POS_BOTTOM:
3186           while (children)
3187             {
3188               page = children->data;
3189               children = children->next;
3190
3191               if (GTK_WIDGET_VISIBLE (page->child))
3192                 tab_space += page->requisition.width;
3193             }
3194           if (tab_space >
3195               allocation->width - 2 * container->border_width - TAB_OVERLAP) 
3196             {
3197               showarrow = TRUE;
3198               page = focus_tab->data; 
3199
3200               tab_space = allocation->width - TAB_OVERLAP -
3201                 page->requisition.width - 2 * container->border_width;
3202               if (notebook->has_after_previous)
3203                 tab_space -= ARROW_SPACING + ARROW_SIZE;
3204               if (notebook->has_after_next)
3205                 tab_space -= ARROW_SPACING + ARROW_SIZE;
3206               if (notebook->has_before_previous)
3207                 {
3208                   tab_space -= ARROW_SPACING + ARROW_SIZE;
3209                   child_allocation.x += ARROW_SPACING + ARROW_SIZE;
3210                 }
3211               if (notebook->has_before_next)
3212                 {
3213                   tab_space -= ARROW_SPACING + ARROW_SIZE;
3214                   child_allocation.x += ARROW_SPACING + ARROW_SIZE;
3215                 }
3216             }
3217           break;
3218         case GTK_POS_LEFT:
3219         case GTK_POS_RIGHT:
3220           while (children)
3221             {
3222               page = children->data;
3223               children = children->next;
3224
3225               if (GTK_WIDGET_VISIBLE (page->child))
3226                 tab_space += page->requisition.height;
3227             }
3228           if (tab_space >
3229               (allocation->height - 2 * container->border_width - TAB_OVERLAP))
3230             {
3231               showarrow = TRUE;
3232               page = focus_tab->data; 
3233               tab_space = allocation->height
3234                 - TAB_OVERLAP - 2 * container->border_width
3235                 - page->requisition.height;
3236               if (notebook->has_after_previous || notebook->has_after_next)
3237                 tab_space -= ARROW_SPACING + ARROW_SIZE;
3238               if (notebook->has_before_previous || notebook->has_before_next)
3239                 {
3240                   tab_space -= ARROW_SPACING + ARROW_SIZE;
3241                   child_allocation.y += ARROW_SPACING + ARROW_SIZE;
3242                 }
3243             }
3244           break;
3245         }
3246       if (showarrow) /* first_tab <- focus_tab */
3247         { 
3248           if (tab_space <= 0)
3249             {
3250               notebook->first_tab = focus_tab;
3251               last_child = gtk_notebook_search_page (notebook, focus_tab,
3252                                                      STEP_NEXT, TRUE);
3253             }
3254           else
3255             {
3256               children = NULL;
3257               if (notebook->first_tab && notebook->first_tab != focus_tab)
3258                 {
3259                   /* Is first_tab really predecessor of focus_tab  ? */
3260                   page = notebook->first_tab->data;
3261                   if (GTK_WIDGET_VISIBLE (page->child))
3262                     for (children = focus_tab;
3263                          children && children != notebook->first_tab;
3264                          children = gtk_notebook_search_page (notebook,
3265                                                               children,
3266                                                               STEP_PREV,
3267                                                               TRUE));
3268                 }
3269               if (!children)
3270                 notebook->first_tab = focus_tab;
3271               else
3272                 gtk_notebook_calc_tabs (notebook,
3273                                         gtk_notebook_search_page (notebook,
3274                                                                   focus_tab,
3275                                                                   STEP_PREV,
3276                                                                   TRUE), 
3277                                         &(notebook->first_tab), &tab_space,
3278                                         STEP_PREV);
3279
3280               if (tab_space <= 0)
3281                 {
3282                   notebook->first_tab =
3283                     gtk_notebook_search_page (notebook, notebook->first_tab,
3284                                               STEP_NEXT, TRUE);
3285                   if (!notebook->first_tab)
3286                     notebook->first_tab = focus_tab;
3287                   last_child = gtk_notebook_search_page (notebook, focus_tab,
3288                                                          STEP_NEXT, TRUE); 
3289                 }
3290               else /* focus_tab -> end */   
3291                 {
3292                   if (!notebook->first_tab)
3293                     notebook->first_tab = gtk_notebook_search_page (notebook,
3294                                                                     NULL,
3295                                                                     STEP_NEXT,
3296                                                                     TRUE);
3297                   children = NULL;
3298                   gtk_notebook_calc_tabs (notebook,
3299                                           gtk_notebook_search_page (notebook,
3300                                                                     focus_tab,
3301                                                                     STEP_NEXT,
3302                                                                     TRUE),
3303                                           &children, &tab_space, STEP_NEXT);
3304
3305                   if (tab_space <= 0) 
3306                     last_child = children;
3307                   else /* start <- first_tab */
3308                     {
3309                       last_child = NULL;
3310                       children = NULL;
3311                       gtk_notebook_calc_tabs
3312                         (notebook,
3313                          gtk_notebook_search_page (notebook,
3314                                                    notebook->first_tab,
3315                                                    STEP_PREV,
3316                                                    TRUE),
3317                          &children, &tab_space, STEP_PREV);
3318                       notebook->first_tab = gtk_notebook_search_page(notebook,
3319                                                                      children,
3320                                                                      STEP_NEXT,
3321                                                                      TRUE);
3322                     }
3323                 }
3324             }
3325
3326           if (tab_space < 0) 
3327             {
3328               tab_space = -tab_space;
3329               n = 0;
3330               for (children = notebook->first_tab;
3331                    children && children != last_child;
3332                    children = gtk_notebook_search_page (notebook, children,
3333                                                         STEP_NEXT, TRUE))
3334                 n++;
3335             }
3336           else 
3337             tab_space = 0;
3338
3339           /*unmap all non-visible tabs*/
3340           for (children = gtk_notebook_search_page (notebook, NULL,
3341                                                     STEP_NEXT, TRUE);
3342                children && children != notebook->first_tab;
3343                children = gtk_notebook_search_page (notebook, children,
3344                                                     STEP_NEXT, TRUE))
3345             {
3346               page = children->data;
3347               if (page->tab_label)
3348                 gtk_widget_set_child_visible (page->tab_label, FALSE);
3349             }
3350           for (children = last_child; children;
3351                children = gtk_notebook_search_page (notebook, children,
3352                                                     STEP_NEXT, TRUE))
3353             {
3354               page = children->data;
3355               if (page->tab_label)
3356                 gtk_widget_set_child_visible (page->tab_label, FALSE);
3357             }
3358         }
3359       else /* !showarrow */
3360         {
3361           notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
3362                                                           STEP_NEXT, TRUE);
3363           tab_space = 0;
3364         }
3365     }
3366
3367   if (!showarrow)
3368     {
3369       gint c = 0;
3370
3371       n = 0;
3372       children = notebook->children;
3373       switch (tab_pos)
3374         {
3375         case GTK_POS_TOP:
3376         case GTK_POS_BOTTOM:
3377           while (children)
3378             {
3379               page = children->data;
3380               children = children->next;
3381
3382               if (GTK_WIDGET_VISIBLE (page->child))
3383                 {
3384                   c++;
3385                   tab_space += page->requisition.width;
3386                   if (page->expand)
3387                     n++;
3388                 }
3389             }
3390           tab_space -= allocation->width;
3391           break;
3392         case GTK_POS_LEFT:
3393         case GTK_POS_RIGHT:
3394           while (children)
3395             {
3396               page = children->data;
3397               children = children->next;
3398
3399               if (GTK_WIDGET_VISIBLE (page->child))
3400                 {
3401                   c++;
3402                   tab_space += page->requisition.height;
3403                   if (page->expand)
3404                     n++;
3405                 }
3406             }
3407           tab_space -= allocation->height;
3408         }
3409       tab_space += 2 * container->border_width + TAB_OVERLAP;
3410       tab_space *= -1;
3411       notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
3412                                                       STEP_NEXT, TRUE);
3413       if (notebook->homogeneous && n)
3414         n = c;
3415     }
3416   
3417   children = notebook->first_tab;
3418   i = 1; 
3419
3420   memo_x = child_allocation.x;
3421   if (notebook->children && is_rtl)
3422      {
3423       child_allocation.x = (allocation->x + allocation->width -
3424                                 container->border_width); 
3425       if (showarrow) 
3426         {
3427           if (notebook->has_after_previous)
3428             child_allocation.x -= ARROW_SPACING + ARROW_SIZE;
3429           if (notebook->has_after_next)
3430             child_allocation.x -= ARROW_SPACING + ARROW_SIZE;
3431         }
3432      }
3433
3434   while (children)
3435     {
3436       if (children == last_child)
3437         {
3438           /* FIXME double check */
3439           goto done;
3440         }
3441
3442       page = children->data;
3443       if (!showarrow && page->pack != GTK_PACK_START) 
3444         break;
3445       children = gtk_notebook_search_page (notebook, children, STEP_NEXT,TRUE);
3446       
3447       delta = 0;
3448       if (n && (showarrow || page->expand || notebook->homogeneous))
3449         {
3450           new_fill = (tab_space * i++) / n;
3451           delta = new_fill - old_fill;
3452           old_fill = new_fill;
3453         }
3454       
3455       switch (tab_pos)
3456         {
3457         case GTK_POS_TOP:
3458         case GTK_POS_BOTTOM:
3459           child_allocation.width = (page->requisition.width +
3460                                     TAB_OVERLAP + delta);
3461           if (is_rtl)
3462               child_allocation.x -= child_allocation.width;
3463           break;
3464         case GTK_POS_LEFT:
3465         case GTK_POS_RIGHT:
3466           child_allocation.height = (page->requisition.height +
3467                                      TAB_OVERLAP + delta);
3468           break;
3469         }
3470
3471       gtk_notebook_page_allocate (notebook, page, &child_allocation);
3472
3473       switch (tab_pos)
3474         {
3475         case GTK_POS_TOP:
3476         case GTK_POS_BOTTOM:
3477           if (!is_rtl)
3478              child_allocation.x += child_allocation.width - TAB_OVERLAP;
3479           else
3480              child_allocation.x += TAB_OVERLAP;
3481           break;
3482         case GTK_POS_LEFT:
3483         case GTK_POS_RIGHT:
3484           child_allocation.y += child_allocation.height - TAB_OVERLAP;
3485           break;
3486         }
3487
3488       if (page->tab_label)
3489         gtk_widget_set_child_visible (page->tab_label, TRUE);
3490     }
3491
3492   if (children)
3493     {
3494       children = notebook->children;
3495
3496       switch (tab_pos)
3497         {
3498         case GTK_POS_TOP:
3499         case GTK_POS_BOTTOM:
3500           if (!is_rtl)
3501              child_allocation.x = (allocation->x + allocation->width -
3502                                   container->border_width);
3503           else
3504              child_allocation.x = memo_x; 
3505           break;
3506         case GTK_POS_LEFT:
3507         case GTK_POS_RIGHT:
3508           child_allocation.y = (allocation->y + allocation->height -
3509                                 container->border_width);
3510           break;
3511         }
3512
3513       while (children != last_child)
3514         {
3515           page = children->data;
3516           children = children->next;
3517
3518           if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
3519              continue;
3520
3521           delta = 0;
3522           if (n && (page->expand || notebook->homogeneous))
3523             {
3524               new_fill = (tab_space * i++) / n;
3525               delta = new_fill - old_fill;
3526               old_fill = new_fill;
3527             }
3528
3529           switch (tab_pos)
3530             {
3531             case GTK_POS_TOP:
3532             case GTK_POS_BOTTOM:
3533               child_allocation.width = (page->requisition.width +
3534                                         TAB_OVERLAP + delta);
3535               if (!is_rtl)
3536                  child_allocation.x -= child_allocation.width;
3537               break;
3538             case GTK_POS_LEFT:
3539             case GTK_POS_RIGHT:
3540               child_allocation.height = (page->requisition.height +
3541                                          TAB_OVERLAP + delta);
3542               child_allocation.y -= child_allocation.height;
3543               break;
3544             }
3545
3546           gtk_notebook_page_allocate (notebook, page, &child_allocation);
3547
3548           switch (tab_pos)
3549             {
3550             case GTK_POS_TOP:
3551             case GTK_POS_BOTTOM:
3552               if (!is_rtl)
3553                  child_allocation.x += TAB_OVERLAP;
3554               else
3555                  child_allocation.x += child_allocation.width - TAB_OVERLAP;
3556               break;
3557             case GTK_POS_LEFT:
3558             case GTK_POS_RIGHT:
3559               child_allocation.y += TAB_OVERLAP;
3560               break;
3561             }
3562
3563           if (page->tab_label)
3564             gtk_widget_set_child_visible (page->tab_label, TRUE);
3565         }
3566     }
3567
3568  done:
3569   gtk_notebook_redraw_tabs (notebook);  
3570 }
3571
3572 static void
3573 gtk_notebook_page_allocate (GtkNotebook     *notebook,
3574                             GtkNotebookPage *page,
3575                             GtkAllocation   *allocation)
3576 {
3577   GtkWidget *widget = GTK_WIDGET (notebook);
3578   GtkAllocation child_allocation;
3579   GtkRequisition tab_requisition;
3580   gint xthickness;
3581   gint ythickness;
3582   gint padding;
3583   gint focus_width;
3584   gint tab_pos = get_effective_tab_pos (notebook);
3585
3586   gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
3587   
3588   xthickness = widget->style->xthickness;
3589   ythickness = widget->style->ythickness;
3590
3591   /* If the size of the notebook tabs change, we need to queue
3592    * a redraw on the tab area
3593    */
3594   if ((allocation->width != page->allocation.width) ||
3595       (allocation->height != page->allocation.height))
3596     {
3597       gint x, y, width, height, border_width;
3598
3599       border_width = GTK_CONTAINER (notebook)->border_width;
3600
3601       switch (tab_pos)
3602        {
3603        case GTK_POS_TOP:
3604          width = widget->allocation.width;
3605          height = MAX (page->allocation.height, allocation->height) + ythickness;
3606          x = 0;                              
3607          y = border_width;
3608          break;
3609
3610        case GTK_POS_BOTTOM:
3611          width = widget->allocation.width + xthickness;
3612          height = MAX (page->allocation.height, allocation->height) + ythickness;
3613          x = 0;                              
3614          y = widget->allocation.height - height - border_width;
3615          break;
3616
3617        case GTK_POS_LEFT:
3618          width = MAX (page->allocation.width, allocation->width) + xthickness;
3619          height = widget->allocation.height;
3620          x = border_width;
3621          y = 0;
3622          break;
3623
3624        case GTK_POS_RIGHT:
3625        default:                /* quiet gcc */
3626          width = MAX (page->allocation.width, allocation->width) + xthickness;
3627          height = widget->allocation.height;
3628          x = widget->allocation.width - width - border_width;
3629          y = 0;
3630          break;
3631        }
3632
3633       gtk_widget_queue_draw_area (widget, x, y, width, height);
3634     }
3635
3636   page->allocation = *allocation;
3637   gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
3638
3639   if (notebook->cur_page != page)
3640     {
3641       switch (tab_pos)
3642         {
3643         case GTK_POS_TOP:
3644           page->allocation.y += ythickness;
3645         case GTK_POS_BOTTOM:
3646           if (page->allocation.height > ythickness)
3647             page->allocation.height -= ythickness;
3648           break;
3649         case GTK_POS_LEFT:
3650           page->allocation.x += xthickness;
3651         case GTK_POS_RIGHT:
3652           if (page->allocation.width > xthickness)
3653             page->allocation.width -= xthickness;
3654           break;
3655         }
3656     }
3657
3658   switch (tab_pos)
3659     {
3660     case GTK_POS_TOP:
3661     case GTK_POS_BOTTOM:
3662       padding = TAB_CURVATURE + focus_width + notebook->tab_hborder;
3663       if (page->fill)
3664         {
3665           child_allocation.x = (xthickness + focus_width +
3666                                 notebook->tab_hborder);
3667           child_allocation.width = MAX (1, (page->allocation.width -
3668                                             2 * child_allocation.x));
3669           child_allocation.x += page->allocation.x;
3670         }
3671       else
3672         {
3673           child_allocation.x = (page->allocation.x +
3674                                 (page->allocation.width -
3675                                  tab_requisition.width) / 2);
3676           child_allocation.width = tab_requisition.width;
3677         }
3678       child_allocation.y = (notebook->tab_vborder + focus_width +
3679                             page->allocation.y);
3680       if (tab_pos == GTK_POS_TOP)
3681         child_allocation.y += ythickness;
3682       child_allocation.height = MAX (1, (((gint) page->allocation.height) - ythickness -
3683                                          2 * (notebook->tab_vborder + focus_width)));
3684       break;
3685     case GTK_POS_LEFT:
3686     case GTK_POS_RIGHT:
3687       padding = TAB_CURVATURE + focus_width + notebook->tab_vborder;
3688       if (page->fill)
3689         {
3690           child_allocation.y = ythickness + padding;
3691           child_allocation.height = MAX (1, (page->allocation.height -
3692                                              2 * child_allocation.y));
3693           child_allocation.y += page->allocation.y;
3694         }
3695       else
3696         {
3697           child_allocation.y = (page->allocation.y + (page->allocation.height -
3698                                                       tab_requisition.height) / 2);
3699           child_allocation.height = tab_requisition.height;
3700         }
3701       child_allocation.x = page->allocation.x + notebook->tab_hborder + focus_width;
3702       if (tab_pos == GTK_POS_LEFT)
3703         child_allocation.x += xthickness;
3704       child_allocation.width = MAX (1, (((gint) page->allocation.width) - xthickness -
3705                                         2 * (notebook->tab_hborder + focus_width)));
3706       break;
3707     }
3708
3709   if (page->tab_label)
3710     gtk_widget_size_allocate (page->tab_label, &child_allocation);
3711 }
3712
3713 static void 
3714 gtk_notebook_calc_tabs (GtkNotebook  *notebook, 
3715                         GList        *start, 
3716                         GList       **end,
3717                         gint         *tab_space,
3718                         guint         direction)
3719 {
3720   GtkNotebookPage *page = NULL;
3721   GList *children;
3722   GList *last_list = NULL;
3723   gboolean pack;
3724   gint tab_pos = get_effective_tab_pos (notebook);
3725
3726   if (!start)
3727     return;
3728
3729   children = start;
3730   pack = GTK_NOTEBOOK_PAGE (start)->pack;
3731   if (pack == GTK_PACK_END)
3732     direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
3733
3734   while (1)
3735     {
3736       switch (tab_pos)
3737         {
3738         case GTK_POS_TOP:
3739         case GTK_POS_BOTTOM:
3740           while (children)
3741             {
3742               page = children->data;
3743               if (GTK_WIDGET_VISIBLE (page->child))
3744                 {
3745                   if (page->pack == pack)
3746                     {
3747                       *tab_space -= page->requisition.width;
3748                       if (*tab_space < 0 || children == *end)
3749                         {
3750                           if (*tab_space < 0) 
3751                             {
3752                               *tab_space = - (*tab_space +
3753                                               page->requisition.width);
3754                               *end = children;
3755                             }
3756                           return;
3757                         }
3758                     }
3759                   last_list = children;
3760                 }
3761               if (direction == STEP_NEXT)
3762                 children = children->next;
3763               else
3764                 children = children->prev;
3765             }
3766           break;
3767         case GTK_POS_LEFT:
3768         case GTK_POS_RIGHT:
3769           while (children)
3770             {
3771               page = children->data;
3772               if (GTK_WIDGET_VISIBLE (page->child))
3773                 {
3774                   if (page->pack == pack)
3775                     {
3776                       *tab_space -= page->requisition.height;
3777                       if (*tab_space < 0 || children == *end)
3778                         {
3779                           if (*tab_space < 0)
3780                             {
3781                               *tab_space = - (*tab_space +
3782                                               page->requisition.height);
3783                               *end = children;
3784                             }
3785                           return;
3786                         }
3787                     }
3788                   last_list = children;
3789                 }
3790               if (direction == STEP_NEXT)
3791                 children = children->next;
3792               else
3793                 children = children->prev;
3794             }
3795           break;
3796         }
3797       if (direction == STEP_PREV)
3798         return;
3799       pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
3800       direction = STEP_PREV;
3801       children = last_list;
3802     }
3803 }
3804
3805 static void
3806 gtk_notebook_update_tab_states (GtkNotebook *notebook)
3807 {
3808   GList *list;
3809
3810   for (list = notebook->children; list != NULL; list = list->next)
3811     {
3812       GtkNotebookPage *page = list->data;
3813       
3814       if (page->tab_label)
3815         {
3816           if (page == notebook->cur_page)
3817             gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
3818           else
3819             gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
3820         }
3821     }
3822 }
3823
3824 /* Private GtkNotebook Page Switch Methods:
3825  *
3826  * gtk_notebook_real_switch_page
3827  */
3828 static void
3829 gtk_notebook_real_switch_page (GtkNotebook     *notebook,
3830                                GtkNotebookPage *page,
3831                                guint            page_num)
3832 {
3833   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3834   g_return_if_fail (page != NULL);
3835
3836   if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
3837     return;
3838
3839   if (notebook->cur_page)
3840     gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
3841   
3842   notebook->cur_page = page;
3843
3844   if (!notebook->focus_tab ||
3845       notebook->focus_tab->data != (gpointer) notebook->cur_page)
3846     notebook->focus_tab = 
3847       g_list_find (notebook->children, notebook->cur_page);
3848
3849   gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
3850
3851   /* If the focus was on the previous page, move it to the first
3852    * element on the new page, if possible, or if not, to the
3853    * notebook itself.
3854    */
3855   if (notebook->child_has_focus)
3856     {
3857       if (notebook->cur_page->last_focus_child &&
3858           gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
3859         gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
3860       else
3861         if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
3862           gtk_widget_grab_focus (GTK_WIDGET (notebook));
3863     }
3864   
3865   gtk_notebook_update_tab_states (notebook);
3866   gtk_widget_queue_resize (GTK_WIDGET (notebook));
3867   g_object_notify (G_OBJECT (notebook), "page");
3868 }
3869
3870 /* Private GtkNotebook Page Switch Functions:
3871  *
3872  * gtk_notebook_switch_page
3873  * gtk_notebook_page_select
3874  * gtk_notebook_switch_focus_tab
3875  * gtk_notebook_menu_switch_page
3876  */
3877 static void
3878 gtk_notebook_switch_page (GtkNotebook     *notebook,
3879                           GtkNotebookPage *page,
3880                           gint             page_num)
3881
3882   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3883   g_return_if_fail (page != NULL);
3884  
3885   if (notebook->cur_page == page)
3886     return;
3887
3888   if (page_num < 0)
3889     page_num = g_list_index (notebook->children, page);
3890
3891   g_signal_emit (notebook,
3892                  notebook_signals[SWITCH_PAGE],
3893                  0,
3894                  page,
3895                  page_num);
3896 }
3897
3898 static gint
3899 gtk_notebook_page_select (GtkNotebook *notebook,
3900                           gboolean     move_focus)
3901 {
3902   GtkNotebookPage *page;
3903   GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
3904   gint tab_pos = get_effective_tab_pos (notebook);
3905
3906   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
3907
3908   if (!notebook->focus_tab)
3909     return FALSE;
3910
3911   page = notebook->focus_tab->data;
3912   gtk_notebook_switch_page (notebook, page, -1);
3913
3914   if (move_focus)
3915     {
3916       switch (tab_pos)
3917         {
3918         case GTK_POS_TOP:
3919           dir = GTK_DIR_DOWN;
3920           break;
3921         case GTK_POS_BOTTOM:
3922           dir = GTK_DIR_UP;
3923           break;
3924         case GTK_POS_LEFT:
3925           dir = GTK_DIR_RIGHT;
3926           break;
3927         case GTK_POS_RIGHT:
3928           dir = GTK_DIR_LEFT;
3929           break;
3930         }
3931
3932       if (gtk_widget_child_focus (page->child, dir))
3933         return TRUE;
3934     }
3935   return FALSE;
3936 }
3937
3938 static void
3939 gtk_notebook_switch_focus_tab (GtkNotebook *notebook, 
3940                                GList       *new_child)
3941 {
3942   GList *old_child;
3943   GtkNotebookPage *old_page = NULL;
3944   GtkNotebookPage *page;
3945
3946   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
3947
3948   if (notebook->focus_tab == new_child)
3949     return;
3950
3951   old_child = notebook->focus_tab;
3952   notebook->focus_tab = new_child;
3953
3954   if (notebook->scrollable)
3955     gtk_notebook_redraw_arrows (notebook);
3956
3957   if (!notebook->show_tabs || !notebook->focus_tab)
3958     return;
3959
3960   if (old_child)
3961     old_page = old_child->data;
3962
3963   page = notebook->focus_tab->data;
3964   if (GTK_WIDGET_MAPPED (page->tab_label))
3965     gtk_notebook_redraw_tabs (notebook);
3966   else
3967     gtk_notebook_pages_allocate (notebook);
3968   
3969   gtk_notebook_switch_page (notebook, page,
3970                             g_list_index (notebook->children, page));
3971 }
3972
3973 static void
3974 gtk_notebook_menu_switch_page (GtkWidget       *widget,
3975                                GtkNotebookPage *page)
3976 {
3977   GtkNotebook *notebook;
3978   GList *children;
3979   guint page_num;
3980
3981   g_return_if_fail (widget != NULL);
3982   g_return_if_fail (page != NULL);
3983
3984   notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
3985                            (GTK_MENU (widget->parent)));
3986
3987   if (notebook->cur_page == page)
3988     return;
3989
3990   page_num = 0;
3991   children = notebook->children;
3992   while (children && children->data != page)
3993     {
3994       children = children->next;
3995       page_num++;
3996     }
3997
3998   g_signal_emit (notebook,
3999                  notebook_signals[SWITCH_PAGE],
4000                  0,
4001                  page,
4002                  page_num);
4003 }
4004
4005 /* Private GtkNotebook Menu Functions:
4006  *
4007  * gtk_notebook_menu_item_create
4008  * gtk_notebook_menu_label_unparent
4009  * gtk_notebook_menu_detacher
4010  */
4011 static void
4012 gtk_notebook_menu_item_create (GtkNotebook *notebook, 
4013                                GList       *list)
4014 {       
4015   GtkNotebookPage *page;
4016   GtkWidget *menu_item;
4017
4018   page = list->data;
4019   if (page->default_menu)
4020     {
4021       if (page->tab_label && GTK_IS_LABEL (page->tab_label))
4022         page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
4023       else
4024         page->menu_label = gtk_label_new ("");
4025       gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
4026     }
4027
4028   gtk_widget_show (page->menu_label);
4029   menu_item = gtk_menu_item_new ();
4030   gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
4031   gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
4032                          gtk_notebook_real_page_position (notebook, list));
4033   g_signal_connect (menu_item, "activate",
4034                     G_CALLBACK (gtk_notebook_menu_switch_page), page);
4035   if (GTK_WIDGET_VISIBLE (page->child))
4036     gtk_widget_show (menu_item);
4037 }
4038
4039 static void
4040 gtk_notebook_menu_label_unparent (GtkWidget *widget, 
4041                                   gpointer  data)
4042 {
4043   gtk_widget_unparent (GTK_BIN(widget)->child);
4044   GTK_BIN(widget)->child = NULL;
4045 }
4046
4047 static void
4048 gtk_notebook_menu_detacher (GtkWidget *widget,
4049                             GtkMenu   *menu)
4050 {
4051   GtkNotebook *notebook;
4052
4053   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
4054
4055   notebook = GTK_NOTEBOOK (widget);
4056   g_return_if_fail (notebook->menu == (GtkWidget*) menu);
4057
4058   notebook->menu = NULL;
4059 }
4060
4061 /* Private GtkNotebook Setter Functions:
4062  *
4063  * gtk_notebook_set_homogeneous_tabs_internal
4064  * gtk_notebook_set_tab_border_internal
4065  * gtk_notebook_set_tab_hborder_internal
4066  * gtk_notebook_set_tab_vborder_internal
4067  */
4068 static void
4069 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
4070                                             gboolean     homogeneous)
4071 {
4072   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4073
4074   if (homogeneous == notebook->homogeneous)
4075     return;
4076
4077   notebook->homogeneous = homogeneous;
4078   gtk_widget_queue_resize (GTK_WIDGET (notebook));
4079
4080   g_object_notify (G_OBJECT (notebook), "homogeneous");
4081 }
4082
4083 static void
4084 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
4085                                       guint        border_width)
4086 {
4087   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4088
4089   notebook->tab_hborder = border_width;
4090   notebook->tab_vborder = border_width;
4091
4092   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
4093     gtk_widget_queue_resize (GTK_WIDGET (notebook));
4094
4095   g_object_freeze_notify (G_OBJECT (notebook));
4096   g_object_notify (G_OBJECT (notebook), "tab_hborder");
4097   g_object_notify (G_OBJECT (notebook), "tab_vborder");
4098   g_object_thaw_notify (G_OBJECT (notebook));
4099 }
4100
4101 static void
4102 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
4103                                        guint        tab_hborder)
4104 {
4105   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4106
4107   if (notebook->tab_hborder == tab_hborder)
4108     return;
4109
4110   notebook->tab_hborder = tab_hborder;
4111
4112   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
4113     gtk_widget_queue_resize (GTK_WIDGET (notebook));
4114
4115   g_object_notify (G_OBJECT (notebook), "tab_hborder");
4116 }
4117
4118 static void
4119 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
4120                                        guint        tab_vborder)
4121 {
4122   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4123
4124   if (notebook->tab_vborder == tab_vborder)
4125     return;
4126
4127   notebook->tab_vborder = tab_vborder;
4128
4129   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
4130     gtk_widget_queue_resize (GTK_WIDGET (notebook));
4131
4132   g_object_notify (G_OBJECT (notebook), "tab_vborder");
4133 }
4134
4135 /* Public GtkNotebook Page Insert/Remove Methods :
4136  *
4137  * gtk_notebook_append_page
4138  * gtk_notebook_append_page_menu
4139  * gtk_notebook_prepend_page
4140  * gtk_notebook_prepend_page_menu
4141  * gtk_notebook_insert_page
4142  * gtk_notebook_insert_page_menu
4143  * gtk_notebook_remove_page
4144  */
4145 /**
4146  * gtk_notebook_append_page:
4147  * @notebook: a #GtkNotebook
4148  * @child: the #GtkWidget to use as the contents of the page.
4149  * @tab_label: the #GtkWidget to be used as the label for the page,
4150  *             or %NULL to use the default label, 'page N'.
4151  * 
4152  * Appends a page to @notebook.
4153  *
4154  * Return value: the index (starting from 0) of the appended
4155  * page in the notebook, or -1 if function fails
4156  **/
4157 gint
4158 gtk_notebook_append_page (GtkNotebook *notebook,
4159                           GtkWidget   *child,
4160                           GtkWidget   *tab_label)
4161 {
4162   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4163   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
4164   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
4165   
4166   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
4167 }
4168
4169 /**
4170  * gtk_notebook_append_page_menu:
4171  * @notebook: a #GtkNotebook
4172  * @child: the #GtkWidget to use as the contents of the page.
4173  * @tab_label: the #GtkWidget to be used as the label for the page,
4174  *             or %NULL to use the default label, 'page N'.
4175  * @menu_label: the widget to use as a label for the page-switch
4176  *              menu, if that is enabled. If %NULL, and @tab_label
4177  *              is a #GtkLabel or %NULL, then the menu label will be
4178  *              a newly created label with the same text as @tab_label;
4179  *              If @tab_label is not a #GtkLabel, @menu_label must be
4180  *              specified if the page-switch menu is to be used.
4181  * 
4182  * Appends a page to @notebook, specifying the widget to use as the
4183  * label in the popup menu.
4184  *
4185  * Return value: the index (starting from 0) of the appended
4186  * page in the notebook, or -1 if function fails
4187  **/
4188 gint
4189 gtk_notebook_append_page_menu (GtkNotebook *notebook,
4190                                GtkWidget   *child,
4191                                GtkWidget   *tab_label,
4192                                GtkWidget   *menu_label)
4193 {
4194   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4195   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
4196   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
4197   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
4198   
4199   return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
4200 }
4201
4202 /**
4203  * gtk_notebook_prepend_page:
4204  * @notebook: a #GtkNotebook
4205  * @child: the #GtkWidget to use as the contents of the page.
4206  * @tab_label: the #GtkWidget to be used as the label for the page,
4207  *             or %NULL to use the default label, 'page N'.
4208  *
4209  * Prepends a page to @notebook.
4210  *
4211  * Return value: the index (starting from 0) of the prepended
4212  * page in the notebook, or -1 if function fails
4213  **/
4214 gint
4215 gtk_notebook_prepend_page (GtkNotebook *notebook,
4216                            GtkWidget   *child,
4217                            GtkWidget   *tab_label)
4218 {
4219   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4220   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
4221   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
4222   
4223   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
4224 }
4225
4226 /**
4227  * gtk_notebook_prepend_page_menu:
4228  * @notebook: a #GtkNotebook
4229  * @child: the #GtkWidget to use as the contents of the page.
4230  * @tab_label: the #GtkWidget to be used as the label for the page,
4231  *             or %NULL to use the default label, 'page N'.
4232  * @menu_label: the widget to use as a label for the page-switch
4233  *              menu, if that is enabled. If %NULL, and @tab_label
4234  *              is a #GtkLabel or %NULL, then the menu label will be
4235  *              a newly created label with the same text as @tab_label;
4236  *              If @tab_label is not a #GtkLabel, @menu_label must be
4237  *              specified if the page-switch menu is to be used.
4238  * 
4239  * Prepends a page to @notebook, specifying the widget to use as the
4240  * label in the popup menu.
4241  *
4242  * Return value: the index (starting from 0) of the prepended
4243  * page in the notebook, or -1 if function fails
4244  **/
4245 gint
4246 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
4247                                 GtkWidget   *child,
4248                                 GtkWidget   *tab_label,
4249                                 GtkWidget   *menu_label)
4250 {
4251   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4252   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
4253   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
4254   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
4255   
4256   return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
4257 }
4258
4259 /**
4260  * gtk_notebook_insert_page:
4261  * @notebook: a #GtkNotebook
4262  * @child: the #GtkWidget to use as the contents of the page.
4263  * @tab_label: the #GtkWidget to be used as the label for the page,
4264  *             or %NULL to use the default label, 'page N'.
4265  * @position: the index (starting at 0) at which to insert the page,
4266  *            or -1 to append the page after all other pages.
4267  * 
4268  * Insert a page into @notebook at the given position.
4269  *
4270  * Return value: the index (starting from 0) of the inserted
4271  * page in the notebook, or -1 if function fails
4272  **/
4273 gint
4274 gtk_notebook_insert_page (GtkNotebook *notebook,
4275                           GtkWidget   *child,
4276                           GtkWidget   *tab_label,
4277                           gint         position)
4278 {
4279   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4280   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
4281   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
4282   
4283   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
4284 }
4285
4286
4287 static gint
4288 gtk_notebook_page_compare_tab (gconstpointer a,
4289                                gconstpointer b)
4290 {
4291   return (((GtkNotebookPage *) a)->tab_label != b);
4292 }
4293
4294 static gboolean
4295 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
4296                                             gboolean overload,
4297                                             gpointer data)
4298 {
4299   GtkNotebook *notebook = GTK_NOTEBOOK (data);
4300   GList *list;
4301   
4302   list = g_list_find_custom (notebook->children, child,
4303                              gtk_notebook_page_compare_tab);
4304   if (list)
4305     {
4306       GtkNotebookPage *page = list->data;
4307
4308       gtk_widget_grab_focus (GTK_WIDGET (notebook));    /* Do this first to avoid focusing new page */
4309       gtk_notebook_switch_page (notebook, page,  -1);
4310       focus_tabs_in (notebook);
4311     }
4312
4313   return TRUE;
4314 }
4315
4316 /**
4317  * gtk_notebook_insert_page_menu:
4318  * @notebook: a #GtkNotebook
4319  * @child: the #GtkWidget to use as the contents of the page.
4320  * @tab_label: the #GtkWidget to be used as the label for the page,
4321  *             or %NULL to use the default label, 'page N'.
4322  * @menu_label: the widget to use as a label for the page-switch
4323  *              menu, if that is enabled. If %NULL, and @tab_label
4324  *              is a #GtkLabel or %NULL, then the menu label will be
4325  *              a newly created label with the same text as @tab_label;
4326  *              If @tab_label is not a #GtkLabel, @menu_label must be
4327  *              specified if the page-switch menu is to be used.
4328  * @position: the index (starting at 0) at which to insert the page,
4329  *            or -1 to append the page after all other pages.
4330  * 
4331  * Insert a page into @notebook at the given position, specifying
4332  * the widget to use as the label in the popup menu.
4333  *
4334  * Return value: the index (starting from 0) of the inserted
4335  * page in the notebook, or -1 if function fails
4336  **/
4337 gint
4338 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
4339                                GtkWidget   *child,
4340                                GtkWidget   *tab_label,
4341                                GtkWidget   *menu_label,
4342                                gint         position)
4343 {
4344   GtkNotebookPage *page;
4345   gint nchildren;
4346
4347   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4348   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
4349   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
4350   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
4351
4352   gtk_widget_freeze_child_notify (child);
4353   
4354   page = g_new (GtkNotebookPage, 1);
4355   page->child = child;
4356   page->last_focus_child = NULL;
4357   page->requisition.width = 0;
4358   page->requisition.height = 0;
4359   page->allocation.x = 0;
4360   page->allocation.y = 0;
4361   page->allocation.width = 0;
4362   page->allocation.height = 0;
4363   page->default_menu = FALSE;
4364   page->default_tab = FALSE;
4365   page->mnemonic_activate_signal = 0;
4366    
4367   nchildren = g_list_length (notebook->children);
4368   if ((position < 0) || (position > nchildren))
4369     position = nchildren;
4370
4371   notebook->children = g_list_insert (notebook->children, page, position);
4372
4373   if (!tab_label)
4374     {
4375       page->default_tab = TRUE;
4376       if (notebook->show_tabs)
4377         tab_label = gtk_label_new ("");
4378     }
4379   page->tab_label = tab_label;
4380   page->menu_label = menu_label;
4381   page->expand = FALSE;
4382   page->fill = TRUE;
4383   page->pack = GTK_PACK_START; 
4384
4385   if (!menu_label)
4386     page->default_menu = TRUE;
4387   else  
4388     {
4389       g_object_ref (page->menu_label);
4390       gtk_object_sink (GTK_OBJECT (page->menu_label));
4391     }
4392
4393   if (notebook->menu)
4394     gtk_notebook_menu_item_create (notebook,
4395                                    g_list_find (notebook->children, page));
4396
4397   gtk_widget_set_parent (child, GTK_WIDGET (notebook));
4398   if (tab_label)
4399     gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
4400
4401   gtk_notebook_update_labels (notebook);
4402
4403   if (!notebook->first_tab)
4404     notebook->first_tab = notebook->children;
4405
4406   if (!notebook->cur_page)
4407     gtk_widget_set_child_visible (child, TRUE);
4408   else
4409     gtk_widget_set_child_visible (child, FALSE);
4410   
4411   if (tab_label)
4412     {
4413       if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
4414         gtk_widget_show (tab_label);
4415       else
4416         gtk_widget_hide (tab_label);
4417     }
4418
4419   if (!notebook->cur_page)
4420     {
4421       gtk_notebook_switch_page (notebook, page, 0);
4422       gtk_notebook_switch_focus_tab (notebook, NULL);
4423     }
4424
4425   gtk_notebook_update_tab_states (notebook);
4426
4427   if (tab_label)
4428     page->mnemonic_activate_signal =
4429       g_signal_connect (tab_label,
4430                         "mnemonic_activate",
4431                         G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
4432                         notebook);
4433
4434   gtk_widget_child_notify (child, "tab_expand");
4435   gtk_widget_child_notify (child, "tab_fill");
4436   gtk_widget_child_notify (child, "tab_pack");
4437   gtk_widget_child_notify (child, "tab_label");
4438   gtk_widget_child_notify (child, "menu_label");
4439   gtk_widget_child_notify (child, "position");
4440   gtk_widget_thaw_child_notify (child);
4441
4442   return position;
4443 }
4444
4445 /**
4446  * gtk_notebook_remove_page:
4447  * @notebook: a #GtkNotebook.
4448  * @page_num: the index of a notebook page, starting
4449  *            from 0. If -1, the last page will
4450  *            be removed.
4451  * 
4452  * Removes a page from the notebook given its index
4453  * in the notebook.
4454  **/
4455 void
4456 gtk_notebook_remove_page (GtkNotebook *notebook,
4457                           gint         page_num)
4458 {
4459   GList *list;
4460   
4461   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4462   
4463   if (page_num >= 0)
4464     {
4465       list = g_list_nth (notebook->children, page_num);
4466       if (list)
4467         gtk_notebook_real_remove (notebook, list, FALSE);
4468     }
4469   else
4470     {
4471       list = g_list_last (notebook->children);
4472       if (list)
4473         gtk_notebook_real_remove (notebook, list, FALSE);
4474     }
4475 }
4476
4477 /* Public GtkNotebook Page Switch Methods :
4478  * gtk_notebook_get_current_page
4479  * gtk_notebook_page_num
4480  * gtk_notebook_set_current_page
4481  * gtk_notebook_next_page
4482  * gtk_notebook_prev_page
4483  */
4484 /**
4485  * gtk_notebook_get_current_page:
4486  * @notebook: a #GtkNotebook
4487  * 
4488  * Returns the page number of the current page.
4489  * 
4490  * Return value: the index (starting from 0) of the current
4491  * page in the notebook. If the notebook has no pages, then
4492  * -1 will be returned.
4493  **/
4494 gint
4495 gtk_notebook_get_current_page (GtkNotebook *notebook)
4496 {
4497   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4498
4499   if (!notebook->cur_page)
4500     return -1;
4501
4502   return g_list_index (notebook->children, notebook->cur_page);
4503 }
4504
4505 /**
4506  * gtk_notebook_get_nth_page:
4507  * @notebook: a #GtkNotebook
4508  * @page_num: the index of a page in the noteobok, or -1
4509  *            to get the last page.
4510  * 
4511  * Returns the child widget contained in page number @page_num.
4512  * 
4513  * Return value: the child widget, or %NULL if @page_num is
4514  * out of bounds.
4515  **/
4516 GtkWidget*
4517 gtk_notebook_get_nth_page (GtkNotebook *notebook,
4518                            gint         page_num)
4519 {
4520   GtkNotebookPage *page;
4521   GList *list;
4522
4523   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
4524
4525   if (page_num >= 0)
4526     list = g_list_nth (notebook->children, page_num);
4527   else
4528     list = g_list_last (notebook->children);
4529
4530   if (list)
4531     {
4532       page = list->data;
4533       return page->child;
4534     }
4535
4536   return NULL;
4537 }
4538
4539 /**
4540  * gtk_notebook_get_n_pages:
4541  * @notebook: a #GtkNotebook
4542  * 
4543  * Gets the number of pages in a notebook.
4544  * 
4545  * Return value: the number of pages in the notebook.
4546  *
4547  * Since: 2.2
4548  **/
4549 gint
4550 gtk_notebook_get_n_pages (GtkNotebook *notebook)
4551 {
4552   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
4553
4554   return g_list_length (notebook->children);
4555 }
4556
4557 /**
4558  * gtk_notebook_page_num:
4559  * @notebook: a #GtkNotebook
4560  * @child: a #GtkWidget
4561  * 
4562  * Finds the index of the page which contains the given child
4563  * widget.
4564  * 
4565  * Return value: the index of the page containing @child, or
4566  *   -1 if @child is not in the notebook.
4567  **/
4568 gint
4569 gtk_notebook_page_num (GtkNotebook      *notebook,
4570                        GtkWidget        *child)
4571 {
4572   GList *children;
4573   gint num;
4574
4575   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
4576
4577   num = 0;
4578   children = notebook->children;
4579   while (children)
4580     {
4581       GtkNotebookPage *page =  children->data;
4582       
4583       if (page->child == child)
4584         return num;
4585
4586       children = children->next;
4587       num++;
4588     }
4589
4590   return -1;
4591 }
4592
4593 /**
4594  * gtk_notebook_set_current_page:
4595  * @notebook: a #GtkNotebook
4596  * @page_num: index of the page to switch to, starting from 0.
4597  *            If negative, the last page will be used. If greater
4598  *            than the number of pages in the notebook, nothing
4599  *            will be done.
4600  *                
4601  * Switches to the page number @page_num.
4602  **/
4603 void
4604 gtk_notebook_set_current_page (GtkNotebook *notebook,
4605                                gint         page_num)
4606 {
4607   GList *list;
4608
4609   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4610
4611   if (page_num >= 0)
4612     list = g_list_nth (notebook->children, page_num);
4613   else
4614     list = g_list_last (notebook->children);
4615
4616   page_num = g_list_index (notebook->children, list);
4617
4618   if (list)
4619     gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
4620 }
4621
4622 /**
4623  * gtk_notebook_next_page:
4624  * @notebook: a #GtkNotebook
4625  * 
4626  * Switches to the next page. Nothing happens if the current page is
4627  * the last page.
4628  **/
4629 void
4630 gtk_notebook_next_page (GtkNotebook *notebook)
4631 {
4632   GList *list;
4633
4634   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4635
4636   list = g_list_find (notebook->children, notebook->cur_page);
4637   if (!list)
4638     return;
4639
4640   list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4641   if (!list)
4642     return;
4643
4644   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
4645 }
4646
4647 /**
4648  * gtk_notebook_prev_page:
4649  * @notebook: a #GtkNotebook
4650  * 
4651  * Switches to the previous page. Nothing happens if the current page
4652  * is the first page.
4653  **/
4654 void
4655 gtk_notebook_prev_page (GtkNotebook *notebook)
4656 {
4657   GList *list;
4658
4659   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4660
4661   list = g_list_find (notebook->children, notebook->cur_page);
4662   if (!list)
4663     return;
4664
4665   list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
4666   if (!list)
4667     return;
4668
4669   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
4670 }
4671
4672 /* Public GtkNotebook/Tab Style Functions
4673  *
4674  * gtk_notebook_set_show_border
4675  * gtk_notebook_set_show_tabs
4676  * gtk_notebook_set_tab_pos
4677  * gtk_notebook_set_homogeneous_tabs
4678  * gtk_notebook_set_tab_border
4679  * gtk_notebook_set_tab_hborder
4680  * gtk_notebook_set_tab_vborder
4681  * gtk_notebook_set_scrollable
4682  */
4683 /**
4684  * gtk_notebook_set_show_border:
4685  * @notebook: a #GtkNotebook
4686  * @show_border: %TRUE if a bevel should be drawn around the notebook.
4687  * 
4688  * Sets whether a bevel will be drawn around the notebook pages.
4689  * This only has a visual effect when the tabs are not shown.
4690  * See gtk_notebook_set_show_tabs().
4691  **/
4692 void
4693 gtk_notebook_set_show_border (GtkNotebook *notebook,
4694                               gboolean     show_border)
4695 {
4696   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4697
4698   if (notebook->show_border != show_border)
4699     {
4700       notebook->show_border = show_border;
4701
4702       if (GTK_WIDGET_VISIBLE (notebook))
4703         gtk_widget_queue_resize (GTK_WIDGET (notebook));
4704       
4705       g_object_notify (G_OBJECT (notebook), "show_border");
4706     }
4707 }
4708
4709 /**
4710  * gtk_notebook_get_show_border:
4711  * @notebook: a #GtkNotebook
4712  *
4713  * Returns whether a bevel will be drawn around the notebook pages. See
4714  * gtk_notebook_set_show_border().
4715  *
4716  * Return value: %TRUE if the bevel is drawn
4717  **/
4718 gboolean
4719 gtk_notebook_get_show_border (GtkNotebook *notebook)
4720 {
4721   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
4722
4723   return notebook->show_border;
4724 }
4725
4726 /**
4727  * gtk_notebook_set_show_tabs:
4728  * @notebook: a #GtkNotebook
4729  * @show_tabs: %TRUE if the tabs should be shown.
4730  * 
4731  * Sets whether to show the tabs for the notebook or not.
4732  **/
4733 void
4734 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
4735                             gboolean     show_tabs)
4736 {
4737   GtkNotebookPage *page;
4738   GList *children;
4739
4740   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4741
4742   show_tabs = show_tabs != FALSE;
4743
4744   if (notebook->show_tabs == show_tabs)
4745     return;
4746
4747   notebook->show_tabs = show_tabs;
4748   children = notebook->children;
4749
4750   if (!show_tabs)
4751     {
4752       GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
4753       
4754       while (children)
4755         {
4756           page = children->data;
4757           children = children->next;
4758           if (page->default_tab)
4759             {
4760               gtk_widget_destroy (page->tab_label);
4761               page->tab_label = NULL;
4762             }
4763           else
4764             gtk_widget_hide (page->tab_label);
4765         }
4766     }
4767   else
4768     {
4769       GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
4770       gtk_notebook_update_labels (notebook);
4771     }
4772   gtk_widget_queue_resize (GTK_WIDGET (notebook));
4773
4774   g_object_notify (G_OBJECT (notebook), "show_tabs");
4775 }
4776
4777 /**
4778  * gtk_notebook_get_show_tabs:
4779  * @notebook: a #GtkNotebook
4780  *
4781  * Returns whether the tabs of the notebook are shown. See
4782  * gtk_notebook_set_show_tabs().
4783  *
4784  * Return value: %TRUE if the tabs are shown
4785  **/
4786 gboolean
4787 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
4788 {
4789   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
4790
4791   return notebook->show_tabs;
4792 }
4793
4794 /**
4795  * gtk_notebook_set_tab_pos:
4796  * @notebook: a #GtkNotebook.
4797  * @pos: the edge to draw the tabs at.
4798  * 
4799  * Sets the edge at which the tabs for switching pages in the
4800  * notebook are drawn.
4801  **/
4802 void
4803 gtk_notebook_set_tab_pos (GtkNotebook     *notebook,
4804                           GtkPositionType  pos)
4805 {
4806   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4807
4808   if (notebook->tab_pos != pos)
4809     {
4810       notebook->tab_pos = pos;
4811       if (GTK_WIDGET_VISIBLE (notebook))
4812         gtk_widget_queue_resize (GTK_WIDGET (notebook));
4813     }
4814
4815   g_object_notify (G_OBJECT (notebook), "tab_pos");
4816 }
4817
4818 /**
4819  * gtk_notebook_get_tab_pos:
4820  * @notebook: a #GtkNotebook
4821  *
4822  * Gets the edge at which the tabs for switching pages in the
4823  * notebook are drawn.
4824  *
4825  * Return value: the edge at which the tabs are drawn
4826  **/
4827 GtkPositionType
4828 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
4829 {
4830   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
4831
4832   return notebook->tab_pos;
4833 }
4834
4835 /**
4836  * gtk_notebook_set_homogeneous_tabs:
4837  * @notebook: a #GtkNotebook
4838  * @homogeneous: %TRUE if all tabs should be the same size.
4839  * 
4840  * Sets whether the tabs must have all the same size or not.
4841  **/
4842 void
4843 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
4844                                    gboolean     homogeneous)
4845 {
4846   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4847
4848   gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
4849 }
4850
4851 /**
4852  * gtk_notebook_set_tab_border:
4853  * @notebook: a #GtkNotebook
4854  * @border_width: width of the border around the tab labels.
4855  * 
4856  * Sets the width the border around the tab labels
4857  * in a notebook. This is equivalent to calling
4858  * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
4859  * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
4860  **/
4861 void
4862 gtk_notebook_set_tab_border (GtkNotebook *notebook,
4863                              guint        border_width)
4864 {
4865   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4866
4867   gtk_notebook_set_tab_border_internal (notebook, border_width);
4868 }
4869
4870 /**
4871  * gtk_notebook_set_tab_hborder:
4872  * @notebook: a #GtkNotebook
4873  * @tab_hborder: width of the horizontal border of tab labels.
4874  * 
4875  * Sets the width of the horizontal border of tab labels.
4876  **/
4877 void
4878 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
4879                               guint        tab_hborder)
4880 {
4881   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4882
4883   gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
4884 }
4885
4886 /**
4887  * gtk_notebook_set_tab_vborder:
4888  * @notebook: a #GtkNotebook
4889  * @tab_vborder: width of the vertical border of tab labels.
4890  * 
4891  * Sets the width of the vertical border of tab labels.
4892  **/
4893 void
4894 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
4895                               guint        tab_vborder)
4896 {
4897   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4898
4899   gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
4900 }
4901
4902 /**
4903  * gtk_notebook_set_scrollable:
4904  * @notebook: a #GtkNotebook
4905  * @scrollable: %TRUE if scroll arrows should be added
4906  * 
4907  * Sets whether the tab label area will have arrows for scrolling if
4908  * there are too many tabs to fit in the area.
4909  **/
4910 void
4911 gtk_notebook_set_scrollable (GtkNotebook *notebook,
4912                              gboolean     scrollable)
4913 {
4914   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4915
4916   scrollable = (scrollable != FALSE);
4917
4918   if (scrollable != notebook->scrollable)
4919     {
4920       notebook->scrollable = scrollable;
4921
4922       if (GTK_WIDGET_VISIBLE (notebook))
4923         gtk_widget_queue_resize (GTK_WIDGET (notebook));
4924
4925       g_object_notify (G_OBJECT (notebook), "scrollable");
4926     }
4927 }
4928
4929 /**
4930  * gtk_notebook_get_scrollable:
4931  * @notebook: a #GtkNotebook
4932  *
4933  * Returns whether the tab label area has arrows for scrolling. See
4934  * gtk_notebook_set_scrollable().
4935  *
4936  * Return value: %TRUE if arrows for scrolling are present
4937  **/
4938 gboolean
4939 gtk_notebook_get_scrollable (GtkNotebook *notebook)
4940 {
4941   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
4942
4943   return notebook->scrollable;
4944 }
4945
4946 /* Public GtkNotebook Popup Menu Methods:
4947  *
4948  * gtk_notebook_popup_enable
4949  * gtk_notebook_popup_disable
4950  */
4951
4952
4953 /**
4954  * gtk_notebook_popup_enable:
4955  * @notebook: a #GtkNotebook
4956  * 
4957  * Enables the popup menu: if the user clicks with the right mouse button on
4958  * the bookmarks, a menu with all the pages will be popped up.
4959  **/
4960 void
4961 gtk_notebook_popup_enable (GtkNotebook *notebook)
4962 {
4963   GList *list;
4964
4965   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4966
4967   if (notebook->menu)
4968     return;
4969
4970   notebook->menu = gtk_menu_new ();
4971   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4972        list;
4973        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4974     gtk_notebook_menu_item_create (notebook, list);
4975
4976   gtk_notebook_update_labels (notebook);
4977   gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
4978                              GTK_WIDGET (notebook),
4979                              gtk_notebook_menu_detacher);
4980
4981   g_object_notify (G_OBJECT (notebook), "enable_popup");
4982 }
4983
4984 /**
4985  * gtk_notebook_popup_disable:
4986  * @notebook: a #GtkNotebook
4987  * 
4988  * Disables the popup menu.
4989  **/
4990 void       
4991 gtk_notebook_popup_disable  (GtkNotebook *notebook)
4992 {
4993   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
4994
4995   if (!notebook->menu)
4996     return;
4997
4998   gtk_container_foreach (GTK_CONTAINER (notebook->menu),
4999                          (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
5000   gtk_widget_destroy (notebook->menu);
5001
5002   g_object_notify (G_OBJECT (notebook), "enable_popup");
5003 }
5004
5005 /* Public GtkNotebook Page Properties Functions:
5006  *
5007  * gtk_notebook_get_tab_label
5008  * gtk_notebook_set_tab_label
5009  * gtk_notebook_set_tab_label_text
5010  * gtk_notebook_get_menu_label
5011  * gtk_notebook_set_menu_label
5012  * gtk_notebook_set_menu_label_text
5013  * gtk_notebook_set_tab_label_packing
5014  * gtk_notebook_query_tab_label_packing
5015  */
5016
5017 /**
5018  * gtk_notebook_get_tab_label:
5019  * @notebook: a #GtkNotebook
5020  * @child: the page
5021  * 
5022  * Returns the tab label widget for the page @child. %NULL is returned
5023  * if @child is not in @notebook or if no tab label has specifically
5024  * been set for @child.
5025  * 
5026  * Return value: the tab label
5027  **/
5028 GtkWidget *
5029 gtk_notebook_get_tab_label (GtkNotebook *notebook,
5030                             GtkWidget   *child)
5031 {
5032   GList *list;
5033
5034   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
5035   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
5036
5037   list = CHECK_FIND_CHILD (notebook, child);
5038   if (!list)  
5039     return NULL;
5040
5041   if (GTK_NOTEBOOK_PAGE (list)->default_tab)
5042     return NULL;
5043
5044   return GTK_NOTEBOOK_PAGE (list)->tab_label;
5045 }  
5046
5047 /**
5048  * gtk_notebook_set_tab_label:
5049  * @notebook: a #GtkNotebook
5050  * @child: the page
5051  * @tab_label: the tab label widget to use, or %NULL for default tab
5052  *             label.
5053  * 
5054  * Changes the tab label for @child. If %NULL is specified
5055  * for @tab_label, then the page will have the label 'page N'.
5056  **/
5057 void
5058 gtk_notebook_set_tab_label (GtkNotebook *notebook,
5059                             GtkWidget   *child,
5060                             GtkWidget   *tab_label)
5061 {
5062   GtkNotebookPage *page;
5063   GList *list;
5064
5065   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5066   g_return_if_fail (GTK_IS_WIDGET (child));
5067
5068   list = CHECK_FIND_CHILD (notebook, child);
5069   if (!list)  
5070     return;
5071
5072   /* a NULL pointer indicates a default_tab setting, otherwise
5073    * we need to set the associated label
5074    */
5075   page = list->data;
5076   
5077   if (page->tab_label == tab_label)
5078     return;
5079   
5080
5081   gtk_notebook_remove_tab_label (notebook, page);
5082   
5083   if (tab_label)
5084     {
5085       page->default_tab = FALSE;
5086       page->tab_label = tab_label;
5087       gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
5088     }
5089   else
5090     {
5091       page->default_tab = TRUE;
5092       page->tab_label = NULL;
5093
5094       if (notebook->show_tabs)
5095         {
5096           gchar string[32];
5097
5098           g_snprintf (string, sizeof(string), _("Page %u"), 
5099                       gtk_notebook_real_page_position (notebook, list));
5100           page->tab_label = gtk_label_new (string);
5101           gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
5102         }
5103     }
5104
5105   if (page->tab_label)
5106     page->mnemonic_activate_signal =
5107       g_signal_connect (page->tab_label,
5108                         "mnemonic_activate",
5109                         G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
5110                         notebook);
5111
5112   if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
5113     {
5114       gtk_widget_show (page->tab_label);
5115       gtk_widget_queue_resize (GTK_WIDGET (notebook));
5116     }
5117
5118   gtk_notebook_update_tab_states (notebook);
5119   gtk_widget_child_notify (child, "tab_label");
5120 }
5121
5122 /**
5123  * gtk_notebook_set_tab_label_text:
5124  * @notebook: a #GtkNotebook
5125  * @child: the page
5126  * @tab_text: the label text
5127  * 
5128  * Creates a new label and sets it as the tab label for the page
5129  * containing @child.
5130  **/
5131 void
5132 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
5133                                  GtkWidget   *child,
5134                                  const gchar *tab_text)
5135 {
5136   GtkWidget *tab_label = NULL;
5137
5138   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5139
5140   if (tab_text)
5141     tab_label = gtk_label_new (tab_text);
5142   gtk_notebook_set_tab_label (notebook, child, tab_label);
5143   gtk_widget_child_notify (child, "tab_label");
5144 }
5145
5146 /**
5147  * gtk_notebook_get_tab_label_text:
5148  * @notebook: a #GtkNotebook
5149  * @child: a widget contained in a page of @notebook
5150  *
5151  * Retrieves the text of the tab label for the page containing
5152  *    @child.
5153  *
5154  * Returns value: the text of the tab label, or %NULL if the
5155  *                tab label widget is not a #GtkLabel. The
5156  *                string is owned by the widget and must not
5157  *                be freed.
5158  **/
5159 G_CONST_RETURN gchar *
5160 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
5161                                  GtkWidget   *child)
5162 {
5163   GtkWidget *tab_label;
5164
5165   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
5166   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
5167
5168   tab_label = gtk_notebook_get_tab_label (notebook, child);
5169
5170   if (tab_label && GTK_IS_LABEL (tab_label))
5171     return gtk_label_get_text (GTK_LABEL (tab_label));
5172   else
5173     return NULL;
5174 }
5175
5176 /**
5177  * gtk_notebook_get_menu_label:
5178  * @notebook: a #GtkNotebook
5179  * @child: a widget contained in a page of @notebook
5180  * 
5181  * Retrieves the menu label widget of the page containing @child.
5182  * 
5183  * Return value: the menu label, or %NULL if the
5184  *               notebook page does not have a menu label other
5185  *               than the default (the tab label).
5186  **/
5187 GtkWidget*
5188 gtk_notebook_get_menu_label (GtkNotebook *notebook,
5189                              GtkWidget   *child)
5190 {
5191   GList *list;
5192
5193   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
5194   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
5195
5196   list = CHECK_FIND_CHILD (notebook, child);
5197   if (!list)  
5198     return NULL;
5199
5200   if (GTK_NOTEBOOK_PAGE (list)->default_menu)
5201     return NULL;
5202
5203   return GTK_NOTEBOOK_PAGE (list)->menu_label;
5204 }  
5205
5206 /**
5207  * gtk_notebook_set_menu_label:
5208  * @notebook: a #GtkNotebook
5209  * @child: the child widget
5210  * @menu_label: the menu label, or NULL for default
5211  * 
5212  * Changes the menu label for the page containing @child. 
5213  **/
5214 void
5215 gtk_notebook_set_menu_label (GtkNotebook *notebook,
5216                              GtkWidget   *child,
5217                              GtkWidget   *menu_label)
5218 {
5219   GtkNotebookPage *page;
5220   GList *list;
5221
5222   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5223   g_return_if_fail (GTK_IS_WIDGET (child));
5224
5225   list = CHECK_FIND_CHILD (notebook, child);
5226   if (!list)  
5227     return;
5228
5229   page = list->data;
5230   if (page->menu_label)
5231     {
5232       if (notebook->menu)
5233         gtk_container_remove (GTK_CONTAINER (notebook->menu), 
5234                               page->menu_label->parent);
5235
5236       if (!page->default_menu)
5237         g_object_unref (page->menu_label);
5238     }
5239
5240   if (menu_label)
5241     {
5242       page->menu_label = menu_label;
5243       g_object_ref (page->menu_label);
5244       gtk_object_sink (GTK_OBJECT(page->menu_label));
5245       page->default_menu = FALSE;
5246     }
5247   else
5248     page->default_menu = TRUE;
5249
5250   if (notebook->menu)
5251     gtk_notebook_menu_item_create (notebook, list);
5252   gtk_widget_child_notify (child, "menu_label");
5253 }
5254
5255 /**
5256  * gtk_notebook_set_menu_label_text:
5257  * @notebook: a #GtkNotebook
5258  * @child: the child widget
5259  * @menu_text: the label text
5260  * 
5261  * Creates a new label and sets it as the menu label of @child.
5262  **/
5263 void
5264 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
5265                                   GtkWidget   *child,
5266                                   const gchar *menu_text)
5267 {
5268   GtkWidget *menu_label = NULL;
5269
5270   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5271
5272   if (menu_text)
5273     menu_label = gtk_label_new (menu_text);
5274   gtk_notebook_set_menu_label (notebook, child, menu_label);
5275   gtk_widget_child_notify (child, "menu_label");
5276 }
5277
5278 /**
5279  * gtk_notebook_get_menu_label_text:
5280  * @notebook: a #GtkNotebook
5281  * @child: the child widget of a page of the notebook.
5282  *
5283  * Retrieves the text of the menu label for the page containing
5284  *    @child.
5285  *
5286  * Returns value: the text of the tab label, or %NULL if the
5287  *                widget does not have a menu label other than
5288  *                the default menu label, or the menu label widget
5289  *                is not a #GtkLabel. The string is owned by
5290  *                the widget and must not be freed.
5291  **/
5292 G_CONST_RETURN gchar *
5293 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
5294                                   GtkWidget *child)
5295 {
5296   GtkWidget *menu_label;
5297
5298   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
5299   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
5300  
5301   menu_label = gtk_notebook_get_menu_label (notebook, child);
5302
5303   if (menu_label && GTK_IS_LABEL (menu_label))
5304     return gtk_label_get_text (GTK_LABEL (menu_label));
5305   else
5306     return NULL;
5307 }
5308   
5309 /* Helper function called when pages are reordered
5310  */
5311 static void
5312 gtk_notebook_child_reordered (GtkNotebook     *notebook,
5313                               GtkNotebookPage *page)
5314 {
5315   if (notebook->menu)
5316     {
5317       GtkWidget *menu_item;
5318       
5319       menu_item = page->menu_label->parent;
5320       gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
5321       gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
5322       gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
5323     }
5324
5325   gtk_notebook_update_tab_states (notebook);
5326   gtk_notebook_update_labels (notebook);
5327 }
5328
5329 /**
5330  * gtk_notebook_set_tab_label_packing:
5331  * @notebook: a #GtkNotebook
5332  * @child: the child widget
5333  * @expand: whether to expand the bookmark or not
5334  * @fill: whether the bookmark should fill the allocated area or not
5335  * @pack_type: the position of the bookmark
5336  * 
5337  * Sets the packing parameters for the tab label of the page
5338  * containing @child. See gtk_box_pack_start() for the exact meaning
5339  * of the parameters.
5340  **/
5341 void
5342 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
5343                                     GtkWidget   *child,
5344                                     gboolean     expand,
5345                                     gboolean     fill,
5346                                     GtkPackType  pack_type)
5347 {
5348   GtkNotebookPage *page;
5349   GList *list;
5350
5351   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5352   g_return_if_fail (GTK_IS_WIDGET (child));
5353
5354   list = CHECK_FIND_CHILD (notebook, child);
5355   if (!list)  
5356     return;
5357
5358   page = list->data;
5359   expand = expand != FALSE;
5360   fill = fill != FALSE;
5361   if (page->pack == pack_type && page->expand == expand && page->fill == fill)
5362     return;
5363
5364   gtk_widget_freeze_child_notify (child);
5365   page->expand = expand;
5366   gtk_widget_child_notify (child, "tab_expand");
5367   page->fill = fill;
5368   gtk_widget_child_notify (child, "tab_fill");
5369   if (page->pack != pack_type)
5370     {
5371       page->pack = pack_type;
5372       gtk_notebook_child_reordered (notebook, page);
5373     }
5374   gtk_widget_child_notify (child, "tab_pack");
5375   gtk_widget_child_notify (child, "position");
5376   if (notebook->show_tabs)
5377     gtk_notebook_pages_allocate (notebook);
5378   gtk_widget_thaw_child_notify (child);
5379 }  
5380
5381 /**
5382  * gtk_notebook_query_tab_label_packing:
5383  * @notebook: a #GtkNotebook
5384  * @child: the page
5385  * @expand: location to store the expand value (or NULL)
5386  * @fill: location to store the fill value (or NULL)
5387  * @pack_type: location to store the pack_type (or NULL)
5388  * 
5389  * Query the packing attributes for the tab label of the page
5390  * containing @child.
5391  **/
5392 void
5393 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
5394                                       GtkWidget   *child,
5395                                       gboolean    *expand,
5396                                       gboolean    *fill,
5397                                       GtkPackType *pack_type)
5398 {
5399   GList *list;
5400
5401   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5402   g_return_if_fail (GTK_IS_WIDGET (child));
5403
5404   list = CHECK_FIND_CHILD (notebook, child);
5405   if (!list)
5406     return;
5407
5408   if (expand)
5409     *expand = GTK_NOTEBOOK_PAGE (list)->expand;
5410   if (fill)
5411     *fill = GTK_NOTEBOOK_PAGE (list)->fill;
5412   if (pack_type)
5413     *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
5414 }
5415
5416 /**
5417  * gtk_notebook_reorder_child:
5418  * @notebook: a #GtkNotebook
5419  * @child: the child to move
5420  * @position: the new position, or -1 to move to the end
5421  * 
5422  * Reorders the page containing @child, so that it appears in position
5423  * @position. If @position is greater than or equal to the number of
5424  * children in the list or negative, @child will be moved to the end
5425  * of the list.
5426  **/
5427 void
5428 gtk_notebook_reorder_child (GtkNotebook *notebook,
5429                             GtkWidget   *child,
5430                             gint         position)
5431 {
5432   GList *list, *new_list;
5433   GtkNotebookPage *page;
5434   gint old_pos;
5435   gint max_pos;
5436
5437   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5438   g_return_if_fail (GTK_IS_WIDGET (child));
5439
5440   list = CHECK_FIND_CHILD (notebook, child);
5441   if (!list)
5442     return;
5443
5444   max_pos = g_list_length (notebook->children) - 1;
5445   if (position < 0 || position > max_pos)
5446     position = max_pos;
5447
5448   old_pos = g_list_position (notebook->children, list);
5449
5450   if (old_pos == position)
5451     return;
5452
5453   page = list->data;
5454   notebook->children = g_list_delete_link (notebook->children, list);
5455
5456   notebook->children = g_list_insert (notebook->children, page, position);
5457   new_list = g_list_nth (notebook->children, position);
5458
5459   /* Fix up GList references in GtkNotebook structure */
5460   if (notebook->first_tab == list)
5461     notebook->first_tab = new_list;
5462   if (notebook->focus_tab == list)
5463     notebook->focus_tab = new_list;
5464
5465   gtk_widget_freeze_child_notify (child);
5466
5467   /* Move around the menu items if necessary */
5468   gtk_notebook_child_reordered (notebook, page);
5469   gtk_widget_child_notify (child, "tab_pack");
5470   gtk_widget_child_notify (child, "position");
5471   
5472   if (notebook->show_tabs)
5473     gtk_notebook_pages_allocate (notebook);
5474
5475   gtk_widget_thaw_child_notify (child);
5476 }