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