]> Pileus Git - ~andy/gtk/blob - gtk/gtknotebook.c
Add a reorder_tab keynav signal and an insert_page vfunc to GtkNotebook.
[~andy/gtk] / gtk / gtknotebook.c
1 /* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
2 /* GTK - The GIMP Toolkit
3  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
26  */
27
28 #include <config.h>
29 #include "gtknotebook.h"
30 #include "gtkmain.h"
31 #include "gtkmenu.h"
32 #include "gtkmenuitem.h"
33 #include "gtklabel.h"
34 #include <gdk/gdkkeysyms.h>
35 #include <stdio.h>
36 #include "gtkintl.h"
37 #include "gtkmarshalers.h"
38 #include "gtkbindings.h"
39 #include "gtkprivate.h"
40 #include "gtkalias.h"
41 #include "gtkdnd.h"
42
43
44 #define ARROW_SIZE            12
45 #define ARROW_SPACING         0
46 #define SCROLL_DELAY_FACTOR   5
47 #define SCROLL_THRESHOLD      12
48 #define DND_THRESHOLD_MULTIPLIER 4
49
50 enum {
51   SWITCH_PAGE,
52   FOCUS_TAB,
53   SELECT_PAGE,
54   CHANGE_CURRENT_PAGE,
55   MOVE_FOCUS_OUT,
56   REORDER_TAB,
57   TAB_REORDERED,
58   TAB_REMOVED,
59   TAB_ADDED,
60   LAST_SIGNAL
61 };
62
63 enum {
64   STEP_PREV,
65   STEP_NEXT
66 };
67
68 typedef enum
69 {
70   ARROW_NONE,
71   ARROW_LEFT_BEFORE,
72   ARROW_RIGHT_BEFORE,
73   ARROW_LEFT_AFTER,
74   ARROW_RIGHT_AFTER
75 } GtkNotebookArrow;
76
77 typedef enum
78 {
79   POINTER_BEFORE,
80   POINTER_AFTER,
81   POINTER_BETWEEN
82 } GtkNotebookPointerPosition;
83
84 typedef enum
85 {
86   DRAG_OPERATION_NONE,
87   DRAG_OPERATION_REORDER,
88   DRAG_OPERATION_DETACH
89 } GtkNotebookDragOperation;
90
91 #define ARROW_IS_LEFT(arrow)  ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
92 #define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)
93
94 enum {
95   PROP_0,
96   PROP_TAB_POS,
97   PROP_SHOW_TABS,
98   PROP_SHOW_BORDER,
99   PROP_SCROLLABLE,
100   PROP_TAB_BORDER,
101   PROP_TAB_HBORDER,
102   PROP_TAB_VBORDER,
103   PROP_PAGE,
104   PROP_ENABLE_POPUP,
105   PROP_GROUP_ID,
106   PROP_HOMOGENEOUS
107 };
108
109 enum {
110   CHILD_PROP_0,
111   CHILD_PROP_TAB_LABEL,
112   CHILD_PROP_MENU_LABEL,
113   CHILD_PROP_POSITION,
114   CHILD_PROP_TAB_EXPAND,
115   CHILD_PROP_TAB_FILL,
116   CHILD_PROP_TAB_PACK,
117   CHILD_PROP_REORDERABLE,
118   CHILD_PROP_DETACHABLE
119 };
120
121 #define GTK_NOTEBOOK_PAGE(_glist_)         ((GtkNotebookPage *)((GList *)(_glist_))->data)
122
123 /* some useful defines for calculating coords */
124 #define PAGE_LEFT_X(_page_)   (((GtkNotebookPage *) (_page_))->allocation.x)
125 #define PAGE_RIGHT_X(_page_)  (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
126 #define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
127 #define PAGE_TOP_Y(_page_)    (((GtkNotebookPage *) (_page_))->allocation.y)
128 #define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
129 #define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
130
131 struct _GtkNotebookPage
132 {
133   GtkWidget *child;
134   GtkWidget *tab_label;
135   GtkWidget *menu_label;
136   GtkWidget *last_focus_child;  /* Last descendant of the page that had focus */
137
138   guint default_menu : 1;       /* If true, we create the menu label ourself */
139   guint default_tab  : 1;       /* If true, we create the tab label ourself */
140   guint expand       : 1;
141   guint fill         : 1;
142   guint pack         : 1;
143   guint reorderable  : 1;
144   guint detachable   : 1;
145
146   GtkRequisition requisition;
147   GtkAllocation allocation;
148
149   gulong mnemonic_activate_signal;
150   gulong notify_visible_handler;
151 };
152
153 #define GTK_NOTEBOOK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookPrivate))
154
155 typedef struct _GtkNotebookPrivate GtkNotebookPrivate;
156
157 struct _GtkNotebookPrivate
158 {
159   gint  group_id;
160   gint  mouse_x;
161   gint  mouse_y;
162   gint  pressed_button;
163   guint dnd_timer;
164   GtkTargetList *source_targets;
165   gboolean during_detach;
166   gboolean has_scrolled;
167 };
168
169 static const GtkTargetEntry notebook_targets[] = {
170   { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
171   { "application/x-rootwindow-drop", 0, 1 }
172 };
173
174 #ifdef G_DISABLE_CHECKS
175 #define CHECK_FIND_CHILD(notebook, child)                           \
176  gtk_notebook_find_child (notebook, child, G_STRLOC)
177 #else
178 #define CHECK_FIND_CHILD(notebook, child)                           \
179  gtk_notebook_find_child (notebook, child, NULL)
180 #endif
181  
182 /*** GtkNotebook Methods ***/
183 static void gtk_notebook_class_init          (GtkNotebookClass *klass);
184 static void gtk_notebook_init                (GtkNotebook      *notebook);
185
186 static gboolean gtk_notebook_select_page         (GtkNotebook      *notebook,
187                                                   gboolean          move_focus);
188 static gboolean gtk_notebook_focus_tab           (GtkNotebook      *notebook,
189                                                   GtkNotebookTab    type);
190 static void     gtk_notebook_change_current_page (GtkNotebook      *notebook,
191                                                   gint              offset);
192 static void     gtk_notebook_move_focus_out      (GtkNotebook      *notebook,
193                                                   GtkDirectionType  direction_type);
194 static void     gtk_notebook_reorder_tab         (GtkNotebook      *notebook,
195                                                   GtkDirectionType  direction_type,
196                                                   gboolean          move_to_last);
197
198 /*** GtkObject Methods ***/
199 static void gtk_notebook_destroy             (GtkObject        *object);
200 static void gtk_notebook_set_property        (GObject         *object,
201                                               guint            prop_id,
202                                               const GValue    *value,
203                                               GParamSpec      *pspec);
204 static void gtk_notebook_get_property        (GObject         *object,
205                                               guint            prop_id,
206                                               GValue          *value,
207                                               GParamSpec      *pspec);
208
209 /*** GtkWidget Methods ***/
210 static void gtk_notebook_map                 (GtkWidget        *widget);
211 static void gtk_notebook_unmap               (GtkWidget        *widget);
212 static void gtk_notebook_realize             (GtkWidget        *widget);
213 static void gtk_notebook_unrealize           (GtkWidget        *widget);
214 static void gtk_notebook_size_request        (GtkWidget        *widget,
215                                               GtkRequisition   *requisition);
216 static void gtk_notebook_size_allocate       (GtkWidget        *widget,
217                                               GtkAllocation    *allocation);
218 static gint gtk_notebook_expose              (GtkWidget        *widget,
219                                               GdkEventExpose   *event);
220 static gboolean gtk_notebook_scroll          (GtkWidget        *widget,
221                                               GdkEventScroll   *event);
222 static gint gtk_notebook_button_press        (GtkWidget        *widget,
223                                               GdkEventButton   *event);
224 static gint gtk_notebook_button_release      (GtkWidget        *widget,
225                                               GdkEventButton   *event);
226 static gboolean gtk_notebook_popup_menu      (GtkWidget        *widget);
227 static gint gtk_notebook_enter_notify        (GtkWidget        *widget,
228                                               GdkEventCrossing *event);
229 static gint gtk_notebook_leave_notify        (GtkWidget        *widget,
230                                               GdkEventCrossing *event);
231 static gint gtk_notebook_motion_notify       (GtkWidget        *widget,
232                                               GdkEventMotion   *event);
233 static gint gtk_notebook_focus_in            (GtkWidget        *widget,
234                                               GdkEventFocus    *event);
235 static gint gtk_notebook_focus_out           (GtkWidget        *widget,
236                                               GdkEventFocus    *event);
237 static void gtk_notebook_grab_notify         (GtkWidget          *widget,
238                                               gboolean            was_grabbed);
239 static void gtk_notebook_state_changed       (GtkWidget          *widget,
240                                               GtkStateType        previous_state);
241 static void gtk_notebook_draw_focus          (GtkWidget        *widget);
242 static gint gtk_notebook_focus               (GtkWidget        *widget,
243                                               GtkDirectionType  direction);
244 static void gtk_notebook_style_set           (GtkWidget        *widget,
245                                               GtkStyle         *previous);
246
247 /*** Drag and drop Methods ***/
248 static void gtk_notebook_drag_begin          (GtkWidget        *widget,
249                                               GdkDragContext   *context);
250 static gboolean gtk_notebook_drag_motion     (GtkWidget        *widget,
251                                               GdkDragContext   *context,
252                                               gint              x,
253                                               gint              y,
254                                               guint             time);
255 static gboolean gtk_notebook_drag_drop       (GtkWidget        *widget,
256                                               GdkDragContext   *context,
257                                               gint              x,
258                                               gint              y,
259                                               guint             time);
260 static void gtk_notebook_drag_data_get       (GtkWidget        *widget,
261                                               GdkDragContext   *context,
262                                               GtkSelectionData *data,
263                                               guint             info,
264                                               guint             time);
265 static void gtk_notebook_drag_data_received  (GtkWidget        *widget,
266                                               GdkDragContext   *context,
267                                               gint              x,
268                                               gint              y,
269                                               GtkSelectionData *data,
270                                               guint             info,
271                                               guint             time);
272
273 /*** GtkContainer Methods ***/
274 static void gtk_notebook_set_child_property  (GtkContainer     *container,
275                                               GtkWidget        *child,
276                                               guint             property_id,
277                                               const GValue     *value,
278                                               GParamSpec       *pspec);
279 static void gtk_notebook_get_child_property  (GtkContainer     *container,
280                                               GtkWidget        *child,
281                                               guint             property_id,
282                                               GValue           *value,
283                                               GParamSpec       *pspec);
284 static void gtk_notebook_add                 (GtkContainer     *container,
285                                               GtkWidget        *widget);
286 static void gtk_notebook_remove              (GtkContainer     *container,
287                                               GtkWidget        *widget);
288 static void gtk_notebook_set_focus_child     (GtkContainer     *container,
289                                               GtkWidget        *child);
290 static GType gtk_notebook_child_type       (GtkContainer     *container);
291 static void gtk_notebook_forall              (GtkContainer     *container,
292                                               gboolean          include_internals,
293                                               GtkCallback       callback,
294                                               gpointer          callback_data);
295
296 /*** GtkNotebook Methods ***/
297 static gint gtk_notebook_real_insert_page    (GtkNotebook      *notebook,
298                                               GtkWidget        *child,
299                                               GtkWidget        *tab_label,
300                                               GtkWidget        *menu_label,
301                                               gint              position);
302
303 /*** GtkNotebook Private Functions ***/
304 static void gtk_notebook_redraw_tabs         (GtkNotebook      *notebook);
305 static void gtk_notebook_redraw_arrows       (GtkNotebook      *notebook);
306 static void gtk_notebook_real_remove         (GtkNotebook      *notebook,
307                                               GList            *list,
308                                               gboolean          destroying);
309 static void gtk_notebook_update_labels       (GtkNotebook      *notebook);
310 static gint gtk_notebook_timer               (GtkNotebook      *notebook);
311 static gint gtk_notebook_page_compare        (gconstpointer     a,
312                                               gconstpointer     b);
313 static GList* gtk_notebook_find_child        (GtkNotebook      *notebook,
314                                               GtkWidget        *child,
315                                               const gchar      *function);
316 static gint  gtk_notebook_real_page_position (GtkNotebook      *notebook,
317                                               GList            *list);
318 static GList * gtk_notebook_search_page      (GtkNotebook      *notebook,
319                                               GList            *list,
320                                               gint              direction,
321                                               gboolean          find_visible);
322
323 /*** GtkNotebook Drawing Functions ***/
324 static void gtk_notebook_paint               (GtkWidget        *widget,
325                                               GdkRectangle     *area);
326 static void gtk_notebook_draw_tab            (GtkNotebook      *notebook,
327                                               GtkNotebookPage  *page,
328                                               GdkRectangle     *area);
329 static void gtk_notebook_draw_arrow          (GtkNotebook      *notebook,
330                                               GtkNotebookArrow  arrow);
331
332 /*** GtkNotebook Size Allocate Functions ***/
333 static void gtk_notebook_pages_allocate      (GtkNotebook              *notebook,
334                                               GtkNotebookDragOperation  operation);
335 static void gtk_notebook_page_allocate       (GtkNotebook      *notebook,
336                                               GtkNotebookPage  *page,
337                                               GtkAllocation    *allocation);
338 static void gtk_notebook_calc_tabs           (GtkNotebook      *notebook,
339                                               GList            *start,
340                                               GList           **end,
341                                               gint             *tab_space,
342                                               guint             direction);
343
344 /*** GtkNotebook Page Switch Methods ***/
345 static void gtk_notebook_real_switch_page    (GtkNotebook      *notebook,
346                                               GtkNotebookPage  *page,
347                                               guint             page_num);
348
349 /*** GtkNotebook Page Switch Functions ***/
350 static void gtk_notebook_switch_page         (GtkNotebook      *notebook,
351                                               GtkNotebookPage  *page,
352                                               gint              page_num);
353 static gint gtk_notebook_page_select         (GtkNotebook      *notebook,
354                                               gboolean          move_focus);
355 static void gtk_notebook_switch_focus_tab    (GtkNotebook      *notebook,
356                                               GList            *new_child);
357 static void gtk_notebook_menu_switch_page    (GtkWidget        *widget,
358                                               GtkNotebookPage  *page);
359
360 /*** GtkNotebook Menu Functions ***/
361 static void gtk_notebook_menu_item_create    (GtkNotebook      *notebook,
362                                               GList            *list);
363 static void gtk_notebook_menu_label_unparent (GtkWidget        *widget,
364                                               gpointer          data);
365 static void gtk_notebook_menu_detacher       (GtkWidget        *widget,
366                                               GtkMenu          *menu);
367
368 /*** GtkNotebook Private Setters ***/
369 static void gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
370                                                         gboolean     homogeneous);
371 static void gtk_notebook_set_tab_border_internal       (GtkNotebook *notebook,
372                                                         guint        border_width);
373 static void gtk_notebook_set_tab_hborder_internal      (GtkNotebook *notebook,
374                                                         guint        tab_hborder);
375 static void gtk_notebook_set_tab_vborder_internal      (GtkNotebook *notebook,
376                                                         guint        tab_vborder);
377
378 static void gtk_notebook_update_tab_states             (GtkNotebook *notebook);
379 static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
380                                                             gboolean overload,
381                                                             gpointer data);
382
383 static gboolean focus_tabs_in  (GtkNotebook      *notebook);
384 static gboolean focus_child_in (GtkNotebook      *notebook,
385                                 GtkDirectionType  direction);
386
387 static void stop_scrolling (GtkNotebook *notebook);
388
389
390 static GtkNotebookWindowCreationFunc window_creation_hook = NULL;
391 static gpointer window_creation_hook_data;
392
393 static GtkContainerClass *parent_class = NULL;
394 static guint notebook_signals[LAST_SIGNAL] = { 0 };
395
396 GType
397 gtk_notebook_get_type (void)
398 {
399   static GType notebook_type = 0;
400
401   if (!notebook_type)
402     {
403       static const GTypeInfo notebook_info =
404       {
405         sizeof (GtkNotebookClass),
406         NULL,           /* base_init */
407         NULL,           /* base_finalize */
408         (GClassInitFunc) gtk_notebook_class_init,
409         NULL,           /* class_finalize */
410         NULL,           /* class_data */
411         sizeof (GtkNotebook),
412         0,              /* n_preallocs */
413         (GInstanceInitFunc) gtk_notebook_init,
414       };
415
416       notebook_type = g_type_register_static (GTK_TYPE_CONTAINER, I_("GtkNotebook"),
417                                               &notebook_info, 0);
418     }
419
420   return notebook_type;
421 }
422
423 static void
424 add_tab_bindings (GtkBindingSet    *binding_set,
425                   GdkModifierType   modifiers,
426                   GtkDirectionType  direction)
427 {
428   gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
429                                 "move_focus_out", 1,
430                                 GTK_TYPE_DIRECTION_TYPE, direction);
431   gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
432                                 "move_focus_out", 1,
433                                 GTK_TYPE_DIRECTION_TYPE, direction);
434 }
435
436 static void
437 add_arrow_bindings (GtkBindingSet    *binding_set,
438                     guint             keysym,
439                     GtkDirectionType  direction)
440 {
441   guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
442   
443   gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
444                                 "move_focus_out", 1,
445                                 GTK_TYPE_DIRECTION_TYPE, direction);
446   gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
447                                 "move_focus_out", 1,
448                                 GTK_TYPE_DIRECTION_TYPE, direction);
449 }
450
451 static void
452 add_reorder_bindings (GtkBindingSet    *binding_set,
453                       guint             keysym,
454                       GtkDirectionType  direction,
455                       gboolean          move_to_last)
456 {
457   guint keypad_keysym = keysym - GDK_Left + GDK_KP_Left;
458
459   gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
460                                 "reorder_tab", 2,
461                                 GTK_TYPE_DIRECTION_TYPE, direction,
462                                 G_TYPE_BOOLEAN, move_to_last);
463   gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
464                                 "reorder_tab", 2,
465                                 GTK_TYPE_DIRECTION_TYPE, direction,
466                                 G_TYPE_BOOLEAN, move_to_last);
467 }
468
469 static void
470 gtk_notebook_class_init (GtkNotebookClass *class)
471 {
472   GObjectClass   *gobject_class = G_OBJECT_CLASS (class);
473   GtkObjectClass *object_class = GTK_OBJECT_CLASS (class);
474   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
475   GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
476   GtkBindingSet *binding_set;
477   
478   parent_class = g_type_class_peek_parent (class);
479
480   gobject_class->set_property = gtk_notebook_set_property;
481   gobject_class->get_property = gtk_notebook_get_property;
482   object_class->destroy = gtk_notebook_destroy;
483
484   widget_class->map = gtk_notebook_map;
485   widget_class->unmap = gtk_notebook_unmap;
486   widget_class->realize = gtk_notebook_realize;
487   widget_class->unrealize = gtk_notebook_unrealize;
488   widget_class->size_request = gtk_notebook_size_request;
489   widget_class->size_allocate = gtk_notebook_size_allocate;
490   widget_class->expose_event = gtk_notebook_expose;
491   widget_class->scroll_event = gtk_notebook_scroll;
492   widget_class->button_press_event = gtk_notebook_button_press;
493   widget_class->button_release_event = gtk_notebook_button_release;
494   widget_class->popup_menu = gtk_notebook_popup_menu;
495   widget_class->enter_notify_event = gtk_notebook_enter_notify;
496   widget_class->leave_notify_event = gtk_notebook_leave_notify;
497   widget_class->motion_notify_event = gtk_notebook_motion_notify;
498   widget_class->grab_notify = gtk_notebook_grab_notify;
499   widget_class->state_changed = gtk_notebook_state_changed;
500   widget_class->focus_in_event = gtk_notebook_focus_in;
501   widget_class->focus_out_event = gtk_notebook_focus_out;
502   widget_class->focus = gtk_notebook_focus;
503   widget_class->style_set = gtk_notebook_style_set;
504   widget_class->drag_begin = gtk_notebook_drag_begin;
505   widget_class->drag_motion = gtk_notebook_drag_motion;
506   widget_class->drag_drop = gtk_notebook_drag_drop;
507   widget_class->drag_data_get = gtk_notebook_drag_data_get;
508   widget_class->drag_data_received = gtk_notebook_drag_data_received;
509
510   container_class->add = gtk_notebook_add;
511   container_class->remove = gtk_notebook_remove;
512   container_class->forall = gtk_notebook_forall;
513   container_class->set_focus_child = gtk_notebook_set_focus_child;
514   container_class->get_child_property = gtk_notebook_get_child_property;
515   container_class->set_child_property = gtk_notebook_set_child_property;
516   container_class->child_type = gtk_notebook_child_type;
517
518   class->switch_page = gtk_notebook_real_switch_page;
519   class->insert_page = gtk_notebook_real_insert_page;
520
521   class->focus_tab = gtk_notebook_focus_tab;
522   class->select_page = gtk_notebook_select_page;
523   class->change_current_page = gtk_notebook_change_current_page;
524   class->move_focus_out = gtk_notebook_move_focus_out;
525   class->reorder_tab = gtk_notebook_reorder_tab;
526   
527   g_object_class_install_property (gobject_class,
528                                    PROP_PAGE,
529                                    g_param_spec_int ("page",
530                                                      P_("Page"),
531                                                      P_("The index of the current page"),
532                                                      0,
533                                                      G_MAXINT,
534                                                      0,
535                                                      GTK_PARAM_READWRITE));
536   g_object_class_install_property (gobject_class,
537                                    PROP_TAB_POS,
538                                    g_param_spec_enum ("tab-pos",
539                                                       P_("Tab Position"),
540                                                       P_("Which side of the notebook holds the tabs"),
541                                                       GTK_TYPE_POSITION_TYPE,
542                                                       GTK_POS_TOP,
543                                                       GTK_PARAM_READWRITE));
544   g_object_class_install_property (gobject_class,
545                                    PROP_TAB_BORDER,
546                                    g_param_spec_uint ("tab-border",
547                                                       P_("Tab Border"),
548                                                       P_("Width of the border around the tab labels"),
549                                                       0,
550                                                       G_MAXUINT,
551                                                       2,
552                                                       GTK_PARAM_WRITABLE));
553   g_object_class_install_property (gobject_class,
554                                    PROP_TAB_HBORDER,
555                                    g_param_spec_uint ("tab-hborder",
556                                                       P_("Horizontal Tab Border"),
557                                                       P_("Width of the horizontal border of tab labels"),
558                                                       0,
559                                                       G_MAXUINT,
560                                                       2,
561                                                       GTK_PARAM_READWRITE));
562   g_object_class_install_property (gobject_class,
563                                    PROP_TAB_VBORDER,
564                                    g_param_spec_uint ("tab-vborder",
565                                                       P_("Vertical Tab Border"),
566                                                       P_("Width of the vertical border of tab labels"),
567                                                       0,
568                                                       G_MAXUINT,
569                                                       2,
570                                                       GTK_PARAM_READWRITE));
571   g_object_class_install_property (gobject_class,
572                                    PROP_SHOW_TABS,
573                                    g_param_spec_boolean ("show-tabs",
574                                                          P_("Show Tabs"),
575                                                          P_("Whether tabs should be shown or not"),
576                                                          TRUE,
577                                                          GTK_PARAM_READWRITE));
578   g_object_class_install_property (gobject_class,
579                                    PROP_SHOW_BORDER,
580                                    g_param_spec_boolean ("show-border",
581                                                          P_("Show Border"),
582                                                          P_("Whether the border should be shown or not"),
583                                                          TRUE,
584                                                          GTK_PARAM_READWRITE));
585   g_object_class_install_property (gobject_class,
586                                    PROP_SCROLLABLE,
587                                    g_param_spec_boolean ("scrollable",
588                                                          P_("Scrollable"),
589                                                          P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
590                                                          FALSE,
591                                                          GTK_PARAM_READWRITE));
592   g_object_class_install_property (gobject_class,
593                                    PROP_ENABLE_POPUP,
594                                    g_param_spec_boolean ("enable-popup",
595                                                          P_("Enable Popup"),
596                                                          P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
597                                                          FALSE,
598                                                          GTK_PARAM_READWRITE));
599   g_object_class_install_property (gobject_class,
600                                    PROP_HOMOGENEOUS,
601                                    g_param_spec_boolean ("homogeneous",
602                                                          P_("Homogeneous"),
603                                                          P_("Whether tabs should have homogeneous sizes"),
604                                                          FALSE,
605                                                          GTK_PARAM_READWRITE));
606   g_object_class_install_property (gobject_class,
607                                    PROP_GROUP_ID,
608                                    g_param_spec_int ("group-id",
609                                                      P_("Group ID"),
610                                                      P_("Group ID for tabs drag and drop"),
611                                                      -1,
612                                                      G_MAXINT,
613                                                      -1,
614                                                      GTK_PARAM_READWRITE));
615
616   gtk_container_class_install_child_property (container_class,
617                                               CHILD_PROP_TAB_LABEL,
618                                               g_param_spec_string ("tab-label", 
619                                                                    P_("Tab label"),
620                                                                    P_("The string displayed on the child's tab label"),
621                                                                    NULL,
622                                                                    GTK_PARAM_READWRITE));
623   gtk_container_class_install_child_property (container_class,
624                                               CHILD_PROP_MENU_LABEL,
625                                               g_param_spec_string ("menu-label", 
626                                                                    P_("Menu label"), 
627                                                                    P_("The string displayed in the child's menu entry"),
628                                                                    NULL,
629                                                                    GTK_PARAM_READWRITE));
630   gtk_container_class_install_child_property (container_class,
631                                               CHILD_PROP_POSITION,
632                                               g_param_spec_int ("position", 
633                                                                 P_("Position"), 
634                                                                 P_("The index of the child in the parent"),
635                                                                 -1, G_MAXINT, 0,
636                                                                 GTK_PARAM_READWRITE));
637   gtk_container_class_install_child_property (container_class,
638                                               CHILD_PROP_TAB_EXPAND,
639                                               g_param_spec_boolean ("tab-expand", 
640                                                                     P_("Tab expand"), 
641                                                                     P_("Whether to expand the child's tab or not"),
642                                                                     TRUE,
643                                                                     GTK_PARAM_READWRITE));
644   gtk_container_class_install_child_property (container_class,
645                                               CHILD_PROP_TAB_FILL,
646                                               g_param_spec_boolean ("tab-fill", 
647                                                                     P_("Tab fill"), 
648                                                                     P_("Whether the child's tab should fill the allocated area or not"),
649                                                                     TRUE,
650                                                                     GTK_PARAM_READWRITE));
651   gtk_container_class_install_child_property (container_class,
652                                               CHILD_PROP_TAB_PACK,
653                                               g_param_spec_enum ("tab-pack", 
654                                                                  P_("Tab pack type"),
655                                                                  P_("A GtkPackType indicating whether the child is packed with reference to the start or end of the parent"),
656                                                                  GTK_TYPE_PACK_TYPE, GTK_PACK_START,
657                                                                  GTK_PARAM_READWRITE));
658   gtk_container_class_install_child_property (container_class,
659                                               CHILD_PROP_REORDERABLE,
660                                               g_param_spec_boolean ("reorderable",
661                                                                     P_("Tab reorderable"),
662                                                                     P_("Whether the tab is reorderable by user action or not"),
663                                                                     FALSE,
664                                                                     GTK_PARAM_READWRITE));
665   gtk_container_class_install_child_property (container_class,
666                                               CHILD_PROP_DETACHABLE,
667                                               g_param_spec_boolean ("detachable",
668                                                                     P_("Tab detachable"),
669                                                                     P_("Whether the tab is detachable"),
670                                                                     FALSE,
671                                                                     GTK_PARAM_READWRITE));
672
673 /**
674  * GtkNotebook:has-secondary-backward-stepper:
675  *
676  * The "has-secondary-backward-stepper" property determines whether 
677  * a second backward arrow button is displayed on the opposite end 
678  * of the tab area.
679  *
680  * Since: 2.4
681  */  
682   gtk_widget_class_install_style_property (widget_class,
683                                            g_param_spec_boolean ("has-secondary-backward-stepper",
684                                                                  P_("Secondary backward stepper"),
685                                                                  P_("Display a second backward arrow button on the opposite end of the tab area"),
686                                                                  FALSE,
687                                                                  GTK_PARAM_READABLE));
688
689 /**
690  * GtkNotebook:has-secondary-forward-stepper:
691  *
692  * The "has-secondary-forward-stepper" property determines whether 
693  * a second forward arrow button is displayed on the opposite end 
694  * of the tab area.
695  *
696  * Since: 2.4
697  */  
698   gtk_widget_class_install_style_property (widget_class,
699                                            g_param_spec_boolean ("has-secondary-forward-stepper",
700                                                                  P_("Secondary forward stepper"),
701                                                                  P_("Display a second forward arrow button on the opposite end of the tab area"),
702                                                                  FALSE,
703                                                                  GTK_PARAM_READABLE));
704
705 /**
706  * GtkNotebook:has-backward-stepper:
707  *
708  * The "has-backward-stepper" property determines whether 
709  * the standard backward arrow button is displayed.
710  *
711  * Since: 2.4
712  */  
713   gtk_widget_class_install_style_property (widget_class,
714                                            g_param_spec_boolean ("has-backward-stepper",
715                                                                  P_("Backward stepper"),
716                                                                  P_("Display the standard backward arrow button"),
717                                                                  TRUE,
718                                                                  GTK_PARAM_READABLE));
719
720 /**
721  * GtkNotebook:has-forward-stepper:
722  *
723  * The "has-forward-stepper" property determines whether 
724  * the standard forward arrow button is displayed.
725  *
726  * Since: 2.4
727  */  
728   gtk_widget_class_install_style_property (widget_class,
729                                            g_param_spec_boolean ("has-forward-stepper",
730                                                                  P_("Forward stepper"),
731                                                                  P_("Display the standard forward arrow button"),
732                                                                  TRUE,
733                                                                  GTK_PARAM_READABLE));
734   
735 /**
736  * GtkNotebook:tab-overlap:
737  *
738  * The "tab-overlap" property defines size of tab overlap
739  * area.
740  *
741  * Since: 2.10
742  */  
743   gtk_widget_class_install_style_property (widget_class,
744                                            g_param_spec_int ("tab-overlap",
745                                                              P_("Tab overlap"),
746                                                              P_("Size of tab overlap area"),
747                                                              G_MININT,
748                                                              G_MAXINT,
749                                                              2,
750                                                              GTK_PARAM_READABLE));
751
752 /**
753  * GtkNotebook:tab-curvature:
754  *
755  * The "tab-curvature" property defines size of tab curvature.
756  *
757  * Since: 2.10
758  */  
759   gtk_widget_class_install_style_property (widget_class,
760                                            g_param_spec_int ("tab-curvature",
761                                                              P_("Tab curvature"),
762                                                              P_("Size of tab curvature"),
763                                                              0,
764                                                              G_MAXINT,
765                                                              1,
766                                                              GTK_PARAM_READABLE));
767
768   notebook_signals[SWITCH_PAGE] =
769     g_signal_new (I_("switch_page"),
770                   G_TYPE_FROM_CLASS (gobject_class),
771                   G_SIGNAL_RUN_LAST,
772                   G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
773                   NULL, NULL,
774                   _gtk_marshal_VOID__POINTER_UINT,
775                   G_TYPE_NONE, 2,
776                   G_TYPE_POINTER,
777                   G_TYPE_UINT);
778   notebook_signals[FOCUS_TAB] = 
779     g_signal_new (I_("focus_tab"),
780                   G_TYPE_FROM_CLASS (gobject_class),
781                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
782                   G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
783                   NULL, NULL,
784                   _gtk_marshal_BOOLEAN__ENUM,
785                   G_TYPE_BOOLEAN, 1,
786                   GTK_TYPE_NOTEBOOK_TAB);
787   notebook_signals[SELECT_PAGE] = 
788     g_signal_new (I_("select_page"),
789                   G_TYPE_FROM_CLASS (gobject_class),
790                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
791                   G_STRUCT_OFFSET (GtkNotebookClass, select_page),
792                   NULL, NULL,
793                   _gtk_marshal_BOOLEAN__BOOLEAN,
794                   G_TYPE_BOOLEAN, 1,
795                   G_TYPE_BOOLEAN);
796   notebook_signals[CHANGE_CURRENT_PAGE] = 
797     g_signal_new (I_("change_current_page"),
798                   G_TYPE_FROM_CLASS (gobject_class),
799                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
800                   G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
801                   NULL, NULL,
802                   _gtk_marshal_VOID__INT,
803                   G_TYPE_NONE, 1,
804                   G_TYPE_INT);
805   notebook_signals[MOVE_FOCUS_OUT] =
806     g_signal_new (I_("move_focus_out"),
807                   G_TYPE_FROM_CLASS (gobject_class),
808                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
809                   G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
810                   NULL, NULL,
811                   _gtk_marshal_VOID__ENUM,
812                   G_TYPE_NONE, 1,
813                   GTK_TYPE_DIRECTION_TYPE);
814   notebook_signals[REORDER_TAB] =
815     g_signal_new (I_("reorder_tab"),
816                   G_TYPE_FROM_CLASS (gobject_class),
817                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
818                   G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
819                   NULL, NULL,
820                   _gtk_marshal_VOID__ENUM_BOOLEAN,
821                   G_TYPE_NONE, 2,
822                   GTK_TYPE_DIRECTION_TYPE,
823                   G_TYPE_BOOLEAN);
824   /**
825    * GtkNotebook::tab-reordered:
826    * @notebook: the #GtkNotebook
827    * @child: the child #GtkWidget affected
828    * @page_num: the new page number for @child
829    *
830    * the ::tab-reordered signal is emitted in the notebook
831    * right after a tab has been reordered by the user.
832    *
833    * Since: 2.10
834    **/
835   notebook_signals[TAB_REORDERED] =
836     g_signal_new (I_("tab_reordered"),
837                   G_TYPE_FROM_CLASS (gobject_class),
838                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
839                   0, NULL, NULL,
840                   _gtk_marshal_VOID__POINTER_UINT,
841                   G_TYPE_NONE, 2,
842                   G_TYPE_POINTER,
843                   G_TYPE_UINT);
844   /**
845    * GtkNotebook::tab-removed:
846    * @notebook: the #GtkNotebook
847    * @child: the child #GtkWidget affected
848    * @page_num: the @child page number
849    *
850    * the ::tab-removed signal is emitted in the notebook
851    * right before a tab is removed from the notebook.
852    *
853    * Since: 2.10
854    **/
855   notebook_signals[TAB_REMOVED] =
856     g_signal_new (I_("tab_removed"),
857                   G_TYPE_FROM_CLASS (gobject_class),
858                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
859                   0, NULL, NULL,
860                   _gtk_marshal_VOID__POINTER_UINT,
861                   G_TYPE_NONE, 2,
862                   G_TYPE_POINTER,
863                   G_TYPE_UINT);
864   /**
865    * GtkNotebook::tab-attached:
866    * @notebook: the #GtkNotebook
867    * @child: the child #GtkWidget affected
868    * @page_num: the new page number for @child
869    *
870    * the ::tab-added signal is emitted in the notebook
871    * right after a tab is added to the notebook.
872    *
873    * Since: 2.10
874    **/
875   notebook_signals[TAB_ADDED] =
876     g_signal_new (I_("tab_added"),
877                   G_TYPE_FROM_CLASS (gobject_class),
878                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
879                   0, NULL, NULL,
880                   _gtk_marshal_VOID__POINTER_UINT,
881                   G_TYPE_NONE, 2,
882                   G_TYPE_POINTER,
883                   G_TYPE_UINT);
884
885   binding_set = gtk_binding_set_by_class (class);
886   gtk_binding_entry_add_signal (binding_set,
887                                 GDK_space, 0,
888                                 "select_page", 1, 
889                                 G_TYPE_BOOLEAN, FALSE);
890   gtk_binding_entry_add_signal (binding_set,
891                                 GDK_KP_Space, 0,
892                                 "select_page", 1, 
893                                 G_TYPE_BOOLEAN, FALSE);
894   
895   gtk_binding_entry_add_signal (binding_set,
896                                 GDK_Home, 0,
897                                 "focus_tab", 1, 
898                                 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
899   gtk_binding_entry_add_signal (binding_set,
900                                 GDK_KP_Home, 0,
901                                 "focus_tab", 1, 
902                                 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
903   gtk_binding_entry_add_signal (binding_set,
904                                 GDK_End, 0,
905                                 "focus_tab", 1, 
906                                 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
907   gtk_binding_entry_add_signal (binding_set,
908                                 GDK_KP_End, 0,
909                                 "focus_tab", 1, 
910                                 GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
911
912   gtk_binding_entry_add_signal (binding_set,
913                                 GDK_Page_Up, GDK_CONTROL_MASK,
914                                 "change_current_page", 1,
915                                 G_TYPE_INT, -1);
916   gtk_binding_entry_add_signal (binding_set,
917                                 GDK_Page_Down, GDK_CONTROL_MASK,
918                                 "change_current_page", 1,
919                                 G_TYPE_INT, 1);
920
921   gtk_binding_entry_add_signal (binding_set,
922                                 GDK_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
923                                 "change_current_page", 1,
924                                 G_TYPE_INT, -1);
925   gtk_binding_entry_add_signal (binding_set,
926                                 GDK_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
927                                 "change_current_page", 1,
928                                 G_TYPE_INT, 1);
929
930   add_arrow_bindings (binding_set, GDK_Up, GTK_DIR_UP);
931   add_arrow_bindings (binding_set, GDK_Down, GTK_DIR_DOWN);
932   add_arrow_bindings (binding_set, GDK_Left, GTK_DIR_LEFT);
933   add_arrow_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT);
934
935   add_reorder_bindings (binding_set, GDK_Up, GTK_DIR_UP, FALSE);
936   add_reorder_bindings (binding_set, GDK_Down, GTK_DIR_DOWN, FALSE);
937   add_reorder_bindings (binding_set, GDK_Left, GTK_DIR_LEFT, FALSE);
938   add_reorder_bindings (binding_set, GDK_Right, GTK_DIR_RIGHT, FALSE);
939   add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_LEFT, TRUE);
940   add_reorder_bindings (binding_set, GDK_Home, GTK_DIR_UP, TRUE);
941   add_reorder_bindings (binding_set, GDK_End, GTK_DIR_RIGHT, TRUE);
942   add_reorder_bindings (binding_set, GDK_End, GTK_DIR_DOWN, TRUE);
943
944   add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
945   add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
946
947   g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
948 }
949
950 static void
951 gtk_notebook_init (GtkNotebook *notebook)
952 {
953   GtkNotebookPrivate *priv;
954
955   GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
956   GTK_WIDGET_SET_FLAGS (notebook, GTK_NO_WINDOW);
957
958   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
959
960   notebook->cur_page = NULL;
961   notebook->children = NULL;
962   notebook->first_tab = NULL;
963   notebook->focus_tab = NULL;
964   notebook->event_window = NULL;
965   notebook->menu = NULL;
966
967   notebook->tab_hborder = 2;
968   notebook->tab_vborder = 2;
969
970   notebook->show_tabs = TRUE;
971   notebook->show_border = TRUE;
972   notebook->tab_pos = GTK_POS_TOP;
973   notebook->scrollable = FALSE;
974   notebook->in_child = 0;
975   notebook->click_child = 0;
976   notebook->button = 0;
977   notebook->need_timer = 0;
978   notebook->child_has_focus = FALSE;
979   notebook->have_visible_child = FALSE;
980   notebook->focus_out = FALSE;
981
982   notebook->has_before_previous = 1;
983   notebook->has_before_next     = 0;
984   notebook->has_after_previous  = 0;
985   notebook->has_after_next      = 1;
986
987   priv->group_id = -1;
988   priv->pressed_button = -1;
989   priv->dnd_timer = 0;
990   priv->source_targets = gtk_target_list_new (notebook_targets,
991                                               G_N_ELEMENTS (notebook_targets));
992
993   gtk_drag_dest_set (GTK_WIDGET (notebook),
994                      GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
995                      notebook_targets, G_N_ELEMENTS (notebook_targets),
996                      GDK_ACTION_MOVE);
997 }
998
999 static gboolean
1000 gtk_notebook_select_page (GtkNotebook *notebook,
1001                           gboolean     move_focus)
1002 {
1003   if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
1004     {
1005       gtk_notebook_page_select (notebook, move_focus);
1006       return TRUE;
1007     }
1008   else
1009     return FALSE;
1010 }
1011
1012 static gboolean
1013 gtk_notebook_focus_tab (GtkNotebook       *notebook,
1014                         GtkNotebookTab     type)
1015 {
1016   GList *list;
1017
1018   if (gtk_widget_is_focus (GTK_WIDGET (notebook)))
1019     {
1020       switch (type)
1021         {
1022         case GTK_NOTEBOOK_TAB_FIRST:
1023           list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1024           if (list)
1025             gtk_notebook_switch_focus_tab (notebook, list);
1026           break;
1027         case GTK_NOTEBOOK_TAB_LAST:
1028           list = gtk_notebook_search_page (notebook, NULL, STEP_PREV, TRUE);
1029           if (list)
1030             gtk_notebook_switch_focus_tab (notebook, list);
1031           break;
1032         }
1033
1034       return TRUE;
1035     }
1036   else
1037     return FALSE;
1038 }
1039
1040 static void
1041 gtk_notebook_change_current_page (GtkNotebook *notebook,
1042                                   gint         offset)
1043 {
1044   GList *current = NULL;
1045
1046   if (notebook->cur_page)
1047     current = g_list_find (notebook->children, notebook->cur_page);
1048
1049   while (offset != 0)
1050     {
1051       current = gtk_notebook_search_page (notebook, current, offset < 0 ? STEP_PREV : STEP_NEXT, TRUE);
1052       offset += offset < 0 ? 1 : -1;
1053     }
1054
1055   if (current)
1056     gtk_notebook_switch_page (notebook, current->data, -1);
1057   else
1058     gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
1059 }
1060
1061 static GtkDirectionType
1062 get_effective_direction (GtkNotebook      *notebook,
1063                          GtkDirectionType  direction)
1064 {
1065   /* Remap the directions into the effective direction it would be for a
1066    * GTK_POS_TOP notebook
1067    */
1068
1069 #define D(rest) GTK_DIR_##rest
1070
1071   static const GtkDirectionType translate_direction[2][4][6] = {
1072     /* LEFT */   {{ D(TAB_FORWARD),  D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP),   D(DOWN) },
1073     /* RIGHT */  { D(TAB_BACKWARD), D(TAB_FORWARD),  D(LEFT), D(RIGHT), D(DOWN), D(UP)   },
1074     /* TOP */    { D(TAB_FORWARD),  D(TAB_BACKWARD), D(UP),   D(DOWN),  D(LEFT), D(RIGHT) },
1075     /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD),  D(DOWN), D(UP),    D(LEFT), D(RIGHT) }},
1076     /* LEFT */  {{ D(TAB_BACKWARD), D(TAB_FORWARD),  D(LEFT), D(RIGHT), D(DOWN), D(UP)   },
1077     /* RIGHT */  { D(TAB_FORWARD),  D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP),   D(DOWN) },
1078     /* TOP */    { D(TAB_FORWARD),  D(TAB_BACKWARD), D(UP),   D(DOWN),  D(RIGHT), D(LEFT) },
1079     /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD),  D(DOWN), D(UP),    D(RIGHT), D(LEFT) }},
1080   };
1081
1082 #undef D
1083
1084   int text_dir = gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL ? 1 : 0;
1085
1086   return translate_direction[text_dir][notebook->tab_pos][direction];
1087 }
1088
1089 static gint
1090 get_effective_tab_pos (GtkNotebook *notebook)
1091 {
1092   if (gtk_widget_get_direction (GTK_WIDGET (notebook)) == GTK_TEXT_DIR_RTL)
1093     {
1094       switch (notebook->tab_pos) 
1095         {
1096         case GTK_POS_LEFT:
1097           return GTK_POS_RIGHT;
1098         case GTK_POS_RIGHT:
1099           return GTK_POS_LEFT;
1100         default: ;
1101         }
1102     }
1103
1104   return notebook->tab_pos;
1105 }
1106
1107 static void
1108 gtk_notebook_move_focus_out (GtkNotebook      *notebook,
1109                              GtkDirectionType  direction_type)
1110 {
1111   GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1112   GtkWidget *toplevel;
1113   
1114   if (GTK_CONTAINER (notebook)->focus_child && effective_direction == GTK_DIR_UP)
1115     if (focus_tabs_in (notebook))
1116       return;
1117   if (gtk_widget_is_focus (GTK_WIDGET (notebook)) && effective_direction == GTK_DIR_DOWN)
1118     if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
1119       return;
1120
1121   /* At this point, we know we should be focusing out of the notebook entirely. We
1122    * do this by setting a flag, then propagating the focus motion to the notebook.
1123    */
1124   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (notebook));
1125   if (!GTK_WIDGET_TOPLEVEL (toplevel))
1126     return;
1127
1128   g_object_ref (notebook);
1129   
1130   notebook->focus_out = TRUE;
1131   g_signal_emit_by_name (toplevel, "move_focus", direction_type);
1132   notebook->focus_out = FALSE;
1133   
1134   g_object_unref (notebook);
1135 }
1136
1137 static gint
1138 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1139 {
1140   GList *elem;
1141
1142   /* check that we aren't inserting the tab in the
1143    * same relative position, taking packing into account */
1144   elem = (position) ? position->prev : g_list_last (notebook->children);
1145
1146   while (elem && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1147     elem = elem->prev;
1148
1149   if (elem == tab)
1150     return g_list_position (notebook->children, tab);
1151
1152   /* now actually reorder the tab */
1153   if (notebook->first_tab == tab)
1154     notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1155                                                     STEP_NEXT, TRUE);
1156
1157   notebook->children = g_list_remove_link (notebook->children, tab);
1158
1159   if (!position)
1160     elem = g_list_last (notebook->children);
1161   else
1162     {
1163       elem = position->prev;
1164       position->prev = tab;
1165     }
1166
1167   if (elem)
1168     elem->next = tab;
1169   else
1170     notebook->children = tab;
1171
1172   tab->prev = elem;
1173   tab->next = position;
1174
1175   return g_list_position (notebook->children, tab);
1176 }
1177
1178 static void
1179 gtk_notebook_reorder_tab (GtkNotebook      *notebook,
1180                           GtkDirectionType  direction_type,
1181                           gboolean          move_to_last)
1182 {
1183   GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1184   GtkNotebookPage *page;
1185   GList *last, *child;
1186   gint page_num;
1187
1188   if (!notebook->cur_page ||
1189       !notebook->cur_page->reorderable)
1190     return;
1191
1192   if (effective_direction != GTK_DIR_LEFT &&
1193       effective_direction != GTK_DIR_RIGHT)
1194     return;
1195
1196   if (move_to_last)
1197     {
1198       child = notebook->focus_tab;
1199
1200       do
1201         {
1202           last = child;
1203           child = gtk_notebook_search_page (notebook, last, 
1204                                             (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1205                                             TRUE);
1206         }
1207       while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1208
1209       child = last;
1210     }
1211   else
1212     child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1213                                       (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1214                                       TRUE);
1215
1216   if (!child || child->data == notebook->cur_page)
1217     return;
1218
1219   page = child->data;
1220
1221   if (page->pack == notebook->cur_page->pack)
1222     {
1223       if (effective_direction == GTK_DIR_RIGHT)
1224         page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1225       else
1226         page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1227
1228       gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
1229
1230       g_signal_emit (notebook,
1231                      notebook_signals[TAB_REORDERED],
1232                      0,
1233                      ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1234                      page_num);
1235     }
1236 }
1237
1238 /**
1239  * gtk_notebook_new:
1240  * 
1241  * Creates a new #GtkNotebook widget with no pages.
1242
1243  * Return value: the newly created #GtkNotebook
1244  **/
1245 GtkWidget*
1246 gtk_notebook_new (void)
1247 {
1248   return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1249 }
1250
1251 /* Private GtkObject Methods :
1252  * 
1253  * gtk_notebook_destroy
1254  * gtk_notebook_set_arg
1255  * gtk_notebook_get_arg
1256  */
1257 static void
1258 gtk_notebook_destroy (GtkObject *object)
1259 {
1260   GList *children;
1261   GtkNotebook *notebook = GTK_NOTEBOOK (object);
1262   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1263   
1264   if (notebook->menu)
1265     gtk_notebook_popup_disable (notebook);
1266
1267   children = notebook->children;
1268   while (children)
1269     {
1270       GList *child = children;
1271       children = child->next;
1272       
1273       gtk_notebook_real_remove (notebook, child, TRUE);
1274     }
1275
1276   if (priv->source_targets)
1277     {
1278       gtk_target_list_unref (priv->source_targets);
1279       priv->source_targets = NULL;
1280     }
1281   
1282   GTK_OBJECT_CLASS (parent_class)->destroy (object);
1283 }
1284
1285 static void
1286 gtk_notebook_set_property (GObject         *object,
1287                            guint            prop_id,
1288                            const GValue    *value,
1289                            GParamSpec      *pspec)
1290 {
1291   GtkNotebook *notebook;
1292
1293   notebook = GTK_NOTEBOOK (object);
1294
1295   switch (prop_id)
1296     {
1297     case PROP_SHOW_TABS:
1298       gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1299       break;
1300     case PROP_SHOW_BORDER:
1301       gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1302       break;
1303     case PROP_SCROLLABLE:
1304       gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1305       break;
1306     case PROP_ENABLE_POPUP:
1307       if (g_value_get_boolean (value))
1308         gtk_notebook_popup_enable (notebook);
1309       else
1310         gtk_notebook_popup_disable (notebook);
1311       break;
1312     case PROP_HOMOGENEOUS:
1313       gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1314       break;  
1315     case PROP_PAGE:
1316       gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1317       break;
1318     case PROP_TAB_POS:
1319       gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1320       break;
1321     case PROP_TAB_BORDER:
1322       gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1323       break;
1324     case PROP_TAB_HBORDER:
1325       gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1326       break;
1327     case PROP_TAB_VBORDER:
1328       gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1329       break;
1330     case PROP_GROUP_ID:
1331       gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1332       break;
1333     default:
1334       break;
1335     }
1336 }
1337
1338 static void
1339 gtk_notebook_get_property (GObject         *object,
1340                            guint            prop_id,
1341                            GValue          *value,
1342                            GParamSpec      *pspec)
1343 {
1344   GtkNotebook *notebook;
1345   GtkNotebookPrivate *priv;
1346
1347   notebook = GTK_NOTEBOOK (object);
1348   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1349
1350   switch (prop_id)
1351     {
1352     case PROP_SHOW_TABS:
1353       g_value_set_boolean (value, notebook->show_tabs);
1354       break;
1355     case PROP_SHOW_BORDER:
1356       g_value_set_boolean (value, notebook->show_border);
1357       break;
1358     case PROP_SCROLLABLE:
1359       g_value_set_boolean (value, notebook->scrollable);
1360       break;
1361     case PROP_ENABLE_POPUP:
1362       g_value_set_boolean (value, notebook->menu != NULL);
1363       break;
1364     case PROP_HOMOGENEOUS:
1365       g_value_set_boolean (value, notebook->homogeneous);
1366       break;
1367     case PROP_PAGE:
1368       g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1369       break;
1370     case PROP_TAB_POS:
1371       g_value_set_enum (value, notebook->tab_pos);
1372       break;
1373     case PROP_TAB_HBORDER:
1374       g_value_set_uint (value, notebook->tab_hborder);
1375       break;
1376     case PROP_TAB_VBORDER:
1377       g_value_set_uint (value, notebook->tab_vborder);
1378       break;
1379     case PROP_GROUP_ID:
1380       g_value_set_int (value, priv->group_id);
1381       break;
1382     default:
1383       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1384       break;
1385     }
1386 }
1387
1388 /* Private GtkWidget Methods :
1389  * 
1390  * gtk_notebook_map
1391  * gtk_notebook_unmap
1392  * gtk_notebook_realize
1393  * gtk_notebook_size_request
1394  * gtk_notebook_size_allocate
1395  * gtk_notebook_expose
1396  * gtk_notebook_scroll
1397  * gtk_notebook_button_press
1398  * gtk_notebook_button_release
1399  * gtk_notebook_popup_menu
1400  * gtk_notebook_enter_notify
1401  * gtk_notebook_leave_notify
1402  * gtk_notebook_motion_notify
1403  * gtk_notebook_focus_in
1404  * gtk_notebook_focus_out
1405  * gtk_notebook_draw_focus
1406  * gtk_notebook_style_set
1407  * gtk_notebook_drag_begin
1408  * gtk_notebook_drag_motion
1409  * gtk_notebook_drag_drop
1410  * gtk_notebook_drag_data_get
1411  * gtk_notebook_drag_data_received
1412  */
1413 static gboolean
1414 gtk_notebook_get_event_window_position (GtkNotebook  *notebook,
1415                                         GdkRectangle *rectangle)
1416 {
1417   GtkWidget *widget = GTK_WIDGET (notebook);
1418   gint border_width = GTK_CONTAINER (notebook)->border_width;
1419   GtkNotebookPage *visible_page = NULL;
1420   GList *tmp_list;
1421   gint tab_pos = get_effective_tab_pos (notebook);
1422
1423   for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1424     {
1425       GtkNotebookPage *page = tmp_list->data;
1426       if (GTK_WIDGET_VISIBLE (page->child))
1427         {
1428           visible_page = page;
1429           break;
1430         }
1431     }
1432
1433   if (notebook->show_tabs && visible_page)
1434     {
1435       if (rectangle)
1436         {
1437           rectangle->x = widget->allocation.x + border_width;
1438           rectangle->y = widget->allocation.y + border_width;
1439           
1440           switch (tab_pos)
1441             {
1442             case GTK_POS_TOP:
1443             case GTK_POS_BOTTOM:
1444               rectangle->width = widget->allocation.width - 2 * border_width;
1445               rectangle->height = visible_page->requisition.height;
1446               if (tab_pos == GTK_POS_BOTTOM)
1447                 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1448               break;
1449             case GTK_POS_LEFT:
1450             case GTK_POS_RIGHT:
1451               rectangle->width = visible_page->requisition.width;
1452               rectangle->height = widget->allocation.height - 2 * border_width;
1453               if (tab_pos == GTK_POS_RIGHT)
1454                 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1455               break;
1456             }
1457         }
1458
1459       return TRUE;
1460     }
1461   else
1462     {
1463       if (rectangle)
1464         {
1465           rectangle->x = rectangle->y = 0;
1466           rectangle->width = rectangle->height = 10;
1467         }
1468     }
1469
1470   return FALSE;
1471 }
1472
1473 static void
1474 gtk_notebook_map (GtkWidget *widget)
1475 {
1476   GtkNotebook *notebook;
1477   GtkNotebookPage *page;
1478   GList *children;
1479
1480   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1481
1482   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1483
1484   notebook = GTK_NOTEBOOK (widget);
1485
1486   if (notebook->cur_page && 
1487       GTK_WIDGET_VISIBLE (notebook->cur_page->child) &&
1488       !GTK_WIDGET_MAPPED (notebook->cur_page->child))
1489     gtk_widget_map (notebook->cur_page->child);
1490
1491   if (notebook->scrollable)
1492     gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
1493   else
1494     {
1495       children = notebook->children;
1496
1497       while (children)
1498         {
1499           page = children->data;
1500           children = children->next;
1501
1502           if (page->tab_label &&
1503               GTK_WIDGET_VISIBLE (page->tab_label) &&
1504               !GTK_WIDGET_MAPPED (page->tab_label))
1505             gtk_widget_map (page->tab_label);
1506         }
1507     }
1508
1509   if (gtk_notebook_get_event_window_position (notebook, NULL))
1510     gdk_window_show_unraised (notebook->event_window);
1511 }
1512
1513 static void
1514 gtk_notebook_unmap (GtkWidget *widget)
1515 {
1516   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1517
1518   stop_scrolling (GTK_NOTEBOOK (widget));
1519   
1520   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1521
1522   gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1523
1524   GTK_WIDGET_CLASS (parent_class)->unmap (widget);
1525 }
1526
1527 static void
1528 gtk_notebook_realize (GtkWidget *widget)
1529 {
1530   GtkNotebook *notebook;
1531   GdkWindowAttr attributes;
1532   gint attributes_mask;
1533   GdkRectangle event_window_pos;
1534
1535   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1536
1537   notebook = GTK_NOTEBOOK (widget);
1538   GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1539
1540   gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1541   
1542   widget->window = gtk_widget_get_parent_window (widget);
1543   g_object_ref (widget->window);
1544   
1545   attributes.window_type = GDK_WINDOW_CHILD;
1546   attributes.x = event_window_pos.x;
1547   attributes.y = event_window_pos.y;
1548   attributes.width = event_window_pos.width;
1549   attributes.height = event_window_pos.height;
1550   attributes.wclass = GDK_INPUT_ONLY;
1551   attributes.event_mask = gtk_widget_get_events (widget);
1552   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1553                             GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1554                             GDK_BUTTON1_MOTION_MASK |
1555                             GDK_SCROLL_MASK);
1556   attributes_mask = GDK_WA_X | GDK_WA_Y;
1557
1558   notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), 
1559                                            &attributes, attributes_mask);
1560   gdk_window_set_user_data (notebook->event_window, notebook);
1561
1562   widget->style = gtk_style_attach (widget->style, widget->window);
1563 }
1564
1565 static void
1566 gtk_notebook_unrealize (GtkWidget *widget)
1567 {
1568   GtkNotebook *notebook;
1569
1570   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
1571
1572   notebook = GTK_NOTEBOOK (widget);
1573
1574   gdk_window_set_user_data (notebook->event_window, NULL);
1575   gdk_window_destroy (notebook->event_window);
1576   notebook->event_window = NULL;
1577
1578   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1579     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1580 }
1581
1582 static void
1583 gtk_notebook_size_request (GtkWidget      *widget,
1584                            GtkRequisition *requisition)
1585 {
1586   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1587   GtkNotebookPage *page;
1588   GList *children;
1589   GtkRequisition child_requisition;
1590   gboolean switch_page = FALSE;
1591   gint vis_pages;
1592   gint focus_width;
1593   gint tab_overlap;
1594   gint tab_curvature;
1595
1596   gtk_widget_style_get (widget,
1597                         "focus-line-width", &focus_width,
1598                         "tab-overlap", &tab_overlap,
1599                         "tab-curvature", &tab_curvature,
1600                         NULL);
1601   
1602   widget->requisition.width = 0;
1603   widget->requisition.height = 0;
1604
1605   for (children = notebook->children, vis_pages = 0; children;
1606        children = children->next)
1607     {
1608       page = children->data;
1609
1610       if (GTK_WIDGET_VISIBLE (page->child))
1611         {
1612           vis_pages++;
1613           gtk_widget_size_request (page->child, &child_requisition);
1614           
1615           widget->requisition.width = MAX (widget->requisition.width,
1616                                            child_requisition.width);
1617           widget->requisition.height = MAX (widget->requisition.height,
1618                                             child_requisition.height);
1619
1620           if (notebook->menu && page->menu_label->parent &&
1621               !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1622             gtk_widget_show (page->menu_label->parent);
1623         }
1624       else
1625         {
1626           if (page == notebook->cur_page)
1627             switch_page = TRUE;
1628           if (notebook->menu && page->menu_label->parent &&
1629               GTK_WIDGET_VISIBLE (page->menu_label->parent))
1630             gtk_widget_hide (page->menu_label->parent);
1631         }
1632     }
1633
1634   if (notebook->show_border || notebook->show_tabs)
1635     {
1636       widget->requisition.width += widget->style->xthickness * 2;
1637       widget->requisition.height += widget->style->ythickness * 2;
1638
1639       if (notebook->show_tabs)
1640         {
1641           gint tab_width = 0;
1642           gint tab_height = 0;
1643           gint tab_max = 0;
1644           gint padding;
1645           
1646           for (children = notebook->children; children;
1647                children = children->next)
1648             {
1649               page = children->data;
1650               
1651               if (GTK_WIDGET_VISIBLE (page->child))
1652                 {
1653                   if (!GTK_WIDGET_VISIBLE (page->tab_label))
1654                     gtk_widget_show (page->tab_label);
1655
1656                   gtk_widget_size_request (page->tab_label,
1657                                            &child_requisition);
1658
1659                   page->requisition.width = 
1660                     child_requisition.width +
1661                     2 * widget->style->xthickness;
1662                   page->requisition.height = 
1663                     child_requisition.height +
1664                     2 * widget->style->ythickness;
1665                   
1666                   switch (notebook->tab_pos)
1667                     {
1668                     case GTK_POS_TOP:
1669                     case GTK_POS_BOTTOM:
1670                       page->requisition.height += 2 * (notebook->tab_vborder +
1671                                                        focus_width);
1672                       tab_height = MAX (tab_height, page->requisition.height);
1673                       tab_max = MAX (tab_max, page->requisition.width);
1674                       break;
1675                     case GTK_POS_LEFT:
1676                     case GTK_POS_RIGHT:
1677                       page->requisition.width += 2 * (notebook->tab_hborder +
1678                                                       focus_width);
1679                       tab_width = MAX (tab_width, page->requisition.width);
1680                       tab_max = MAX (tab_max, page->requisition.height);
1681                       break;
1682                     }
1683                 }
1684               else if (GTK_WIDGET_VISIBLE (page->tab_label))
1685                 gtk_widget_hide (page->tab_label);
1686             }
1687
1688           children = notebook->children;
1689
1690           if (vis_pages)
1691             {
1692               switch (notebook->tab_pos)
1693                 {
1694                 case GTK_POS_TOP:
1695                 case GTK_POS_BOTTOM:
1696                   if (tab_height == 0)
1697                     break;
1698
1699                   if (notebook->scrollable && vis_pages > 1 && 
1700                       widget->requisition.width < tab_width)
1701                     tab_height = MAX (tab_height, ARROW_SIZE);
1702
1703                   padding = 2 * (tab_curvature + focus_width +
1704                                  notebook->tab_hborder) - tab_overlap;
1705                   tab_max += padding;
1706                   while (children)
1707                     {
1708                       page = children->data;
1709                       children = children->next;
1710                   
1711                       if (!GTK_WIDGET_VISIBLE (page->child))
1712                         continue;
1713
1714                       if (notebook->homogeneous)
1715                         page->requisition.width = tab_max;
1716                       else
1717                         page->requisition.width += padding;
1718
1719                       tab_width += page->requisition.width;
1720                       page->requisition.height = tab_height;
1721                     }
1722
1723                   if (notebook->scrollable && vis_pages > 1 &&
1724                       widget->requisition.width < tab_width)
1725                     tab_width = tab_max + 2 * (ARROW_SIZE + ARROW_SPACING);
1726
1727                   if (notebook->homogeneous && !notebook->scrollable)
1728                     widget->requisition.width = MAX (widget->requisition.width,
1729                                                      vis_pages * tab_max +
1730                                                      tab_overlap);
1731                   else
1732                     widget->requisition.width = MAX (widget->requisition.width,
1733                                                      tab_width + tab_overlap);
1734
1735                   widget->requisition.height += tab_height;
1736                   break;
1737                 case GTK_POS_LEFT:
1738                 case GTK_POS_RIGHT:
1739                   if (tab_width == 0)
1740                     break;
1741
1742                   if (notebook->scrollable && vis_pages > 1 && 
1743                       widget->requisition.height < tab_height)
1744                     tab_width = MAX (tab_width, ARROW_SPACING + 2 * ARROW_SIZE);
1745
1746                   padding = 2 * (tab_curvature + focus_width +
1747                                  notebook->tab_vborder) - tab_overlap;
1748                   tab_max += padding;
1749
1750                   while (children)
1751                     {
1752                       page = children->data;
1753                       children = children->next;
1754
1755                       if (!GTK_WIDGET_VISIBLE (page->child))
1756                         continue;
1757
1758                       page->requisition.width   = tab_width;
1759
1760                       if (notebook->homogeneous)
1761                         page->requisition.height = tab_max;
1762                       else
1763                         page->requisition.height += padding;
1764
1765                       tab_height += page->requisition.height;
1766                     }
1767
1768                   if (notebook->scrollable && vis_pages > 1 && 
1769                       widget->requisition.height < tab_height)
1770                     tab_height = tab_max + ARROW_SIZE + ARROW_SPACING;
1771
1772                   widget->requisition.width += tab_width;
1773
1774                   if (notebook->homogeneous && !notebook->scrollable)
1775                     widget->requisition.height =
1776                       MAX (widget->requisition.height,
1777                            vis_pages * tab_max + tab_overlap);
1778                   else
1779                     widget->requisition.height =
1780                       MAX (widget->requisition.height,
1781                            tab_height + tab_overlap);
1782
1783                   if (!notebook->homogeneous || notebook->scrollable)
1784                     vis_pages = 1;
1785                   widget->requisition.height = MAX (widget->requisition.height,
1786                                                     vis_pages * tab_max +
1787                                                     tab_overlap);
1788                   break;
1789                 }
1790             }
1791         }
1792       else
1793         {
1794           for (children = notebook->children; children;
1795                children = children->next)
1796             {
1797               page = children->data;
1798               
1799               if (page->tab_label && GTK_WIDGET_VISIBLE (page->tab_label))
1800                 gtk_widget_hide (page->tab_label);
1801             }
1802         }
1803     }
1804
1805   widget->requisition.width += GTK_CONTAINER (widget)->border_width * 2;
1806   widget->requisition.height += GTK_CONTAINER (widget)->border_width * 2;
1807
1808   if (switch_page)
1809     {
1810       if (vis_pages)
1811         {
1812           for (children = notebook->children; children;
1813                children = children->next)
1814             {
1815               page = children->data;
1816               if (GTK_WIDGET_VISIBLE (page->child))
1817                 {
1818                   gtk_notebook_switch_page (notebook, page, -1);
1819                   break;
1820                 }
1821             }
1822         }
1823       else if (GTK_WIDGET_VISIBLE (widget))
1824         {
1825           widget->requisition.width = GTK_CONTAINER (widget)->border_width * 2;
1826           widget->requisition.height= GTK_CONTAINER (widget)->border_width * 2;
1827         }
1828     }
1829   if (vis_pages && !notebook->cur_page)
1830     {
1831       children = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
1832       if (children)
1833         {
1834           notebook->first_tab = children;
1835           gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (children),-1);
1836         }
1837     }
1838 }
1839
1840 static void
1841 gtk_notebook_size_allocate (GtkWidget     *widget,
1842                             GtkAllocation *allocation)
1843 {
1844   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1845   gint vis_pages = 0;
1846   gint tab_pos = get_effective_tab_pos (notebook);
1847
1848   widget->allocation = *allocation;
1849   if (GTK_WIDGET_REALIZED (widget))
1850     {
1851       GdkRectangle position;
1852
1853       if (gtk_notebook_get_event_window_position (notebook, &position))
1854         {
1855           gdk_window_move_resize (notebook->event_window,
1856                                   position.x, position.y,
1857                                   position.width, position.height);
1858           if (GTK_WIDGET_MAPPED (notebook))
1859             gdk_window_show_unraised (notebook->event_window);
1860         }
1861       else
1862         gdk_window_hide (notebook->event_window);
1863     }
1864
1865   if (notebook->children)
1866     {
1867       gint border_width = GTK_CONTAINER (widget)->border_width;
1868       GtkNotebookPage *page;
1869       GtkAllocation child_allocation;
1870       GList *children;
1871       
1872       child_allocation.x = widget->allocation.x + border_width;
1873       child_allocation.y = widget->allocation.y + border_width;
1874       child_allocation.width = MAX (1, allocation->width - border_width * 2);
1875       child_allocation.height = MAX (1, allocation->height - border_width * 2);
1876
1877       if (notebook->show_tabs || notebook->show_border)
1878         {
1879           child_allocation.x += widget->style->xthickness;
1880           child_allocation.y += widget->style->ythickness;
1881           child_allocation.width = MAX (1, child_allocation.width -
1882                                         widget->style->xthickness * 2);
1883           child_allocation.height = MAX (1, child_allocation.height -
1884                                          widget->style->ythickness * 2);
1885
1886           if (notebook->show_tabs && notebook->children && notebook->cur_page)
1887             {
1888               switch (tab_pos)
1889                 {
1890                 case GTK_POS_TOP:
1891                   child_allocation.y += notebook->cur_page->requisition.height;
1892                 case GTK_POS_BOTTOM:
1893                   child_allocation.height =
1894                     MAX (1, child_allocation.height -
1895                          notebook->cur_page->requisition.height);
1896                   break;
1897                 case GTK_POS_LEFT:
1898                   child_allocation.x += notebook->cur_page->requisition.width;
1899                 case GTK_POS_RIGHT:
1900                   child_allocation.width =
1901                     MAX (1, child_allocation.width -
1902                          notebook->cur_page->requisition.width);
1903                   break;
1904                 }
1905             }
1906         }
1907
1908       children = notebook->children;
1909       while (children)
1910         {
1911           page = children->data;
1912           children = children->next;
1913           
1914           if (GTK_WIDGET_VISIBLE (page->child))
1915             {
1916               gtk_widget_size_allocate (page->child, &child_allocation);
1917               vis_pages++;
1918             }
1919         }
1920
1921       gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
1922     }
1923 }
1924
1925 static gint
1926 gtk_notebook_expose (GtkWidget      *widget,
1927                      GdkEventExpose *event)
1928 {
1929   GtkNotebook *notebook;
1930   GdkRectangle child_area;
1931    
1932   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
1933   g_return_val_if_fail (event != NULL, FALSE);
1934
1935   if (GTK_WIDGET_DRAWABLE (widget))
1936     {
1937       notebook = GTK_NOTEBOOK (widget);
1938
1939       gtk_notebook_paint (widget, &event->area);
1940       if (notebook->show_tabs)
1941         {
1942           if (notebook->cur_page && 
1943               gtk_widget_intersect (notebook->cur_page->tab_label, 
1944                                     &event->area, &child_area))
1945             gtk_notebook_draw_focus (widget);
1946         }
1947
1948       
1949       if (notebook->cur_page)
1950         gtk_container_propagate_expose (GTK_CONTAINER (notebook),
1951                                         notebook->cur_page->child,
1952                                         event);
1953     }
1954
1955   return FALSE;
1956 }
1957
1958 static gboolean
1959 gtk_notebook_show_arrows (GtkNotebook *notebook)
1960 {
1961   gboolean show_arrow = FALSE;
1962   GList *children;
1963   
1964   if (!notebook->scrollable)
1965     return FALSE;
1966
1967   children = notebook->children;
1968   while (children)
1969     {
1970       GtkNotebookPage *page = children->data;
1971
1972       if (page->tab_label && !gtk_widget_get_child_visible (page->tab_label))
1973         show_arrow = TRUE;
1974
1975       children = children->next;
1976     }
1977
1978   return show_arrow;
1979 }
1980
1981 static void
1982 gtk_notebook_get_arrow_rect (GtkNotebook     *notebook,
1983                              GdkRectangle    *rectangle,
1984                              GtkNotebookArrow arrow)
1985 {
1986   GdkRectangle event_window_pos;
1987   gboolean before = ARROW_IS_BEFORE (arrow);
1988   gboolean left = ARROW_IS_LEFT (arrow);
1989
1990   if (gtk_notebook_get_event_window_position (notebook, &event_window_pos))
1991     {
1992       rectangle->width = ARROW_SIZE;
1993       rectangle->height = ARROW_SIZE;
1994
1995       switch (notebook->tab_pos)
1996         {
1997         case GTK_POS_LEFT:
1998         case GTK_POS_RIGHT:
1999           if ((before && (notebook->has_before_previous != notebook->has_before_next)) ||
2000               (!before && (notebook->has_after_previous != notebook->has_after_next))) 
2001           rectangle->x = event_window_pos.x + (event_window_pos.width - rectangle->width) / 2;
2002           else if (left)
2003             rectangle->x = event_window_pos.x + event_window_pos.width / 2 - rectangle->width;
2004           else 
2005             rectangle->x = event_window_pos.x + event_window_pos.width / 2;
2006           rectangle->y = event_window_pos.y;
2007           if (!before)
2008             rectangle->y += event_window_pos.height - rectangle->height;
2009           break;
2010         case GTK_POS_TOP:
2011         case GTK_POS_BOTTOM:
2012           if (before)
2013             {
2014               if (left || !notebook->has_before_previous)
2015                 rectangle->x = event_window_pos.x;
2016               else
2017                 rectangle->x = event_window_pos.x + rectangle->width;
2018             }
2019           else
2020             {
2021               if (!left || !notebook->has_after_next)
2022                 rectangle->x = event_window_pos.x + event_window_pos.width - rectangle->width;
2023               else
2024                 rectangle->x = event_window_pos.x + event_window_pos.width - 2 * rectangle->width;
2025             }
2026           rectangle->y = event_window_pos.y + (event_window_pos.height - rectangle->height) / 2;
2027           break;
2028         }
2029     }
2030 }
2031
2032 static GtkNotebookArrow
2033 gtk_notebook_get_arrow (GtkNotebook *notebook,
2034                         gint         x,
2035                         gint         y)
2036 {
2037   GdkRectangle arrow_rect;
2038   GdkRectangle event_window_pos;
2039   gint i;
2040   gint x0, y0;
2041   GtkNotebookArrow arrow[4];
2042
2043   arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
2044   arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
2045   arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
2046   arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
2047
2048   if (gtk_notebook_show_arrows (notebook))
2049     {
2050       gtk_notebook_get_event_window_position (notebook, &event_window_pos);
2051       for (i = 0; i < 4; i++) 
2052         { 
2053           if (arrow[i] == ARROW_NONE)
2054             continue;
2055       
2056           gtk_notebook_get_arrow_rect (notebook, &arrow_rect, arrow[i]);
2057       
2058           x0 = x - arrow_rect.x;
2059           y0 = y - arrow_rect.y;
2060           
2061           if (y0 >= 0 && y0 < arrow_rect.height &&
2062               x0 >= 0 && x0 < arrow_rect.width)
2063             return arrow[i];
2064         }
2065     }
2066
2067   return ARROW_NONE;
2068 }
2069
2070 static void
2071 gtk_notebook_do_arrow (GtkNotebook     *notebook,
2072                        GtkNotebookArrow arrow)
2073 {
2074   GtkWidget *widget = GTK_WIDGET (notebook);
2075   GtkDirectionType dir;
2076   gboolean is_rtl, left;
2077
2078   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2079   left = (ARROW_IS_LEFT (arrow) && !is_rtl) || 
2080          (!ARROW_IS_LEFT (arrow) && is_rtl);
2081   
2082   if (!notebook->focus_tab ||
2083       gtk_notebook_search_page (notebook, notebook->focus_tab,
2084                                 left ? STEP_PREV : STEP_NEXT,
2085                                 TRUE))
2086     {
2087       if (notebook->tab_pos == GTK_POS_LEFT ||
2088           notebook->tab_pos == GTK_POS_RIGHT)
2089         dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_UP : GTK_DIR_DOWN;
2090       else
2091         dir = ARROW_IS_LEFT (arrow) ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
2092       gtk_widget_child_focus (widget, dir);
2093     }
2094 }
2095
2096 static gboolean
2097 gtk_notebook_arrow_button_press (GtkNotebook      *notebook,
2098                                  GtkNotebookArrow  arrow,
2099                                  GdkEventButton   *event)
2100 {
2101   GtkWidget *widget = GTK_WIDGET (notebook);
2102   gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2103   gboolean left = (ARROW_IS_LEFT (arrow) && !is_rtl) || 
2104                   (!ARROW_IS_LEFT (arrow) && is_rtl);
2105
2106   if (!GTK_WIDGET_HAS_FOCUS (widget))
2107     gtk_widget_grab_focus (widget);
2108   
2109   notebook->button = event->button;
2110   notebook->click_child = arrow;
2111   
2112   if (event->button == 1)
2113     {
2114       gtk_notebook_do_arrow (notebook, arrow);
2115       
2116       if (!notebook->timer)
2117         {
2118           GtkSettings *settings = gtk_widget_get_settings (widget);
2119           guint        timeout;
2120
2121           g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);
2122
2123           notebook->timer = g_timeout_add (timeout,
2124                                            (GSourceFunc) gtk_notebook_timer,
2125                                            (gpointer) notebook);
2126           notebook->need_timer = TRUE;
2127         }
2128     }
2129   else if (event->button == 2)
2130     gtk_notebook_page_select (notebook, TRUE);
2131   else if (event->button == 3)
2132     gtk_notebook_switch_focus_tab (notebook,
2133                                    gtk_notebook_search_page (notebook,
2134                                                              NULL,
2135                                                              left ? STEP_NEXT : STEP_PREV,
2136                                                              TRUE));
2137   gtk_notebook_redraw_arrows (notebook);
2138
2139   return TRUE;
2140 }
2141
2142 static gboolean
2143 get_widget_coordinates (GtkWidget *widget,
2144                         GdkEvent  *event,
2145                         gint      *x,
2146                         gint      *y)
2147 {
2148   GdkWindow *window = ((GdkEventAny *)event)->window;
2149   gdouble tx, ty;
2150
2151   if (!gdk_event_get_coords (event, &tx, &ty))
2152     return FALSE;
2153
2154   while (window && window != widget->window)
2155     {
2156       gint window_x, window_y;
2157       
2158       gdk_window_get_position (window, &window_x, &window_y);
2159       tx += window_x;
2160       ty += window_y;
2161
2162       window = gdk_window_get_parent (window);
2163     }
2164
2165   if (window)
2166     {
2167       *x = tx;
2168       *y = ty;
2169
2170       return TRUE;
2171     }
2172   else
2173     return FALSE;
2174 }
2175
2176 static gboolean
2177 gtk_notebook_scroll (GtkWidget      *widget,
2178                      GdkEventScroll *event)
2179 {
2180   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2181
2182   GtkWidget* child;
2183   GtkWidget* originator;
2184
2185   if (!notebook->cur_page)
2186     return FALSE;
2187
2188   child = notebook->cur_page->child;
2189   originator = gtk_get_event_widget ((GdkEvent *)event);
2190
2191   /* ignore scroll events from the content of the page */
2192   if (!originator || gtk_widget_is_ancestor (originator, child))
2193     return FALSE;
2194   
2195   switch (event->direction)
2196     {
2197     case GDK_SCROLL_RIGHT:
2198     case GDK_SCROLL_DOWN:
2199       gtk_notebook_next_page (notebook);
2200       break;
2201     case GDK_SCROLL_LEFT:
2202     case GDK_SCROLL_UP:
2203       gtk_notebook_prev_page (notebook);
2204       break;
2205     }
2206
2207   return TRUE;
2208 }
2209
2210 static gboolean
2211 gtk_notebook_button_press (GtkWidget      *widget,
2212                            GdkEventButton *event)
2213 {
2214   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2215   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2216   GtkNotebookPage *page;
2217   GList *children;
2218   GtkNotebookArrow arrow;
2219   gint num;
2220   gint x, y;
2221
2222   if (event->type != GDK_BUTTON_PRESS || !notebook->children ||
2223       notebook->button)
2224     return FALSE;
2225
2226   if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2227     return FALSE;
2228
2229   arrow = gtk_notebook_get_arrow (notebook, x, y);
2230   if (arrow)
2231     return gtk_notebook_arrow_button_press (notebook, arrow, event);
2232
2233   if (event->button == 3 && notebook->menu)
2234     {
2235       gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL, 
2236                       NULL, NULL, 3, event->time);
2237       return TRUE;
2238     }
2239
2240   if (event->button != 1)
2241     return FALSE;
2242
2243   notebook->button = event->button;
2244   num = 0;
2245   children = notebook->children;
2246
2247   while (children)
2248     {
2249       page = children->data;
2250       
2251       if (GTK_WIDGET_VISIBLE (page->child) &&
2252           page->tab_label && GTK_WIDGET_MAPPED (page->tab_label) &&
2253           (x >= page->allocation.x) &&
2254           (y >= page->allocation.y) &&
2255           (x <= (page->allocation.x + page->allocation.width)) &&
2256           (y <= (page->allocation.y + page->allocation.height)))
2257         {
2258           gboolean page_changed = page != notebook->cur_page;
2259           gboolean was_focus = gtk_widget_is_focus (widget);
2260           
2261           gtk_notebook_switch_focus_tab (notebook, children);
2262           gtk_widget_grab_focus (widget);
2263           
2264           if (page_changed && !was_focus)
2265             gtk_widget_child_focus (page->child, GTK_DIR_TAB_FORWARD);
2266           
2267           /* save press to possibly begin a drag */
2268           if (page->reorderable || page->detachable)
2269             {
2270               priv->during_detach = FALSE;
2271               priv->pressed_button = event->button;
2272               gtk_grab_add (widget);
2273             }
2274
2275           break;
2276         }
2277       children = children->next;
2278       num++;
2279     }
2280
2281   return TRUE;
2282 }
2283
2284 static void
2285 popup_position_func (GtkMenu  *menu,
2286                      gint     *x,
2287                      gint     *y,
2288                      gboolean *push_in,
2289                      gpointer  data)
2290 {
2291   GtkNotebook *notebook = data;
2292   GtkWidget *w;
2293   GtkRequisition requisition;
2294
2295   if (notebook->focus_tab)
2296     {
2297       GtkNotebookPage *page;
2298
2299       page = notebook->focus_tab->data;
2300       w = page->tab_label;
2301     }
2302   else
2303    {
2304      w = GTK_WIDGET (notebook);
2305    }
2306
2307   gdk_window_get_origin (w->window, x, y);
2308   gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
2309
2310   if (gtk_widget_get_direction (w) == GTK_TEXT_DIR_RTL)
2311     *x += w->allocation.x + w->allocation.width - requisition.width;
2312   else
2313     *x += w->allocation.x;
2314
2315   *y += w->allocation.y + w->allocation.height;
2316
2317   *push_in = FALSE;
2318 }
2319
2320 static gboolean
2321 gtk_notebook_popup_menu (GtkWidget *widget)
2322 {
2323   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2324
2325   if (notebook->menu)
2326     {
2327       gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL, 
2328                       popup_position_func, notebook,
2329                       0, gtk_get_current_event_time ());
2330       gtk_menu_shell_select_first (GTK_MENU_SHELL (notebook->menu), FALSE);
2331       return TRUE;
2332     }
2333
2334   return FALSE;
2335 }
2336
2337 static void 
2338 stop_scrolling (GtkNotebook *notebook)
2339 {
2340   if (notebook->timer)
2341     {
2342       g_source_remove (notebook->timer);
2343       notebook->timer = 0;
2344       notebook->need_timer = FALSE;
2345     }
2346   notebook->click_child = 0;
2347   notebook->button = 0;
2348   gtk_notebook_redraw_arrows (notebook);
2349 }
2350
2351 static GList*
2352 get_drop_position (GtkNotebook *notebook,
2353                    guint        pack,
2354                    gint         x,
2355                    gint         y)
2356 {
2357   GList *children;
2358   GtkNotebookPage *page;
2359   gboolean is_rtl;
2360   
2361   is_rtl = gtk_widget_get_direction ((GtkWidget *) notebook) == GTK_TEXT_DIR_RTL;
2362   children = notebook->children;
2363
2364   while (children)
2365     {
2366       page = children->data;
2367
2368       if (GTK_WIDGET_VISIBLE (page->child) &&
2369           page->tab_label &&
2370           GTK_WIDGET_MAPPED (page->tab_label) &&
2371           page->pack == pack)
2372         {
2373           switch (notebook->tab_pos)
2374             {
2375             case GTK_POS_TOP:
2376             case GTK_POS_BOTTOM:
2377               if (!is_rtl)
2378                 {
2379                   if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) > x) ||
2380                       (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) < x))
2381                     return children;
2382                 }
2383               else
2384                 {
2385                   if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_X (page) < x) ||
2386                       (page->pack == GTK_PACK_END && PAGE_MIDDLE_X (page) > x))
2387                     return children;
2388                 }
2389
2390               break;
2391             case GTK_POS_LEFT:
2392             case GTK_POS_RIGHT:
2393               if ((page->pack == GTK_PACK_START && PAGE_MIDDLE_Y (page) > y) ||
2394                   (page->pack == GTK_PACK_END && PAGE_MIDDLE_Y (page) < y))
2395                 return children;
2396
2397               break;
2398             }
2399         }
2400
2401       children = children->next;
2402     }
2403
2404   return NULL;
2405 }
2406
2407 static gint
2408 gtk_notebook_button_release (GtkWidget      *widget,
2409                              GdkEventButton *event)
2410 {
2411   GtkNotebook *notebook;
2412   GtkNotebookPrivate *priv;
2413   GList *element;
2414   gint old_page_num, page_num;
2415
2416   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2417   g_return_val_if_fail (event != NULL, FALSE);
2418
2419   if (event->type != GDK_BUTTON_RELEASE)
2420     return FALSE;
2421
2422   notebook = GTK_NOTEBOOK (widget);
2423   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2424
2425   if (notebook->cur_page->reorderable &&
2426       event->button == priv->pressed_button)
2427     {
2428       gtk_grab_remove (widget);
2429       priv->pressed_button = -1;
2430
2431       if (!priv->during_detach)
2432         {
2433           element = get_drop_position (notebook,
2434                                        notebook->cur_page->pack,
2435                                        PAGE_MIDDLE_X (notebook->cur_page),
2436                                        PAGE_MIDDLE_Y (notebook->cur_page));
2437           old_page_num = g_list_position (notebook->children, notebook->focus_tab);
2438           page_num = reorder_tab (notebook, element, notebook->focus_tab);
2439
2440           if (priv->has_scrolled ||
2441               old_page_num != page_num)
2442             g_signal_emit (notebook,
2443                            notebook_signals[TAB_REORDERED], 0,
2444                            ((GtkNotebookPage *) notebook->focus_tab->data)->child,
2445                            page_num);
2446
2447           priv->has_scrolled = FALSE;
2448         }
2449
2450       gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
2451
2452       if (priv->dnd_timer)
2453         {
2454           g_source_remove (priv->dnd_timer);
2455           priv->dnd_timer = 0;
2456         }
2457     }
2458
2459   if (event->button == notebook->button)
2460     {
2461       stop_scrolling (notebook);
2462
2463       return TRUE;
2464     }
2465   else
2466     return FALSE;
2467 }
2468
2469 static gint
2470 gtk_notebook_enter_notify (GtkWidget        *widget,
2471                            GdkEventCrossing *event)
2472 {
2473   GtkNotebook *notebook;
2474   GtkNotebookArrow arrow;
2475   gint x, y;
2476
2477   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
2478   g_return_val_if_fail (event != NULL, FALSE);
2479
2480   notebook = GTK_NOTEBOOK (widget);
2481
2482   if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2483     return FALSE;
2484
2485   arrow = gtk_notebook_get_arrow (notebook, x, y);
2486
2487   if (arrow != notebook->in_child)
2488     {
2489       notebook->in_child = arrow;
2490       gtk_notebook_redraw_arrows (notebook);
2491
2492       return TRUE;
2493     }
2494
2495   return TRUE;
2496 }
2497
2498 static gint
2499 gtk_notebook_leave_notify (GtkWidget        *widget,
2500                            GdkEventCrossing *event)
2501 {
2502   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2503   gint x, y;
2504
2505   if (!get_widget_coordinates (widget, (GdkEvent *)event, &x, &y))
2506     return FALSE;
2507
2508   if (notebook->in_child)
2509     {
2510       notebook->in_child = 0;
2511       gtk_notebook_redraw_arrows (notebook);
2512     }
2513
2514   return TRUE;
2515 }
2516
2517 static GtkNotebookPointerPosition
2518 get_pointer_position (GtkNotebook *notebook)
2519 {
2520   GtkWidget *widget = (GtkWidget *) notebook;
2521   GtkContainer *container = (GtkContainer *) notebook;
2522   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2523   gboolean is_rtl;
2524
2525   if (!notebook->scrollable)
2526     return POINTER_BETWEEN;
2527
2528   if (notebook->tab_pos == GTK_POS_TOP ||
2529       notebook->tab_pos == GTK_POS_BOTTOM)
2530     {
2531       is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
2532
2533       if (priv->mouse_x > widget->allocation.width - 2 * container->border_width - SCROLL_THRESHOLD)
2534         return (is_rtl) ? POINTER_BEFORE : POINTER_AFTER;
2535       else if (priv->mouse_x < SCROLL_THRESHOLD + container->border_width)
2536         return (is_rtl) ? POINTER_AFTER : POINTER_BEFORE;
2537       else
2538         return POINTER_BETWEEN;
2539     }
2540   else
2541     {
2542       if (priv->mouse_y > widget->allocation.height - 2 * container->border_width - SCROLL_THRESHOLD)
2543         return POINTER_AFTER;
2544       else if (priv->mouse_y < SCROLL_THRESHOLD + container->border_width)
2545         return POINTER_BEFORE;
2546       else
2547         return POINTER_BETWEEN;
2548     }
2549 }
2550
2551 static gboolean
2552 scroll_notebook_timer (gpointer data)
2553 {
2554   GtkNotebook *notebook = (GtkNotebook *) data;
2555   GtkNotebookPrivate *priv;
2556   GtkNotebookPointerPosition pointer_position;
2557   GList *element, *first_tab;
2558
2559   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2560   pointer_position = get_pointer_position (notebook);
2561
2562   element = get_drop_position (notebook,
2563                                notebook->cur_page->pack,
2564                                PAGE_MIDDLE_X (notebook->cur_page),
2565                                PAGE_MIDDLE_Y (notebook->cur_page));
2566
2567   reorder_tab (notebook, element, notebook->focus_tab);
2568
2569   first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
2570                                         (pointer_position == POINTER_BEFORE) ? STEP_PREV : STEP_NEXT,
2571                                         TRUE);
2572   if (first_tab)
2573     {
2574       notebook->first_tab = first_tab;
2575       gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_REORDER);
2576     }
2577
2578   return TRUE;
2579 }
2580
2581 static gboolean
2582 check_threshold (GtkNotebook *notebook,
2583                  gint         current_x,
2584                  gint         current_y)
2585 {
2586   GtkWidget *widget;
2587   gint dnd_threshold, width, height;
2588   GdkRectangle rectangle = { 0, }; /* shut up gcc */
2589   GtkSettings *settings;
2590   
2591   widget = GTK_WIDGET (notebook);
2592   settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2593   g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &dnd_threshold, NULL);
2594
2595   gdk_drawable_get_size (GDK_DRAWABLE (notebook->event_window), &width, &height);
2596
2597   /* we want a large threshold */
2598   dnd_threshold *= DND_THRESHOLD_MULTIPLIER;
2599
2600   rectangle.x = - dnd_threshold;
2601   rectangle.width = width + 2 * dnd_threshold;
2602   rectangle.y = - dnd_threshold;
2603   rectangle.height = height + 2 * dnd_threshold;
2604
2605   return (current_x < rectangle.x ||
2606           current_x > rectangle.x + rectangle.width ||
2607           current_y < rectangle.y ||
2608           current_y > rectangle.y + rectangle.height);
2609 }
2610
2611 static gint
2612 gtk_notebook_motion_notify (GtkWidget      *widget,
2613                             GdkEventMotion *event)
2614 {
2615   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2616   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
2617   GtkNotebookPointerPosition pointer_position;
2618   GtkSettings *settings;
2619   guint        timeout;
2620   GList       *element;
2621
2622   if (priv->pressed_button == -1)
2623     return FALSE;
2624
2625   if (!notebook->cur_page)
2626     return FALSE;
2627
2628   priv->mouse_x = (gint) event->x;
2629   priv->mouse_y = (gint) event->y;
2630
2631   if (notebook->cur_page->detachable &&
2632       check_threshold (notebook, priv->mouse_x, priv->mouse_y))
2633     {
2634       /* move the page to the current position */
2635       element = get_drop_position (notebook,
2636                                    notebook->cur_page->pack,
2637                                    PAGE_MIDDLE_X (notebook->cur_page),
2638                                    PAGE_MIDDLE_Y (notebook->cur_page));
2639       reorder_tab (notebook, element, notebook->focus_tab);
2640       priv->during_detach = TRUE;
2641
2642       gtk_drag_begin (widget, priv->source_targets, GDK_ACTION_MOVE,
2643                       priv->pressed_button, (GdkEvent*) event);
2644       return TRUE;
2645     }
2646
2647   if (notebook->cur_page->reorderable)
2648     {
2649       pointer_position = get_pointer_position (notebook);
2650
2651       if (pointer_position != POINTER_BETWEEN &&
2652           gtk_notebook_show_arrows (notebook))
2653         {
2654           if (!priv->dnd_timer)
2655             {
2656               priv->has_scrolled = TRUE;
2657               settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
2658               g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
2659
2660               priv->dnd_timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
2661                                                (GSourceFunc) scroll_notebook_timer, 
2662                                                (gpointer) notebook);
2663             }
2664         }
2665       else
2666         {
2667           if (priv->dnd_timer)
2668             {
2669               g_source_remove (priv->dnd_timer);
2670               priv->dnd_timer = 0;
2671             }
2672         }
2673
2674       gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_REORDER);
2675     }
2676
2677   return TRUE;
2678 }
2679
2680 static void
2681 gtk_notebook_grab_notify (GtkWidget *widget,
2682                           gboolean   was_grabbed)
2683 {
2684   if (!was_grabbed)
2685     stop_scrolling (GTK_NOTEBOOK (widget));
2686 }
2687
2688 static void
2689 gtk_notebook_state_changed (GtkWidget    *widget,
2690                             GtkStateType  previous_state)
2691 {
2692   if (!GTK_WIDGET_IS_SENSITIVE (widget)) 
2693     stop_scrolling (GTK_NOTEBOOK (widget));
2694 }
2695
2696 static gint
2697 gtk_notebook_focus_in (GtkWidget     *widget,
2698                        GdkEventFocus *event)
2699 {
2700   GTK_NOTEBOOK (widget)->child_has_focus = FALSE;
2701
2702   gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2703   
2704   return FALSE;
2705 }
2706
2707 static gint
2708 gtk_notebook_focus_out (GtkWidget     *widget,
2709                         GdkEventFocus *event)
2710 {
2711   gtk_notebook_redraw_tabs (GTK_NOTEBOOK (widget));
2712
2713   return FALSE;
2714 }
2715
2716 static void
2717 gtk_notebook_draw_focus (GtkWidget *widget)
2718 {
2719   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
2720
2721   if (GTK_WIDGET_DRAWABLE (widget) && notebook->show_tabs &&
2722       notebook->focus_tab)
2723     {
2724       GtkNotebookPage *page;
2725       GdkRectangle area;
2726       gint focus_width;
2727       
2728       gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
2729
2730       page = notebook->focus_tab->data;
2731
2732       area.x = page->tab_label->allocation.x - focus_width;
2733       area.y = page->tab_label->allocation.y - focus_width;
2734       area.width = page->tab_label->allocation.width + 2 * focus_width;
2735       area.height = page->tab_label->allocation.height + 2 * focus_width;
2736
2737       gtk_notebook_draw_tab (GTK_NOTEBOOK (widget), page, &area);
2738     }
2739 }
2740
2741 static void
2742 gtk_notebook_style_set  (GtkWidget *widget,
2743                          GtkStyle  *previous)
2744 {
2745   GtkNotebook *notebook;
2746
2747   gboolean has_before_previous;
2748   gboolean has_before_next;
2749   gboolean has_after_previous;
2750   gboolean has_after_next;
2751
2752   notebook = GTK_NOTEBOOK (widget);
2753   
2754   gtk_widget_style_get (widget,
2755                         "has-backward-stepper", &has_before_previous,
2756                         "has-secondary-forward-stepper", &has_before_next,
2757                         "has-secondary-backward-stepper", &has_after_previous,
2758                         "has-forward-stepper", &has_after_next,
2759                         NULL);
2760   
2761   notebook->has_before_previous = has_before_previous;
2762   notebook->has_before_next = has_before_next;
2763   notebook->has_after_previous = has_after_previous;
2764   notebook->has_after_next = has_after_next;
2765   
2766   (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, previous);
2767 }
2768
2769 static void
2770 gtk_notebook_drag_begin (GtkWidget        *widget,
2771                          GdkDragContext   *context)
2772 {
2773   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
2774   GtkNotebook *notebook = (GtkNotebook*) widget;
2775   GtkWidget *tab_label;
2776   GdkPixmap *pixmap;
2777
2778   if (priv->dnd_timer)
2779     {
2780       g_source_remove (priv->dnd_timer);
2781       priv->dnd_timer = 0;
2782     }
2783
2784   tab_label = notebook->cur_page->tab_label;
2785
2786   pixmap = gdk_pixmap_new (tab_label->window,
2787                            tab_label->allocation.width + 2,
2788                            tab_label->allocation.height + 2,
2789                            -1);
2790
2791   gdk_draw_drawable (pixmap,
2792                      tab_label->style->base_gc [GTK_WIDGET_STATE (widget)],
2793                      tab_label->window,
2794                      tab_label->allocation.x,
2795                      tab_label->allocation.y,
2796                      1, 1, -1, -1);
2797
2798   gdk_draw_rectangle (pixmap,
2799                       widget->style->black_gc,
2800                       FALSE,
2801                       0, 0,
2802                       tab_label->allocation.width + 1,
2803                       tab_label->allocation.height + 1);
2804
2805   gtk_drag_set_icon_pixmap (context,
2806                             gdk_drawable_get_colormap (pixmap),
2807                             pixmap,
2808                             NULL,
2809                             -2, -2);
2810
2811   gtk_notebook_pages_allocate (GTK_NOTEBOOK (widget), DRAG_OPERATION_DETACH);
2812 }
2813
2814 static gboolean
2815 gtk_notebook_drag_motion (GtkWidget      *widget,
2816                           GdkDragContext *context,
2817                           gint            x,
2818                           gint            y,
2819                           guint           time)
2820 {
2821   GtkWidget *source_widget;
2822   gint widget_group, source_widget_group;
2823   
2824   source_widget = gtk_drag_get_source_widget (context);
2825   
2826   g_assert (source_widget);
2827
2828   widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (widget));
2829   source_widget_group = gtk_notebook_get_group_id (GTK_NOTEBOOK (source_widget));
2830
2831   if (widget_group != -1 &&
2832       source_widget_group != -1 &&
2833       widget_group == source_widget_group)
2834     return TRUE;
2835
2836   gdk_drag_status (context, 0, time);
2837
2838   return FALSE;
2839 }
2840
2841 static gboolean
2842 gtk_notebook_drag_drop (GtkWidget        *widget,
2843                         GdkDragContext   *context,
2844                         gint              x,
2845                         gint              y,
2846                         guint             time)
2847 {
2848   GdkAtom target;
2849
2850   target = gtk_drag_dest_find_target (widget, context, NULL);
2851
2852   if (target == GDK_NONE)
2853     gtk_drag_finish (context, FALSE, FALSE, time);
2854
2855   return TRUE;
2856 }
2857
2858 static void
2859 do_detach_tab (GtkNotebook     *from,
2860                GtkNotebook     *to,
2861                GtkNotebookPage *page_info,
2862                gint             x,
2863                gint             y)
2864 {
2865   GtkWidget *child, *tab_label, *menu_label;
2866   gboolean tab_expand, tab_fill, reorderable, detachable;
2867   GList *element;
2868   guint tab_pack;
2869   gint page_num;
2870
2871   menu_label = tab_label = child = NULL;
2872
2873   if (page_info->menu_label)
2874     menu_label = g_object_ref (page_info->menu_label);
2875
2876   if (page_info->tab_label)
2877     tab_label = g_object_ref (page_info->tab_label);
2878
2879   if (page_info->child)
2880     child = g_object_ref (page_info->child);
2881
2882   /* preserve properties */
2883   tab_expand = page_info->expand;
2884   tab_fill = page_info->fill;
2885   tab_pack = page_info->pack;
2886   reorderable = page_info->reorderable;
2887   detachable = page_info->detachable;
2888
2889   gtk_container_remove (GTK_CONTAINER (from), child);
2890
2891   element = get_drop_position (to,
2892                                tab_pack,
2893                                GTK_WIDGET (to)->allocation.x + x,
2894                                GTK_WIDGET (to)->allocation.y + y);
2895
2896   page_num = g_list_position (to->children, element);
2897   gtk_notebook_insert_page_menu (to, child, tab_label, menu_label, page_num);
2898
2899   gtk_container_child_set (GTK_CONTAINER (to), child,
2900                            "tab-pack", tab_pack,
2901                            "tab-expand", tab_expand,
2902                            "tab-fill", tab_fill,
2903                            "reorderable", reorderable,
2904                            "detachable", detachable,
2905                            NULL);
2906   if (child)
2907     g_object_unref (child);
2908
2909   if (tab_label)
2910     g_object_unref (tab_label);
2911
2912   if (menu_label)
2913     g_object_unref (menu_label);
2914
2915   gtk_notebook_set_current_page (to, page_num);
2916 }
2917
2918 static void
2919 gtk_notebook_drag_data_get (GtkWidget        *widget,
2920                             GdkDragContext   *context,
2921                             GtkSelectionData *data,
2922                             guint             info,
2923                             guint             time)
2924 {
2925   GtkNotebook *dest_notebook, *notebook;
2926   gint page_num;
2927
2928   if (data->target != gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB") &&
2929       (data->target != gdk_atom_intern_static_string ("application/x-rootwindow-drop") ||
2930        !window_creation_hook))
2931     return;
2932
2933   notebook = GTK_NOTEBOOK (widget);
2934   page_num = g_list_index (notebook->children, notebook->cur_page);
2935
2936   if (data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
2937     {
2938       gtk_selection_data_set (data,
2939                               data->target,
2940                               8,
2941                               (void*) notebook->cur_page,
2942                               sizeof (GtkNotebookPage));
2943     }
2944   else
2945     {
2946       GdkDisplay *display;
2947       gint x, y;
2948
2949       display = gtk_widget_get_display (widget);
2950       gdk_display_get_pointer (display, NULL, &x, &y, NULL);
2951
2952       dest_notebook = (* window_creation_hook) (notebook,
2953                                                 notebook->cur_page->child,
2954                                                 x, y,
2955                                                 window_creation_hook_data);
2956
2957       if (dest_notebook)
2958         do_detach_tab (notebook, dest_notebook, notebook->cur_page, 0, 0);
2959     }
2960 }
2961
2962 static void
2963 gtk_notebook_drag_data_received (GtkWidget        *widget,
2964                                  GdkDragContext   *context,
2965                                  gint              x,
2966                                  gint              y,
2967                                  GtkSelectionData *data,
2968                                  guint             info,
2969                                  guint             time)
2970 {
2971   GtkNotebook *notebook;
2972   GtkWidget *source_widget;
2973   GtkNotebookPage *page_info;
2974
2975   notebook = GTK_NOTEBOOK (widget);
2976   source_widget = gtk_drag_get_source_widget (context);
2977
2978   if (source_widget &&
2979       data->target == gdk_atom_intern_static_string ("GTK_NOTEBOOK_TAB"))
2980     {
2981       page_info = (void*) data->data;
2982
2983       do_detach_tab (GTK_NOTEBOOK (source_widget), notebook, page_info, x, y);
2984       gtk_drag_finish (context, TRUE, FALSE, time);
2985     }
2986
2987   gtk_drag_finish (context, FALSE, FALSE, time);
2988 }
2989
2990 /* Private GtkContainer Methods :
2991  * 
2992  * gtk_notebook_set_child_arg
2993  * gtk_notebook_get_child_arg
2994  * gtk_notebook_add
2995  * gtk_notebook_remove
2996  * gtk_notebook_focus
2997  * gtk_notebook_set_focus_child
2998  * gtk_notebook_child_type
2999  * gtk_notebook_forall
3000  */
3001 static void
3002 gtk_notebook_set_child_property (GtkContainer    *container,
3003                                  GtkWidget       *child,
3004                                  guint            property_id,
3005                                  const GValue    *value,
3006                                  GParamSpec      *pspec)
3007 {
3008   gboolean expand;
3009   gboolean fill;
3010   GtkPackType pack_type;
3011
3012   /* not finding child's page is valid for menus or labels */
3013   if (!gtk_notebook_find_child (GTK_NOTEBOOK (container), child, NULL))
3014     return;
3015
3016   switch (property_id)
3017     {
3018     case CHILD_PROP_TAB_LABEL:
3019       /* a NULL pointer indicates a default_tab setting, otherwise
3020        * we need to set the associated label
3021        */
3022       gtk_notebook_set_tab_label_text (GTK_NOTEBOOK (container), child,
3023                                        g_value_get_string (value));
3024       break;
3025     case CHILD_PROP_MENU_LABEL:
3026       gtk_notebook_set_menu_label_text (GTK_NOTEBOOK (container), child,
3027                                         g_value_get_string (value));
3028       break;
3029     case CHILD_PROP_POSITION:
3030       gtk_notebook_reorder_child (GTK_NOTEBOOK (container), child,
3031                                   g_value_get_int (value));
3032       break;
3033     case CHILD_PROP_TAB_EXPAND:
3034       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3035                                             &expand, &fill, &pack_type);
3036       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3037                                           g_value_get_boolean (value),
3038                                           fill, pack_type);
3039       break;
3040     case CHILD_PROP_TAB_FILL:
3041       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3042                                             &expand, &fill, &pack_type);
3043       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3044                                           expand,
3045                                           g_value_get_boolean (value),
3046                                           pack_type);
3047       break;
3048     case CHILD_PROP_TAB_PACK:
3049       gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3050                                             &expand, &fill, &pack_type);
3051       gtk_notebook_set_tab_label_packing (GTK_NOTEBOOK (container), child,
3052                                           expand, fill,
3053                                           g_value_get_enum (value));
3054       break;
3055     case CHILD_PROP_REORDERABLE:
3056       gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (container), child,
3057                                         g_value_get_boolean (value));
3058       break;
3059     case CHILD_PROP_DETACHABLE:
3060       gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (container), child,
3061                                        g_value_get_boolean (value));
3062       break;
3063     default:
3064       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3065       break;
3066     }
3067 }
3068
3069 static void
3070 gtk_notebook_get_child_property (GtkContainer    *container,
3071                                  GtkWidget       *child,
3072                                  guint            property_id,
3073                                  GValue          *value,
3074                                  GParamSpec      *pspec)
3075 {
3076   GList *list;
3077   GtkNotebook *notebook;
3078   GtkWidget *label;
3079   gboolean expand;
3080   gboolean fill;
3081   GtkPackType pack_type;
3082
3083   notebook = GTK_NOTEBOOK (container);
3084
3085   /* not finding child's page is valid for menus or labels */
3086   list = gtk_notebook_find_child (notebook, child, NULL);
3087   if (!list)
3088     {
3089       /* nothing to set on labels or menus */
3090       g_param_value_set_default (pspec, value);
3091       return;
3092     }
3093
3094   switch (property_id)
3095     {
3096     case CHILD_PROP_TAB_LABEL:
3097       label = gtk_notebook_get_tab_label (notebook, child);
3098
3099       if (label && GTK_IS_LABEL (label))
3100         g_value_set_string (value, GTK_LABEL (label)->label);
3101       else
3102         g_value_set_string (value, NULL);
3103       break;
3104     case CHILD_PROP_MENU_LABEL:
3105       label = gtk_notebook_get_menu_label (notebook, child);
3106
3107       if (label && GTK_IS_LABEL (label))
3108         g_value_set_string (value, GTK_LABEL (label)->label);
3109       else
3110         g_value_set_string (value, NULL);
3111       break;
3112     case CHILD_PROP_POSITION:
3113       g_value_set_int (value, g_list_position (notebook->children, list));
3114       break;
3115     case CHILD_PROP_TAB_EXPAND:
3116         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3117                                               &expand, NULL, NULL);
3118         g_value_set_boolean (value, expand);
3119       break;
3120     case CHILD_PROP_TAB_FILL:
3121         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3122                                               NULL, &fill, NULL);
3123         g_value_set_boolean (value, fill);
3124       break;
3125     case CHILD_PROP_TAB_PACK:
3126         gtk_notebook_query_tab_label_packing (GTK_NOTEBOOK (container), child,
3127                                               NULL, NULL, &pack_type);
3128         g_value_set_enum (value, pack_type);
3129       break;
3130     case CHILD_PROP_REORDERABLE:
3131       g_value_set_boolean (value,
3132                            gtk_notebook_get_tab_reorderable (GTK_NOTEBOOK (container), child));
3133       break;
3134     case CHILD_PROP_DETACHABLE:
3135       g_value_set_boolean (value,
3136                            gtk_notebook_get_tab_detachable (GTK_NOTEBOOK (container), child));
3137       break;
3138     default:
3139       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
3140       break;
3141     }
3142 }
3143
3144 static void
3145 gtk_notebook_add (GtkContainer *container,
3146                   GtkWidget    *widget)
3147 {
3148   g_return_if_fail (GTK_IS_NOTEBOOK (container));
3149
3150   gtk_notebook_insert_page_menu (GTK_NOTEBOOK (container), widget, 
3151                                  NULL, NULL, -1);
3152 }
3153
3154 static void
3155 gtk_notebook_remove (GtkContainer *container,
3156                      GtkWidget    *widget)
3157 {
3158   GtkNotebook *notebook;
3159   GtkNotebookPage *page;
3160   GList *children;
3161   gint page_num = 0;
3162
3163   g_return_if_fail (GTK_IS_NOTEBOOK (container));
3164   g_return_if_fail (widget != NULL);
3165
3166   notebook = GTK_NOTEBOOK (container);
3167
3168   children = notebook->children;
3169   while (children)
3170     {
3171       page = children->data;
3172
3173       if (page->child == widget)
3174         break;
3175
3176       page_num++;
3177       children = children->next;
3178     }
3179
3180   g_signal_emit (notebook,
3181                  notebook_signals[TAB_REMOVED],
3182                  0,
3183                  widget,
3184                  page_num);
3185
3186   gtk_notebook_real_remove (notebook, children, FALSE);
3187 }
3188
3189 static gboolean
3190 focus_tabs_in (GtkNotebook *notebook)
3191 {
3192   if (notebook->show_tabs && notebook->cur_page)
3193     {
3194       gtk_widget_grab_focus (GTK_WIDGET (notebook));
3195
3196       gtk_notebook_switch_focus_tab (notebook,
3197                                      g_list_find (notebook->children,
3198                                                   notebook->cur_page));
3199
3200       return TRUE;
3201     }
3202   else
3203     return FALSE;
3204 }
3205
3206 static gboolean
3207 focus_tabs_move (GtkNotebook     *notebook,
3208                  GtkDirectionType direction,
3209                  gint             search_direction)
3210 {
3211   GList *new_page;
3212
3213   new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
3214                                        search_direction, TRUE);
3215   if (new_page)
3216     gtk_notebook_switch_focus_tab (notebook, new_page);
3217   else
3218     gdk_display_beep (gtk_widget_get_display (GTK_WIDGET (notebook)));
3219   
3220   return TRUE;
3221 }
3222
3223 static gboolean
3224 focus_child_in (GtkNotebook     *notebook,
3225                 GtkDirectionType direction)
3226 {
3227   if (notebook->cur_page)
3228     return gtk_widget_child_focus (notebook->cur_page->child, direction);
3229   else
3230     return FALSE;
3231 }
3232
3233 /* Focus in the notebook can either be on the pages, or on
3234  * the tabs.
3235  */
3236 static gint
3237 gtk_notebook_focus (GtkWidget        *widget,
3238                     GtkDirectionType  direction)
3239 {
3240   GtkWidget *old_focus_child;
3241   GtkNotebook *notebook;
3242   GtkDirectionType effective_direction;
3243
3244   gboolean widget_is_focus;
3245   GtkContainer *container;
3246
3247   g_return_val_if_fail (GTK_IS_NOTEBOOK (widget), FALSE);
3248
3249   container = GTK_CONTAINER (widget);
3250   notebook = GTK_NOTEBOOK (container);
3251
3252   if (notebook->focus_out)
3253     {
3254       notebook->focus_out = FALSE; /* Clear this to catch the wrap-around case */
3255       return FALSE;
3256     }
3257
3258   widget_is_focus = gtk_widget_is_focus (widget);
3259   old_focus_child = container->focus_child; 
3260
3261   effective_direction = get_effective_direction (notebook, direction);
3262
3263   if (old_focus_child)          /* Focus on page child */
3264     {
3265       if (gtk_widget_child_focus (old_focus_child, direction))
3266         return TRUE;
3267       
3268       switch (effective_direction)
3269         {
3270         case GTK_DIR_TAB_BACKWARD:
3271         case GTK_DIR_UP:
3272           /* Focus onto the tabs */
3273           return focus_tabs_in (notebook);
3274         case GTK_DIR_DOWN:
3275         case GTK_DIR_TAB_FORWARD:
3276         case GTK_DIR_LEFT:
3277         case GTK_DIR_RIGHT:
3278           return FALSE;
3279         }
3280     }
3281   else if (widget_is_focus)     /* Focus was on tabs */
3282     {
3283       switch (effective_direction)
3284         {
3285         case GTK_DIR_TAB_BACKWARD:
3286         case GTK_DIR_UP:
3287           return FALSE;
3288         case GTK_DIR_TAB_FORWARD:
3289         case GTK_DIR_DOWN:
3290           /* We use TAB_FORWARD rather than direction so that we focus a more
3291            * predictable widget for the user; users may be using arrow focusing
3292            * in this situation even if they don't usually use arrow focusing.
3293            */
3294           return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
3295         case GTK_DIR_LEFT:
3296           return focus_tabs_move (notebook, direction, STEP_PREV);
3297         case GTK_DIR_RIGHT:
3298           return focus_tabs_move (notebook, direction, STEP_NEXT);
3299         }
3300     }
3301   else /* Focus was not on widget */
3302     {
3303       switch (effective_direction)
3304         {
3305         case GTK_DIR_TAB_FORWARD:
3306         case GTK_DIR_DOWN:
3307           if (focus_tabs_in (notebook))
3308             return TRUE;
3309           if (focus_child_in (notebook, direction))
3310             return TRUE;
3311           return FALSE;
3312         case GTK_DIR_TAB_BACKWARD:
3313         case GTK_DIR_UP:
3314           if (focus_child_in (notebook, direction))
3315             return TRUE;
3316           if (focus_tabs_in (notebook))
3317             return TRUE;
3318           return FALSE;
3319         case GTK_DIR_LEFT:
3320         case GTK_DIR_RIGHT:
3321           return focus_child_in (notebook, direction);
3322         }
3323     }
3324
3325   g_assert_not_reached ();
3326   return FALSE;
3327 }  
3328
3329 static void
3330 gtk_notebook_set_focus_child (GtkContainer *container,
3331                               GtkWidget    *child)
3332 {
3333   GtkNotebook *notebook = GTK_NOTEBOOK (container);
3334   GtkWidget *page_child;
3335   GtkWidget *toplevel;
3336
3337   /* If the old focus widget was within a page of the notebook,
3338    * (child may either be NULL or not in this case), record it
3339    * for future use if we switch to the page with a mnemonic.
3340    */
3341
3342   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
3343   if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel))
3344     {
3345       page_child = GTK_WINDOW (toplevel)->focus_widget; 
3346       while (page_child)
3347         {
3348           if (page_child->parent == GTK_WIDGET (container))
3349             {
3350               GList *list = gtk_notebook_find_child (notebook, page_child, NULL);
3351               if (list != NULL) 
3352                 {
3353                   GtkNotebookPage *page = list->data;
3354               
3355                   if (page->last_focus_child)
3356                     g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3357                   
3358                   page->last_focus_child = GTK_WINDOW (toplevel)->focus_widget;
3359                   g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3360               
3361                   break;
3362                 }
3363             }
3364
3365           page_child = page_child->parent;
3366         }
3367     }
3368   
3369   if (child)
3370     {
3371       g_return_if_fail (GTK_IS_WIDGET (child));
3372
3373       notebook->child_has_focus = TRUE;
3374       if (!notebook->focus_tab)
3375         {
3376           GList *children;
3377           GtkNotebookPage *page;
3378
3379           children = notebook->children;
3380           while (children)
3381             {
3382               page = children->data;
3383               if (page->child == child || page->tab_label == child)
3384                 gtk_notebook_switch_focus_tab (notebook, children);
3385               children = children->next;
3386             }
3387         }
3388     }
3389
3390   parent_class->set_focus_child (container, child);
3391 }
3392
3393 static void
3394 gtk_notebook_forall (GtkContainer *container,
3395                      gboolean      include_internals,
3396                      GtkCallback   callback,
3397                      gpointer      callback_data)
3398 {
3399   GtkNotebook *notebook;
3400   GList *children;
3401
3402   g_return_if_fail (GTK_IS_NOTEBOOK (container));
3403   g_return_if_fail (callback != NULL);
3404
3405   notebook = GTK_NOTEBOOK (container);
3406
3407   children = notebook->children;
3408   while (children)
3409     {
3410       GtkNotebookPage *page;
3411       
3412       page = children->data;
3413       children = children->next;
3414       (* callback) (page->child, callback_data);
3415       if (include_internals)
3416         {
3417           if (page->tab_label)
3418             (* callback) (page->tab_label, callback_data);
3419         }
3420     }
3421 }
3422
3423 static GType
3424 gtk_notebook_child_type (GtkContainer     *container)
3425 {
3426   return GTK_TYPE_WIDGET;
3427 }
3428
3429 /* Private GtkNotebook Methods:
3430  *
3431  * gtk_notebook_real_insert_page
3432  */
3433 static void
3434 page_visible_cb (GtkWidget  *page,
3435                  GParamSpec *arg,
3436                  gpointer    data)
3437 {
3438   GtkNotebook *notebook = (GtkNotebook *)data;
3439   GList *list;
3440   GList *next = NULL;
3441
3442   if (notebook->cur_page &&
3443       notebook->cur_page->child == page &&
3444       !GTK_WIDGET_VISIBLE (page))
3445     {
3446       list = g_list_find (notebook->children, notebook->cur_page);
3447       if (list)
3448         {
3449           next = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
3450           if (!next)
3451             next = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
3452         }
3453
3454       if (next)
3455         gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next), -1);
3456     }
3457 }
3458
3459 static gint
3460 gtk_notebook_real_insert_page (GtkNotebook *notebook,
3461                                GtkWidget   *child,
3462                                GtkWidget   *tab_label,
3463                                GtkWidget   *menu_label,
3464                                gint         position)
3465 {
3466   GtkNotebookPage *page;
3467   gint nchildren;
3468
3469   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3470   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
3471   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
3472   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
3473
3474   gtk_widget_freeze_child_notify (child);
3475   
3476   page = g_new (GtkNotebookPage, 1);
3477   page->child = child;
3478   page->last_focus_child = NULL;
3479   page->requisition.width = 0;
3480   page->requisition.height = 0;
3481   page->allocation.x = 0;
3482   page->allocation.y = 0;
3483   page->allocation.width = 0;
3484   page->allocation.height = 0;
3485   page->default_menu = FALSE;
3486   page->default_tab = FALSE;
3487   page->mnemonic_activate_signal = 0;
3488   page->reorderable = FALSE;
3489   page->detachable = FALSE;
3490    
3491   nchildren = g_list_length (notebook->children);
3492   if ((position < 0) || (position > nchildren))
3493     position = nchildren;
3494
3495   notebook->children = g_list_insert (notebook->children, page, position);
3496
3497   if (!tab_label)
3498     {
3499       page->default_tab = TRUE;
3500       if (notebook->show_tabs)
3501         tab_label = gtk_label_new ("");
3502     }
3503   page->tab_label = tab_label;
3504   page->menu_label = menu_label;
3505   page->expand = FALSE;
3506   page->fill = TRUE;
3507   page->pack = GTK_PACK_START; 
3508
3509   if (!menu_label)
3510     page->default_menu = TRUE;
3511   else  
3512     {
3513       g_object_ref_sink (page->menu_label);
3514     }
3515
3516   if (notebook->menu)
3517     gtk_notebook_menu_item_create (notebook,
3518                                    g_list_find (notebook->children, page));
3519
3520   gtk_widget_set_parent (child, GTK_WIDGET (notebook));
3521   if (tab_label)
3522     gtk_widget_set_parent (tab_label, GTK_WIDGET (notebook));
3523
3524   gtk_notebook_update_labels (notebook);
3525
3526   if (!notebook->first_tab)
3527     notebook->first_tab = notebook->children;
3528
3529   /* child visible will be turned on by switch_page below */
3530   gtk_widget_set_child_visible (child, FALSE);
3531   
3532   if (tab_label)
3533     {
3534       if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
3535         gtk_widget_show (tab_label);
3536       else
3537         gtk_widget_hide (tab_label);
3538     }
3539
3540   if (!notebook->cur_page)
3541     {
3542       gtk_notebook_switch_page (notebook, page, 0);
3543       gtk_notebook_switch_focus_tab (notebook, NULL);
3544     }
3545
3546   page->notify_visible_handler = g_signal_connect (G_OBJECT (child), "notify::visible",
3547                                                    G_CALLBACK (page_visible_cb), notebook);
3548   gtk_notebook_update_tab_states (notebook);
3549
3550   if (tab_label)
3551     page->mnemonic_activate_signal =
3552       g_signal_connect (tab_label,
3553                         "mnemonic_activate",
3554                         G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
3555                         notebook);
3556
3557   gtk_widget_child_notify (child, "tab-expand");
3558   gtk_widget_child_notify (child, "tab-fill");
3559   gtk_widget_child_notify (child, "tab-pack");
3560   gtk_widget_child_notify (child, "tab-label");
3561   gtk_widget_child_notify (child, "menu-label");
3562   gtk_widget_child_notify (child, "position");
3563   gtk_widget_thaw_child_notify (child);
3564
3565   g_signal_emit (notebook,
3566                  notebook_signals[TAB_ADDED],
3567                  0,
3568                  child,
3569                  position);
3570
3571   return position;
3572 }
3573
3574 /* Private GtkNotebook Functions:
3575  *
3576  * gtk_notebook_redraw_tabs
3577  * gtk_notebook_real_remove
3578  * gtk_notebook_update_labels
3579  * gtk_notebook_timer
3580  * gtk_notebook_page_compare
3581  * gtk_notebook_real_page_position
3582  * gtk_notebook_search_page
3583  */
3584 static void
3585 gtk_notebook_redraw_tabs (GtkNotebook *notebook)
3586 {
3587   GtkWidget *widget;
3588   GtkNotebookPage *page;
3589   GdkRectangle redraw_rect;
3590   gint border;
3591   gint tab_pos = get_effective_tab_pos (notebook);
3592
3593   widget = GTK_WIDGET (notebook);
3594   border = GTK_CONTAINER (notebook)->border_width;
3595
3596   if (!GTK_WIDGET_MAPPED (notebook) || !notebook->first_tab)
3597     return;
3598
3599   page = notebook->first_tab->data;
3600
3601   redraw_rect.x = border;
3602   redraw_rect.y = border;
3603
3604   switch (tab_pos)
3605     {
3606     case GTK_POS_BOTTOM:
3607       redraw_rect.y = (widget->allocation.height - border -
3608                        page->allocation.height -
3609                        widget->style->ythickness);
3610       if (page != notebook->cur_page)
3611         redraw_rect.y -= widget->style->ythickness;
3612       /* fall through */
3613     case GTK_POS_TOP:
3614       redraw_rect.width = widget->allocation.width - 2 * border;
3615       redraw_rect.height = (page->allocation.height +
3616                             widget->style->ythickness);
3617       if (page != notebook->cur_page)
3618         redraw_rect.height += widget->style->ythickness;
3619       break;
3620     case GTK_POS_RIGHT:
3621       redraw_rect.x = (widget->allocation.width - border -
3622                        page->allocation.width -
3623                        widget->style->xthickness);
3624       if (page != notebook->cur_page)
3625         redraw_rect.x -= widget->style->xthickness;
3626       /* fall through */
3627     case GTK_POS_LEFT:
3628       redraw_rect.width = (page->allocation.width +
3629                            widget->style->xthickness);
3630       redraw_rect.height = widget->allocation.height - 2 * border;
3631       if (page != notebook->cur_page)
3632         redraw_rect.width += widget->style->xthickness;
3633       break;
3634     }
3635
3636   redraw_rect.x += widget->allocation.x;
3637   redraw_rect.y += widget->allocation.y;
3638
3639   gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE);
3640 }
3641
3642 static void
3643 gtk_notebook_redraw_arrows (GtkNotebook *notebook)
3644 {
3645   if (GTK_WIDGET_MAPPED (notebook) && gtk_notebook_show_arrows (notebook))
3646     {
3647       GdkRectangle rect;
3648       gint i;
3649       GtkNotebookArrow arrow[4];
3650
3651       arrow[0] = notebook->has_before_previous ? ARROW_LEFT_BEFORE : ARROW_NONE;
3652       arrow[1] = notebook->has_before_next ? ARROW_RIGHT_BEFORE : ARROW_NONE;
3653       arrow[2] = notebook->has_after_previous ? ARROW_LEFT_AFTER : ARROW_NONE;
3654       arrow[3] = notebook->has_after_next ? ARROW_RIGHT_AFTER : ARROW_NONE;
3655
3656       for (i = 0; i < 4; i++) 
3657         {
3658           if (arrow[i] == ARROW_NONE)
3659             continue;
3660
3661           gtk_notebook_get_arrow_rect (notebook, &rect, arrow[i]);
3662           gdk_window_invalidate_rect (GTK_WIDGET (notebook)->window, 
3663                                       &rect, FALSE);
3664         }
3665     }
3666 }
3667
3668 static gint
3669 gtk_notebook_timer (GtkNotebook *notebook)
3670 {
3671   gboolean retval = FALSE;
3672
3673   GDK_THREADS_ENTER ();
3674
3675   if (notebook->timer)
3676     {
3677       gtk_notebook_do_arrow (notebook, notebook->click_child);
3678
3679       if (notebook->need_timer)
3680         {
3681           GtkSettings *settings;
3682           guint        timeout;
3683
3684           settings = gtk_widget_get_settings (GTK_WIDGET (notebook));
3685           g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);
3686
3687           notebook->need_timer = FALSE;
3688           notebook->timer = g_timeout_add (timeout * SCROLL_DELAY_FACTOR,
3689                                            (GSourceFunc) gtk_notebook_timer,
3690                                            (gpointer) notebook);
3691         }
3692       else
3693         retval = TRUE;
3694     }
3695
3696   GDK_THREADS_LEAVE ();
3697
3698   return retval;
3699 }
3700
3701 static gint
3702 gtk_notebook_page_compare (gconstpointer a,
3703                            gconstpointer b)
3704 {
3705   return (((GtkNotebookPage *) a)->child != b);
3706 }
3707
3708 static GList*
3709 gtk_notebook_find_child (GtkNotebook *notebook,
3710                          GtkWidget   *child,
3711                          const gchar *function)
3712 {
3713   GList *list = g_list_find_custom (notebook->children, child,
3714                                     gtk_notebook_page_compare);
3715
3716 #ifndef G_DISABLE_CHECKS
3717   if (!list && function)
3718     g_warning ("%s: unable to find child %p in notebook %p",
3719                function, child, notebook);
3720 #endif
3721
3722   return list;
3723 }
3724
3725 static void
3726 gtk_notebook_remove_tab_label (GtkNotebook     *notebook,
3727                                GtkNotebookPage *page)
3728 {
3729   if (page->tab_label)
3730     {
3731       if (page->mnemonic_activate_signal)
3732         g_signal_handler_disconnect (page->tab_label,
3733                                      page->mnemonic_activate_signal);
3734       page->mnemonic_activate_signal = 0;
3735
3736       gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
3737       gtk_widget_unparent (page->tab_label);
3738     }
3739 }
3740
3741 static void
3742 gtk_notebook_real_remove (GtkNotebook *notebook,
3743                           GList       *list,
3744                           gboolean     destroying)
3745 {
3746   GtkNotebookPage *page;
3747   GList * next_list;
3748   gint need_resize = FALSE;
3749
3750   next_list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
3751   if (!next_list)
3752     next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
3753
3754   if (notebook->cur_page == list->data)
3755     { 
3756       notebook->cur_page = NULL;
3757       if (next_list && !destroying)
3758         gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list), -1);
3759     }
3760
3761   if (list == notebook->first_tab)
3762     notebook->first_tab = next_list;
3763   if (list == notebook->focus_tab && !destroying)
3764     gtk_notebook_switch_focus_tab (notebook, next_list);
3765
3766   page = list->data;
3767   
3768   g_signal_handler_disconnect (page->child, page->notify_visible_handler); 
3769
3770   if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
3771     need_resize = TRUE;
3772
3773   gtk_widget_unparent (page->child);
3774
3775   gtk_notebook_remove_tab_label (notebook, page);
3776   
3777   if (notebook->menu)
3778     {
3779       gtk_container_remove (GTK_CONTAINER (notebook->menu), 
3780                             page->menu_label->parent);
3781       gtk_widget_queue_resize (notebook->menu);
3782     }
3783   if (!page->default_menu)
3784     g_object_unref (page->menu_label);
3785   
3786   notebook->children = g_list_remove_link (notebook->children, list);
3787   g_list_free (list);
3788
3789   if (page->last_focus_child)
3790     {
3791       g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
3792       page->last_focus_child = NULL;
3793     }
3794   
3795   g_free (page);
3796
3797   gtk_notebook_update_labels (notebook);
3798   if (need_resize)
3799     gtk_widget_queue_resize (GTK_WIDGET (notebook));
3800 }
3801
3802 static void
3803 gtk_notebook_update_labels (GtkNotebook *notebook)
3804 {
3805   GtkNotebookPage *page;
3806   GList *list;
3807   gchar string[32];
3808   gint page_num = 1;
3809
3810   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
3811        list;
3812        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
3813     {
3814       page = list->data;
3815       g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
3816       if (notebook->show_tabs)
3817         {
3818           if (page->default_tab)
3819             {
3820               if (!page->tab_label)
3821                 {
3822                   page->tab_label = gtk_label_new (string);
3823                   gtk_widget_set_parent (page->tab_label,
3824                                          GTK_WIDGET (notebook));
3825                 }
3826               else
3827                 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
3828             }
3829
3830           if (GTK_WIDGET_VISIBLE (page->child) &&
3831               !GTK_WIDGET_VISIBLE (page->tab_label))
3832             gtk_widget_show (page->tab_label);
3833           else if (!GTK_WIDGET_VISIBLE (page->child) &&
3834                    GTK_WIDGET_VISIBLE (page->tab_label))
3835             gtk_widget_hide (page->tab_label);
3836         }
3837       if (notebook->menu && page->default_menu)
3838         {
3839           if (page->tab_label && GTK_IS_LABEL (page->tab_label))
3840             gtk_label_set_text (GTK_LABEL (page->menu_label),
3841                            GTK_LABEL (page->tab_label)->label);
3842           else
3843             gtk_label_set_text (GTK_LABEL (page->menu_label), string);
3844         }
3845     }  
3846 }
3847
3848 static gint
3849 gtk_notebook_real_page_position (GtkNotebook *notebook,
3850                                  GList       *list)
3851 {
3852   GList *work;
3853   gint count_start;
3854
3855   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
3856   g_return_val_if_fail (list != NULL, -1);
3857
3858   for (work = notebook->children, count_start = 0;
3859        work && work != list; work = work->next)
3860     if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
3861       count_start++;
3862
3863   if (!work)
3864     return -1;
3865
3866   if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
3867     return count_start;
3868
3869   return (count_start + g_list_length (list) - 1);
3870 }
3871
3872 static GList *
3873 gtk_notebook_search_page (GtkNotebook *notebook,
3874                           GList       *list,
3875                           gint         direction,
3876                           gboolean     find_visible)
3877 {
3878   GtkNotebookPage *page = NULL;
3879   GList *old_list = NULL;
3880   gint flag = 0;
3881
3882   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
3883
3884   switch (direction)
3885     {
3886     case STEP_PREV:
3887       flag = GTK_PACK_END;
3888       break;
3889
3890     case STEP_NEXT:
3891       flag = GTK_PACK_START;
3892       break;
3893     }
3894
3895   if (list)
3896     page = list->data;
3897
3898   if (!page || page->pack == flag)
3899     {
3900       if (list)
3901         {
3902           old_list = list;
3903           list = list->next;
3904         }
3905       else
3906         list = notebook->children;
3907
3908       while (list)
3909         {
3910           page = list->data;
3911           if (page->pack == flag &&
3912               (!find_visible || GTK_WIDGET_VISIBLE (page->child)))
3913             return list;
3914           old_list = list;
3915           list = list->next;
3916         }
3917       list = old_list;
3918     }
3919   else
3920     {
3921       old_list = list;
3922       list = list->prev;
3923     }
3924   while (list)
3925     {
3926       page = list->data;
3927       if (page->pack != flag &&
3928           (!find_visible || GTK_WIDGET_VISIBLE (page->child)))
3929         return list;
3930       old_list = list;
3931       list = list->prev;
3932     }
3933   return NULL;
3934 }
3935
3936 /* Private GtkNotebook Drawing Functions:
3937  *
3938  * gtk_notebook_paint
3939  * gtk_notebook_draw_tab
3940  * gtk_notebook_draw_arrow
3941  */
3942 static void
3943 gtk_notebook_paint (GtkWidget    *widget,
3944                     GdkRectangle *area)
3945 {
3946   GtkNotebook *notebook;
3947   GtkNotebookPage *page;
3948   GList *children;
3949   gboolean showarrow;
3950   gint width, height;
3951   gint x, y;
3952   gint border_width = GTK_CONTAINER (widget)->border_width;
3953   gint gap_x = 0, gap_width = 0, step = STEP_PREV;
3954   gboolean is_rtl;
3955   gint tab_pos;
3956    
3957   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
3958   g_return_if_fail (area != NULL);
3959
3960   if (!GTK_WIDGET_DRAWABLE (widget))
3961     return;
3962
3963   notebook = GTK_NOTEBOOK (widget);
3964   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
3965   tab_pos = get_effective_tab_pos (notebook);
3966
3967   if ((!notebook->show_tabs && !notebook->show_border) ||
3968       !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
3969     return;
3970
3971   x = widget->allocation.x + border_width;
3972   y = widget->allocation.y + border_width;
3973   width = widget->allocation.width - border_width * 2;
3974   height = widget->allocation.height - border_width * 2;
3975
3976   if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
3977     {
3978       gtk_paint_box (widget->style, widget->window,
3979                      GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3980                      area, widget, "notebook",
3981                      x, y, width, height);
3982       return;
3983     }
3984
3985
3986   if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
3987     {
3988       page = notebook->first_tab->data;
3989
3990       switch (tab_pos)
3991         {
3992         case GTK_POS_TOP:
3993           y += page->allocation.height + widget->style->ythickness;
3994         case GTK_POS_BOTTOM:
3995           height -= page->allocation.height + widget->style->ythickness;
3996           break;
3997         case GTK_POS_LEFT:
3998           x += page->allocation.width + widget->style->xthickness;
3999         case GTK_POS_RIGHT:
4000           width -= page->allocation.width + widget->style->xthickness;
4001           break;
4002         }
4003       gtk_paint_box (widget->style, widget->window,
4004                      GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4005                      area, widget, "notebook",
4006                      x, y, width, height);
4007     }
4008   else
4009     {
4010       switch (tab_pos)
4011         {
4012         case GTK_POS_TOP:
4013           y += notebook->cur_page->allocation.height;
4014         case GTK_POS_BOTTOM:
4015           height -= notebook->cur_page->allocation.height;
4016           break;
4017         case GTK_POS_LEFT:
4018           x += notebook->cur_page->allocation.width;
4019         case GTK_POS_RIGHT:
4020           width -= notebook->cur_page->allocation.width;
4021           break;
4022         }
4023
4024       switch (tab_pos)
4025         {
4026         case GTK_POS_TOP:
4027         case GTK_POS_BOTTOM:
4028           gap_x = (notebook->cur_page->allocation.x - widget->allocation.x - border_width);
4029           gap_width = notebook->cur_page->allocation.width;
4030           step = is_rtl ? STEP_NEXT : STEP_PREV;
4031           break;
4032         case GTK_POS_LEFT:
4033         case GTK_POS_RIGHT:
4034           gap_x = (notebook->cur_page->allocation.y - widget->allocation.y - border_width);
4035           gap_width = notebook->cur_page->allocation.height;
4036           step = STEP_PREV;
4037           break;
4038         }
4039       gtk_paint_box_gap (widget->style, widget->window,
4040                          GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4041                          area, widget, "notebook",
4042                          x, y, width, height,
4043                          tab_pos, gap_x, gap_width);
4044     }
4045
4046   showarrow = FALSE;
4047   children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4048   while (children)
4049     {
4050       page = children->data;
4051       children = gtk_notebook_search_page (notebook, children,
4052                                            step, TRUE);
4053       if (!GTK_WIDGET_VISIBLE (page->child))
4054         continue;
4055       if (!GTK_WIDGET_MAPPED (page->tab_label))
4056         showarrow = TRUE;
4057       else if (page != notebook->cur_page)
4058         gtk_notebook_draw_tab (notebook, page, area);
4059     }
4060
4061   if (showarrow && notebook->scrollable) 
4062     {
4063       if (notebook->has_before_previous)
4064         gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4065       if (notebook->has_before_next)
4066         gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4067       if (notebook->has_after_previous)
4068         gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4069       if (notebook->has_after_next)
4070         gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4071     }
4072   gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4073 }
4074
4075 static void
4076 gtk_notebook_draw_tab (GtkNotebook     *notebook,
4077                        GtkNotebookPage *page,
4078                        GdkRectangle    *area)
4079 {
4080   GdkRectangle child_area;
4081   GdkRectangle page_area;
4082   GtkStateType state_type;
4083   GtkPositionType gap_side;
4084   gint tab_pos = get_effective_tab_pos (notebook);
4085   
4086   g_return_if_fail (notebook != NULL);
4087   g_return_if_fail (page != NULL);
4088   g_return_if_fail (area != NULL);
4089
4090   if (!GTK_WIDGET_MAPPED (page->tab_label) ||
4091       (page->allocation.width == 0) || (page->allocation.height == 0))
4092     return;
4093
4094   page_area.x = page->allocation.x;
4095   page_area.y = page->allocation.y;
4096   page_area.width = page->allocation.width;
4097   page_area.height = page->allocation.height;
4098
4099   if (gdk_rectangle_intersect (&page_area, area, &child_area))
4100     {
4101       GtkWidget *widget;
4102
4103       widget = GTK_WIDGET (notebook);
4104       gap_side = 0;
4105       switch (tab_pos)
4106         {
4107         case GTK_POS_TOP:
4108           gap_side = GTK_POS_BOTTOM;
4109           break;
4110         case GTK_POS_BOTTOM:
4111           gap_side = GTK_POS_TOP;
4112           break;
4113         case GTK_POS_LEFT:
4114           gap_side = GTK_POS_RIGHT;
4115           break;
4116         case GTK_POS_RIGHT:
4117           gap_side = GTK_POS_LEFT;
4118           break;
4119         }
4120       
4121       if (notebook->cur_page == page)
4122         state_type = GTK_STATE_NORMAL;
4123       else 
4124         state_type = GTK_STATE_ACTIVE;
4125       gtk_paint_extension(widget->style, widget->window,
4126                           state_type, GTK_SHADOW_OUT,
4127                           area, widget, "tab",
4128                           page_area.x, page_area.y,
4129                           page_area.width, page_area.height,
4130                           gap_side);
4131       if ((GTK_WIDGET_HAS_FOCUS (widget)) &&
4132           notebook->focus_tab && (notebook->focus_tab->data == page))
4133         {
4134           gint focus_width;
4135           
4136           gtk_widget_style_get (widget, "focus-line-width", &focus_width, NULL);
4137           
4138           gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
4139                            area, widget, "tab",
4140                            page->tab_label->allocation.x - focus_width,
4141                            page->tab_label->allocation.y - focus_width,
4142                            page->tab_label->allocation.width + 2 * focus_width,
4143                            page->tab_label->allocation.height + 2 * focus_width);
4144         }
4145       if (gtk_widget_intersect (page->tab_label, area, &child_area) &&
4146           GTK_WIDGET_DRAWABLE (page->tab_label))
4147         {
4148           GdkEvent *expose_event = gdk_event_new (GDK_EXPOSE);
4149
4150           /* This is a lame hack since all this code needs rewriting anyhow */
4151           
4152           expose_event->expose.window = g_object_ref (page->tab_label->window);
4153           expose_event->expose.area = child_area;
4154           expose_event->expose.region = gdk_region_rectangle (&child_area);
4155           expose_event->expose.send_event = TRUE;
4156           expose_event->expose.count = 0;
4157
4158           gtk_container_propagate_expose (GTK_CONTAINER (notebook), page->tab_label, (GdkEventExpose *)expose_event);
4159
4160           gdk_event_free (expose_event);
4161         }
4162     }
4163 }
4164
4165 static void
4166 gtk_notebook_draw_arrow (GtkNotebook      *notebook,
4167                          GtkNotebookArrow  nbarrow)
4168 {
4169   GtkStateType state_type;
4170   GtkShadowType shadow_type;
4171   GtkWidget *widget;
4172   GdkRectangle arrow_rect;
4173   GtkArrowType arrow;
4174   gboolean is_rtl, left;
4175
4176   gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4177
4178   widget = GTK_WIDGET (notebook);
4179
4180   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4181   left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4182          (!ARROW_IS_LEFT (nbarrow) && is_rtl); 
4183
4184   if (GTK_WIDGET_DRAWABLE (notebook))
4185     {
4186       if (notebook->in_child == nbarrow)
4187         {
4188           if (notebook->click_child == nbarrow)
4189             state_type = GTK_STATE_ACTIVE;
4190           else
4191             state_type = GTK_STATE_PRELIGHT;
4192         }
4193       else
4194         state_type = GTK_WIDGET_STATE (widget);
4195
4196       if (notebook->click_child == nbarrow)
4197         shadow_type = GTK_SHADOW_IN;
4198       else
4199         shadow_type = GTK_SHADOW_OUT;
4200
4201       if (notebook->focus_tab &&
4202           !gtk_notebook_search_page (notebook, notebook->focus_tab,
4203                                       left? STEP_PREV : STEP_NEXT, TRUE))
4204         {
4205           shadow_type = GTK_SHADOW_ETCHED_IN;
4206           state_type = GTK_STATE_INSENSITIVE;
4207         }
4208       
4209       if (notebook->tab_pos == GTK_POS_LEFT ||
4210           notebook->tab_pos == GTK_POS_RIGHT)
4211         arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4212       else
4213         arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4214       
4215       gtk_paint_arrow (widget->style, widget->window, state_type, 
4216                        shadow_type, NULL, widget, "notebook",
4217                        arrow, TRUE, arrow_rect.x, arrow_rect.y, 
4218                        ARROW_SIZE, ARROW_SIZE);
4219     }
4220 }
4221
4222 static void
4223 get_notebook_tabs_space (GtkNotebook *notebook, gint *min, gint *max)
4224 {
4225   GtkWidget *widget = (GtkWidget *) notebook;
4226   GtkContainer *container = (GtkContainer *) notebook;
4227
4228   if (notebook->tab_pos == GTK_POS_TOP ||
4229       notebook->tab_pos == GTK_POS_BOTTOM)
4230     {
4231       *min = widget->allocation.x + container->border_width;
4232       *max = widget->allocation.x + widget->allocation.width - container->border_width;
4233
4234       if (gtk_notebook_show_arrows (notebook))
4235         {
4236           if (notebook->has_after_previous)
4237             *max -= ARROW_SPACING + ARROW_SIZE;
4238           if (notebook->has_after_next)
4239             *max -= ARROW_SPACING + ARROW_SIZE;
4240           if (notebook->has_before_previous)
4241             *min += ARROW_SPACING + ARROW_SIZE;
4242           if (notebook->has_before_next)
4243             *min += ARROW_SPACING + ARROW_SIZE;
4244         }
4245     }
4246   else
4247     {
4248       *min = widget->allocation.y + container->border_width;
4249       *max = widget->allocation.y + widget->allocation.height - container->border_width;
4250
4251       if (gtk_notebook_show_arrows (notebook))
4252         {
4253           if (notebook->has_after_previous || notebook->has_after_next)
4254             *max -= ARROW_SPACING + ARROW_SIZE;
4255           if (notebook->has_before_previous || notebook->has_before_next)
4256             *min += ARROW_SPACING + ARROW_SIZE;
4257         }
4258     }
4259 }
4260
4261 /* Private GtkNotebook Size Allocate Functions:
4262  *
4263  * gtk_notebook_pages_allocate
4264  * gtk_notebook_page_allocate
4265  * gtk_notebook_calc_tabs
4266  */
4267 static void
4268 gtk_notebook_pages_allocate (GtkNotebook              *notebook,
4269                              GtkNotebookDragOperation  operation)
4270 {
4271   GtkWidget    *widget = GTK_WIDGET (notebook);
4272   GtkContainer *container = GTK_CONTAINER (notebook);
4273   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4274   GtkNotebookPage *page = NULL;
4275   GtkAllocation *allocation = &widget->allocation;
4276   GtkAllocation child_allocation;
4277   GList *children = NULL;
4278   GList *last_child = NULL;
4279   gboolean showarrow = FALSE;
4280   gint tab_space = 0; 
4281   gint delta; 
4282   gint i;
4283   gint n = 1;
4284   gint old_fill = 0;
4285   gint new_fill = 0;
4286   gint tab_pos = get_effective_tab_pos (notebook);
4287   gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL &&
4288                      (tab_pos == GTK_POS_TOP || tab_pos == GTK_POS_BOTTOM));
4289   gint tab_overlap;
4290   gint memo_x, anchor_x, anchor_y;
4291   gint min, max, top_y, bottom_y, left_x, right_x;
4292   gboolean packing_changed = FALSE;
4293   gboolean gap_left = FALSE;
4294
4295   if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
4296     return;
4297
4298   gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4299
4300   child_allocation.x = widget->allocation.x + container->border_width;
4301   child_allocation.y = widget->allocation.y + container->border_width;
4302
4303   switch (tab_pos)
4304     {
4305     case GTK_POS_BOTTOM:
4306       child_allocation.y = (widget->allocation.y +
4307                             allocation->height -
4308                             notebook->cur_page->requisition.height -
4309                             container->border_width);
4310       /* fall through */
4311     case GTK_POS_TOP:
4312       child_allocation.height = notebook->cur_page->requisition.height;
4313       break;
4314       
4315     case GTK_POS_RIGHT:
4316       child_allocation.x = (widget->allocation.x +
4317                             allocation->width -
4318                             notebook->cur_page->requisition.width -
4319                             container->border_width);
4320       /* fall through */
4321     case GTK_POS_LEFT:
4322       child_allocation.width = notebook->cur_page->requisition.width;
4323       break;
4324     }
4325
4326   if (notebook->scrollable) 
4327     {
4328       GList *focus_tab;
4329       
4330       children = notebook->children;
4331
4332       if (notebook->focus_tab)
4333         focus_tab = notebook->focus_tab;
4334       else if (notebook->first_tab)
4335         focus_tab = notebook->first_tab;
4336       else
4337         focus_tab = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE);
4338
4339       switch (tab_pos)
4340         {
4341         case GTK_POS_TOP:
4342         case GTK_POS_BOTTOM:
4343           while (children)
4344             {
4345               page = children->data;
4346               children = children->next;
4347
4348               if (GTK_WIDGET_VISIBLE (page->child))
4349                 tab_space += page->requisition.width;
4350             }
4351
4352           if (tab_space >
4353               allocation->width - 2 * container->border_width - tab_overlap) 
4354             {
4355               showarrow = TRUE;
4356               page = focus_tab->data; 
4357
4358               tab_space = allocation->width - tab_overlap -
4359                 page->requisition.width - 2 * container->border_width;
4360               if (notebook->has_after_previous)
4361                 tab_space -= ARROW_SPACING + ARROW_SIZE;
4362               if (notebook->has_after_next)
4363                 tab_space -= ARROW_SPACING + ARROW_SIZE;
4364               if (notebook->has_before_previous)
4365                 {
4366                   tab_space -= ARROW_SPACING + ARROW_SIZE;
4367                   child_allocation.x += ARROW_SPACING + ARROW_SIZE;
4368                 }
4369               if (notebook->has_before_next)
4370                 {
4371                   tab_space -= ARROW_SPACING + ARROW_SIZE;
4372                   child_allocation.x += ARROW_SPACING + ARROW_SIZE;
4373                 }
4374             }
4375           break;
4376         case GTK_POS_LEFT:
4377         case GTK_POS_RIGHT:
4378           while (children)
4379             {
4380               page = children->data;
4381               children = children->next;
4382
4383               if (GTK_WIDGET_VISIBLE (page->child))
4384                 tab_space += page->requisition.height;
4385             }
4386           if (tab_space >
4387               (allocation->height - 2 * container->border_width - tab_overlap))
4388             {
4389               showarrow = TRUE;
4390               page = focus_tab->data; 
4391               tab_space = allocation->height
4392                 - tab_overlap - 2 * container->border_width
4393                 - page->requisition.height;
4394               if (notebook->has_after_previous || notebook->has_after_next)
4395                 tab_space -= ARROW_SPACING + ARROW_SIZE;
4396               if (notebook->has_before_previous || notebook->has_before_next)
4397                 {
4398                   tab_space -= ARROW_SPACING + ARROW_SIZE;
4399                   child_allocation.y += ARROW_SPACING + ARROW_SIZE;
4400                 }
4401             }
4402           break;
4403         }
4404       if (showarrow) /* first_tab <- focus_tab */
4405         {
4406           if (tab_space <= 0)
4407             {
4408               notebook->first_tab = focus_tab;
4409               last_child = gtk_notebook_search_page (notebook, focus_tab,
4410                                                      STEP_NEXT, TRUE);
4411             }
4412           else
4413             {
4414               children = NULL;
4415               if (notebook->first_tab && notebook->first_tab != focus_tab)
4416                 {
4417                   /* Is first_tab really predecessor of focus_tab  ? */
4418                   page = notebook->first_tab->data;
4419                   if (GTK_WIDGET_VISIBLE (page->child))
4420                     for (children = focus_tab;
4421                          children && children != notebook->first_tab;
4422                          children = gtk_notebook_search_page (notebook,
4423                                                               children,
4424                                                               STEP_PREV,
4425                                                               TRUE));
4426                 }
4427               if (!children)
4428                 notebook->first_tab = focus_tab;
4429               else
4430                 gtk_notebook_calc_tabs (notebook,
4431                                         gtk_notebook_search_page (notebook,
4432                                                                   focus_tab,
4433                                                                   STEP_PREV,
4434                                                                   TRUE), 
4435                                         &(notebook->first_tab), &tab_space,
4436                                         STEP_PREV);
4437
4438               if (tab_space <= 0)
4439                 {
4440                   notebook->first_tab =
4441                     gtk_notebook_search_page (notebook, notebook->first_tab,
4442                                               STEP_NEXT, TRUE);
4443                   if (!notebook->first_tab)
4444                     notebook->first_tab = focus_tab;
4445                   last_child = gtk_notebook_search_page (notebook, focus_tab,
4446                                                          STEP_NEXT, TRUE); 
4447                 }
4448               else /* focus_tab -> end */   
4449                 {
4450                   if (!notebook->first_tab)
4451                     notebook->first_tab = gtk_notebook_search_page (notebook,
4452                                                                     NULL,
4453                                                                     STEP_NEXT,
4454                                                                     TRUE);
4455                   children = NULL;
4456                   gtk_notebook_calc_tabs (notebook,
4457                                           gtk_notebook_search_page (notebook,
4458                                                                     focus_tab,
4459                                                                     STEP_NEXT,
4460                                                                     TRUE),
4461                                           &children, &tab_space, STEP_NEXT);
4462
4463                   if (tab_space <= 0) 
4464                     last_child = children;
4465                   else /* start <- first_tab */
4466                     {
4467                       last_child = NULL;
4468                       children = NULL;
4469                       gtk_notebook_calc_tabs
4470                         (notebook,
4471                          gtk_notebook_search_page (notebook,
4472                                                    notebook->first_tab,
4473                                                    STEP_PREV,
4474                                                    TRUE),
4475                          &children, &tab_space, STEP_PREV);
4476                       notebook->first_tab = gtk_notebook_search_page(notebook,
4477                                                                      children,
4478                                                                      STEP_NEXT,
4479                                                                      TRUE);
4480                     }
4481                 }
4482             }
4483
4484           if (tab_space < 0) 
4485             {
4486               tab_space = -tab_space;
4487               n = 0;
4488               for (children = notebook->first_tab;
4489                    children && children != last_child;
4490                    children = gtk_notebook_search_page (notebook, children,
4491                                                         STEP_NEXT, TRUE))
4492                 n++;
4493             }
4494           else 
4495             tab_space = 0;
4496
4497           /*unmap all non-visible tabs*/
4498           for (children = gtk_notebook_search_page (notebook, NULL,
4499                                                     STEP_NEXT, TRUE);
4500                children && children != notebook->first_tab;
4501                children = gtk_notebook_search_page (notebook, children,
4502                                                     STEP_NEXT, TRUE))
4503             {
4504               page = children->data;
4505               if (page->tab_label)
4506                 gtk_widget_set_child_visible (page->tab_label, FALSE);
4507             }
4508           for (children = last_child; children;
4509                children = gtk_notebook_search_page (notebook, children,
4510                                                     STEP_NEXT, TRUE))
4511             {
4512               page = children->data;
4513               if (page->tab_label)
4514                 gtk_widget_set_child_visible (page->tab_label, FALSE);
4515             }
4516         }
4517       else /* !showarrow */
4518         {
4519           notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
4520                                                           STEP_NEXT, TRUE);
4521           tab_space = 0;
4522         }
4523     }
4524
4525   if (!showarrow)
4526     {
4527       gint c = 0;
4528
4529       n = 0;
4530       children = notebook->children;
4531       switch (tab_pos)
4532         {
4533         case GTK_POS_TOP:
4534         case GTK_POS_BOTTOM:
4535           while (children)
4536             {
4537               page = children->data;
4538               children = children->next;
4539
4540               if (GTK_WIDGET_VISIBLE (page->child))
4541                 {
4542                   c++;
4543                   tab_space += page->requisition.width;
4544                   if (page->expand)
4545                     n++;
4546                 }
4547             }
4548           tab_space -= allocation->width;
4549           break;
4550         case GTK_POS_LEFT:
4551         case GTK_POS_RIGHT:
4552           while (children)
4553             {
4554               page = children->data;
4555               children = children->next;
4556
4557               if (GTK_WIDGET_VISIBLE (page->child))
4558                 {
4559                   c++;
4560                   tab_space += page->requisition.height;
4561                   if (page->expand)
4562                     n++;
4563                 }
4564             }
4565           tab_space -= allocation->height;
4566         }
4567       tab_space += 2 * container->border_width + tab_overlap;
4568       tab_space *= -1;
4569       notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
4570                                                       STEP_NEXT, TRUE);
4571       if (notebook->homogeneous && n)
4572         n = c;
4573     }
4574   
4575   children = notebook->first_tab;
4576   i = 1; 
4577
4578   memo_x = child_allocation.x;
4579   if (notebook->children && is_rtl)
4580      {
4581       child_allocation.x = (allocation->x + allocation->width -
4582                             container->border_width); 
4583       if (showarrow) 
4584         {
4585           if (notebook->has_after_previous)
4586             child_allocation.x -= ARROW_SPACING + ARROW_SIZE;
4587           if (notebook->has_after_next)
4588             child_allocation.x -= ARROW_SPACING + ARROW_SIZE;
4589         }
4590      }
4591
4592   get_notebook_tabs_space (notebook, &min, &max);
4593   anchor_x = child_allocation.x;
4594   anchor_y = child_allocation.y;
4595
4596   left_x   = CLAMP (widget->allocation.x + priv->mouse_x - notebook->cur_page->allocation.width / 2,
4597                     min, max - notebook->cur_page->allocation.width);
4598   top_y    = CLAMP (widget->allocation.y + priv->mouse_y - notebook->cur_page->allocation.height / 2,
4599                     min, max - notebook->cur_page->allocation.height);
4600   right_x  = left_x + notebook->cur_page->allocation.width;
4601   bottom_y = top_y + notebook->cur_page->allocation.height;
4602
4603   while (children)
4604     {
4605       if (children == last_child)
4606         {
4607           /* FIXME double check */
4608           goto done;
4609         }
4610
4611       page = children->data;
4612
4613       if (page->pack != GTK_PACK_START)
4614         {
4615           if (!showarrow)
4616             break;
4617           else if (operation == DRAG_OPERATION_REORDER)
4618             packing_changed = TRUE;
4619         }
4620
4621       children = gtk_notebook_search_page (notebook, children, STEP_NEXT,TRUE);
4622
4623       delta = 0;
4624       if (n && (showarrow || page->expand || notebook->homogeneous))
4625         {
4626           new_fill = (tab_space * i++) / n;
4627           delta = new_fill - old_fill;
4628           old_fill = new_fill;
4629         }
4630
4631       switch (tab_pos)
4632         {
4633         case GTK_POS_TOP:
4634         case GTK_POS_BOTTOM:
4635           child_allocation.width = (page->requisition.width +
4636                                     tab_overlap + delta);
4637
4638           /* make sure that the reordered tab doesn't go past the last position */
4639           if (operation == DRAG_OPERATION_REORDER &&
4640               !gap_left && packing_changed)
4641             {
4642               if (!is_rtl)
4643                 {
4644                   if ((notebook->cur_page->pack == GTK_PACK_START && left_x  >= anchor_x) ||
4645                       (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor_x))
4646                     {
4647                       left_x = notebook->cur_page->allocation.x = anchor_x;
4648                       gtk_notebook_page_allocate (notebook, notebook->cur_page,
4649                                                   &notebook->cur_page->allocation);
4650
4651                       anchor_x += notebook->cur_page->allocation.width - tab_overlap;
4652                     }
4653                 }
4654               else
4655                 {
4656                   if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor_x) ||
4657                       (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor_x))
4658                     {
4659                       anchor_x -= notebook->cur_page->allocation.width;
4660
4661                       left_x = notebook->cur_page->allocation.x = anchor_x;
4662                       gtk_notebook_page_allocate (notebook, notebook->cur_page,
4663                                                   &notebook->cur_page->allocation);
4664
4665                       anchor_x += tab_overlap;
4666                     }
4667                 }
4668
4669               gap_left = TRUE;
4670             }
4671
4672           if (operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4673             child_allocation.x = left_x;
4674           else
4675             {
4676               if (is_rtl)
4677                 anchor_x -= child_allocation.width;
4678  
4679               if (operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
4680                 {
4681                   if (!is_rtl &&
4682                       left_x >= anchor_x &&
4683                       left_x <= anchor_x + child_allocation.width / 2)
4684                     anchor_x += notebook->cur_page->allocation.width - tab_overlap;
4685                   else if (is_rtl &&
4686                            right_x >  anchor_x + child_allocation.width / 2 &&
4687                            right_x <= anchor_x + child_allocation.width)
4688                     anchor_x -= notebook->cur_page->allocation.width - tab_overlap;
4689                 }
4690  
4691               child_allocation.x = anchor_x;
4692             }
4693
4694           break;
4695         case GTK_POS_LEFT:
4696         case GTK_POS_RIGHT:
4697           child_allocation.height = (page->requisition.height +
4698                                      tab_overlap + delta);
4699
4700           /* make sure that the reordered tab doesn't go past the last position */
4701           if (operation == DRAG_OPERATION_REORDER &&
4702               !gap_left && packing_changed)
4703             {
4704               if ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor_y) ||
4705                   (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor_y))
4706                 {
4707                   top_y = notebook->cur_page->allocation.y = anchor_y;
4708                   gtk_notebook_page_allocate (notebook, notebook->cur_page,
4709                                               &notebook->cur_page->allocation);
4710
4711                   anchor_y += notebook->cur_page->allocation.height - tab_overlap;
4712                 }
4713  
4714               gap_left = TRUE;
4715             }
4716
4717           if (operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4718             child_allocation.y = top_y;
4719           else
4720             {
4721               if (operation == DRAG_OPERATION_REORDER &&
4722                   page->pack == notebook->cur_page->pack &&
4723                   top_y >= anchor_y &&
4724                   top_y <= anchor_y + child_allocation.height / 2)
4725                 anchor_y += notebook->cur_page->allocation.height - tab_overlap;
4726  
4727               child_allocation.y = anchor_y;
4728             }
4729
4730           break;
4731         }
4732
4733       gtk_notebook_page_allocate (notebook, page, &child_allocation);
4734
4735       switch (tab_pos)
4736         {
4737         case GTK_POS_TOP:
4738         case GTK_POS_BOTTOM:
4739           if (operation != DRAG_OPERATION_REORDER ||
4740               (operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
4741             {
4742               if (operation == DRAG_OPERATION_REORDER)
4743                 {
4744                   if (page->pack == notebook->cur_page->pack &&
4745                       !is_rtl &&
4746                       left_x >  anchor_x + child_allocation.width / 2 &&
4747                       left_x <= anchor_x + child_allocation.width)
4748                     anchor_x += notebook->cur_page->allocation.width - tab_overlap;
4749                   else if (page->pack == notebook->cur_page->pack &&
4750                            is_rtl &&
4751                            right_x >= anchor_x &&
4752                            right_x <= anchor_x + child_allocation.width / 2)
4753                     anchor_x -= notebook->cur_page->allocation.width - tab_overlap;
4754                 }
4755  
4756               if (!is_rtl)
4757                 anchor_x += child_allocation.width - tab_overlap;
4758               else
4759                 anchor_x += tab_overlap;
4760             }
4761
4762           break;
4763         case GTK_POS_LEFT:
4764         case GTK_POS_RIGHT:
4765           if (operation != DRAG_OPERATION_REORDER  ||
4766               (operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
4767             {
4768               if (operation == DRAG_OPERATION_REORDER &&
4769                   page->pack == notebook->cur_page->pack &&
4770                   page != notebook->cur_page &&
4771                   top_y >  anchor_y + child_allocation.height / 2 &&
4772                   top_y <= anchor_y + child_allocation.height)
4773                 anchor_y += notebook->cur_page->allocation.height - tab_overlap;
4774  
4775               anchor_y += child_allocation.height - tab_overlap;
4776             }
4777
4778           break;
4779         }
4780
4781       if (page->tab_label)
4782         gtk_widget_set_child_visible (page->tab_label, TRUE);
4783     }
4784
4785   /* don't move the tab past the last position */
4786   if (operation == DRAG_OPERATION_REORDER &&
4787       notebook->cur_page->pack == GTK_PACK_START)
4788     {
4789       switch (tab_pos)
4790         {
4791         case GTK_POS_TOP:
4792         case GTK_POS_BOTTOM:
4793           if ((!is_rtl && PAGE_LEFT_X (notebook->cur_page) > anchor_x) ||
4794               (is_rtl && PAGE_RIGHT_X (notebook->cur_page) < anchor_x))
4795             {
4796               if (is_rtl)
4797                 anchor_x -= notebook->cur_page->allocation.width;
4798
4799               notebook->cur_page->allocation.x = anchor_x;
4800               gtk_notebook_page_allocate (notebook, notebook->cur_page,
4801                                           &notebook->cur_page->allocation);
4802             }
4803           break;
4804         case GTK_POS_LEFT:
4805         case GTK_POS_RIGHT:
4806           if (PAGE_TOP_Y (notebook->cur_page) > anchor_y)
4807             {
4808               notebook->cur_page->allocation.y = anchor_y;
4809               gtk_notebook_page_allocate (notebook, notebook->cur_page,
4810                                           &notebook->cur_page->allocation);
4811             }
4812           break;
4813         }
4814     }
4815
4816   if (children)
4817     {
4818       children = notebook->children;
4819
4820       switch (tab_pos)
4821         {
4822         case GTK_POS_TOP:
4823         case GTK_POS_BOTTOM:
4824           if (!is_rtl)
4825              anchor_x = (allocation->x + allocation->width -
4826                          container->border_width);
4827           else
4828              anchor_x = memo_x; 
4829           break;
4830         case GTK_POS_LEFT:
4831         case GTK_POS_RIGHT:
4832           anchor_y = (allocation->y + allocation->height -
4833                       container->border_width);
4834           break;
4835         }
4836
4837       while (children != last_child)
4838         {
4839           page = children->data;
4840           children = children->next;
4841
4842           if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
4843              continue;
4844
4845           delta = 0;
4846           if (n && (page->expand || notebook->homogeneous))
4847             {
4848               new_fill = (tab_space * i++) / n;
4849               delta = new_fill - old_fill;
4850               old_fill = new_fill;
4851             }
4852
4853           switch (tab_pos)
4854             {
4855             case GTK_POS_TOP:
4856             case GTK_POS_BOTTOM:
4857               child_allocation.width = (page->requisition.width +
4858                                         tab_overlap + delta);
4859
4860               if (operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4861                 child_allocation.x = left_x;
4862               else
4863                 {
4864                   if (!is_rtl)
4865                     anchor_x -= child_allocation.width;
4866  
4867                   if (operation == DRAG_OPERATION_REORDER)
4868                     {
4869                       if (page->pack == notebook->cur_page->pack &&
4870                           is_rtl &&
4871                           left_x >= anchor_x &&
4872                           left_x <= anchor_x + child_allocation.width / 2)
4873                         anchor_x += notebook->cur_page->allocation.width - tab_overlap;
4874                       else if (page->pack == notebook->cur_page->pack &&
4875                                !is_rtl &&
4876                                right_x >  anchor_x + child_allocation.width / 2 &&
4877                                right_x <= anchor_x + child_allocation.width)
4878                         anchor_x -= notebook->cur_page->allocation.width - tab_overlap;
4879                     }
4880  
4881                   child_allocation.x = anchor_x;
4882                 }
4883
4884               break;
4885             case GTK_POS_LEFT:
4886             case GTK_POS_RIGHT:
4887               child_allocation.height = (page->requisition.height +
4888                                          tab_overlap + delta);
4889
4890               if (operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4891                 child_allocation.y = top_y;
4892               else
4893                 {
4894                   anchor_y -= child_allocation.height;
4895  
4896                   if (operation == DRAG_OPERATION_REORDER &&
4897                       page->pack == notebook->cur_page->pack &&
4898                       bottom_y >  anchor_y + child_allocation.height / 2 &&
4899                       bottom_y <= anchor_y + child_allocation.height)
4900                     anchor_y -= notebook->cur_page->allocation.height - tab_overlap;
4901  
4902                   child_allocation.y = anchor_y;
4903                 }
4904
4905               break;
4906             }
4907
4908           gtk_notebook_page_allocate (notebook, page, &child_allocation);
4909
4910           switch (tab_pos)
4911             {
4912             case GTK_POS_TOP:
4913             case GTK_POS_BOTTOM:
4914               if (operation != DRAG_OPERATION_REORDER ||
4915                   (operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
4916                 {
4917                   if (operation == DRAG_OPERATION_REORDER)
4918                     {
4919                       if (page->pack == notebook->cur_page->pack &&
4920                           is_rtl &&
4921                           left_x >  anchor_x + child_allocation.width / 2 &&
4922                           left_x <= anchor_x + child_allocation.width)
4923                         anchor_x += notebook->cur_page->allocation.width - tab_overlap;
4924                       else if (page->pack == notebook->cur_page->pack &&
4925                                !is_rtl &&
4926                                right_x >= anchor_x &&
4927                                right_x <= anchor_x + child_allocation.width / 2)
4928                         anchor_x -= notebook->cur_page->allocation.width - tab_overlap;
4929                     }
4930  
4931                   if (!is_rtl)
4932                     anchor_x += tab_overlap;
4933                   else
4934                     anchor_x += child_allocation.width - tab_overlap;
4935                 }
4936
4937               break;
4938             case GTK_POS_LEFT:
4939             case GTK_POS_RIGHT:
4940               if (operation != DRAG_OPERATION_REORDER  ||
4941                   (operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
4942                 {
4943                   if (operation == DRAG_OPERATION_REORDER &&
4944                       page->pack == notebook->cur_page->pack &&
4945                       page != notebook->cur_page &&
4946                       bottom_y >= anchor_y &&
4947                       bottom_y <= anchor_y + child_allocation.height / 2)
4948                     anchor_y -= notebook->cur_page->allocation.height - tab_overlap;
4949  
4950                   anchor_y += tab_overlap;
4951                 }
4952
4953               break;
4954             }
4955
4956           if (page->tab_label)
4957             gtk_widget_set_child_visible (page->tab_label, TRUE);
4958         }
4959
4960       /* don't move the tab past the last position */
4961       if (operation == DRAG_OPERATION_REORDER &&
4962           notebook->cur_page->pack == GTK_PACK_END)
4963         {
4964           switch (tab_pos)
4965             {
4966             case GTK_POS_TOP:
4967             case GTK_POS_BOTTOM:
4968               if ((!is_rtl && PAGE_RIGHT_X (notebook->cur_page) < anchor_x) ||
4969                   (is_rtl && PAGE_LEFT_X (notebook->cur_page) > anchor_x))
4970                 {
4971                   if (!is_rtl)
4972                     anchor_x -= notebook->cur_page->allocation.width;
4973
4974                   notebook->cur_page->allocation.x = anchor_x;
4975                   gtk_notebook_page_allocate (notebook, notebook->cur_page,
4976                                               &notebook->cur_page->allocation);
4977                 }
4978               break;
4979             case GTK_POS_LEFT:
4980             case GTK_POS_RIGHT:
4981               if (PAGE_BOTTOM_Y (notebook->cur_page) < anchor_y)
4982                 {
4983                   anchor_y -= notebook->cur_page->allocation.height;
4984                   notebook->cur_page->allocation.y = anchor_y;
4985                   gtk_notebook_page_allocate (notebook, notebook->cur_page,
4986                                               &notebook->cur_page->allocation);
4987                 }
4988               break;
4989             }
4990         }
4991     }
4992
4993  done:
4994   gtk_notebook_redraw_tabs (notebook);  
4995 }
4996
4997 static void
4998 gtk_notebook_page_allocate (GtkNotebook     *notebook,
4999                             GtkNotebookPage *page,
5000                             GtkAllocation   *allocation)
5001 {
5002   GtkWidget *widget = GTK_WIDGET (notebook);
5003   GtkAllocation child_allocation;
5004   GtkRequisition tab_requisition;
5005   gint xthickness;
5006   gint ythickness;
5007   gint padding;
5008   gint focus_width;
5009   gint tab_curvature;
5010   gint tab_pos = get_effective_tab_pos (notebook);
5011
5012   gtk_widget_style_get (widget,
5013                         "focus-line-width", &focus_width,
5014                         "tab-curvature", &tab_curvature,
5015                         NULL);
5016   
5017   xthickness = widget->style->xthickness;
5018   ythickness = widget->style->ythickness;
5019
5020   page->allocation = *allocation;
5021   gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5022
5023   if (notebook->cur_page != page)
5024     {
5025       switch (tab_pos)
5026         {
5027         case GTK_POS_TOP:
5028           page->allocation.y += ythickness;
5029         case GTK_POS_BOTTOM:
5030           page->allocation.height = MAX (1, page->allocation.height - ythickness);
5031           break;
5032         case GTK_POS_LEFT:
5033           page->allocation.x += xthickness;
5034         case GTK_POS_RIGHT:
5035           page->allocation.width = MAX (1, page->allocation.width - xthickness);
5036           break;
5037         }
5038     }
5039
5040   switch (tab_pos)
5041     {
5042     case GTK_POS_TOP:
5043     case GTK_POS_BOTTOM:
5044       padding = tab_curvature + focus_width + notebook->tab_hborder;
5045       if (page->fill)
5046         {
5047           child_allocation.x = (xthickness + focus_width +
5048                                 notebook->tab_hborder);
5049           child_allocation.width = MAX (1, (page->allocation.width -
5050                                             2 * child_allocation.x));
5051           child_allocation.x += page->allocation.x;
5052         }
5053       else
5054         {
5055           child_allocation.x = (page->allocation.x +
5056                                 (page->allocation.width -
5057                                  tab_requisition.width) / 2);
5058           child_allocation.width = tab_requisition.width;
5059         }
5060       child_allocation.y = (notebook->tab_vborder + focus_width +
5061                             page->allocation.y);
5062       if (tab_pos == GTK_POS_TOP)
5063         child_allocation.y += ythickness;
5064       child_allocation.height = MAX (1, (((gint) page->allocation.height) - ythickness -
5065                                          2 * (notebook->tab_vborder + focus_width)));
5066       break;
5067     case GTK_POS_LEFT:
5068     case GTK_POS_RIGHT:
5069       padding = tab_curvature + focus_width + notebook->tab_vborder;
5070       if (page->fill)
5071         {
5072           child_allocation.y = ythickness + padding;
5073           child_allocation.height = MAX (1, (page->allocation.height -
5074                                              2 * child_allocation.y));
5075           child_allocation.y += page->allocation.y;
5076         }
5077       else
5078         {
5079           child_allocation.y = (page->allocation.y + (page->allocation.height -
5080                                                       tab_requisition.height) / 2);
5081           child_allocation.height = tab_requisition.height;
5082         }
5083       child_allocation.x = page->allocation.x + notebook->tab_hborder + focus_width;
5084       if (tab_pos == GTK_POS_LEFT)
5085         child_allocation.x += xthickness;
5086       child_allocation.width = MAX (1, (((gint) page->allocation.width) - xthickness -
5087                                         2 * (notebook->tab_hborder + focus_width)));
5088       break;
5089     }
5090
5091   if (page->tab_label)
5092     gtk_widget_size_allocate (page->tab_label, &child_allocation);
5093 }
5094
5095 static void 
5096 gtk_notebook_calc_tabs (GtkNotebook  *notebook, 
5097                         GList        *start, 
5098                         GList       **end,
5099                         gint         *tab_space,
5100                         guint         direction)
5101 {
5102   GtkNotebookPage *page = NULL;
5103   GList *children;
5104   GList *last_list = NULL;
5105   gboolean pack;
5106   gint tab_pos = get_effective_tab_pos (notebook);
5107
5108   if (!start)
5109     return;
5110
5111   children = start;
5112   pack = GTK_NOTEBOOK_PAGE (start)->pack;
5113   if (pack == GTK_PACK_END)
5114     direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5115
5116   while (1)
5117     {
5118       switch (tab_pos)
5119         {
5120         case GTK_POS_TOP:
5121         case GTK_POS_BOTTOM:
5122           while (children)
5123             {
5124               page = children->data;
5125               if (GTK_WIDGET_VISIBLE (page->child))
5126                 {
5127                   if (page->pack == pack)
5128                     {
5129                       *tab_space -= page->requisition.width;
5130                       if (*tab_space < 0 || children == *end)
5131                         {
5132                           if (*tab_space < 0) 
5133                             {
5134                               *tab_space = - (*tab_space +
5135                                               page->requisition.width);
5136                               *end = children;
5137                             }
5138                           return;
5139                         }
5140                     }
5141                   last_list = children;
5142                 }
5143               if (direction == STEP_NEXT)
5144                 children = children->next;
5145               else
5146                 children = children->prev;
5147             }
5148           break;
5149         case GTK_POS_LEFT:
5150         case GTK_POS_RIGHT:
5151           while (children)
5152             {
5153               page = children->data;
5154               if (GTK_WIDGET_VISIBLE (page->child))
5155                 {
5156                   if (page->pack == pack)
5157                     {
5158                       *tab_space -= page->requisition.height;
5159                       if (*tab_space < 0 || children == *end)
5160                         {
5161                           if (*tab_space < 0)
5162                             {
5163                               *tab_space = - (*tab_space +
5164                                               page->requisition.height);
5165                               *end = children;
5166                             }
5167                           return;
5168                         }
5169                     }
5170                   last_list = children;
5171                 }
5172               if (direction == STEP_NEXT)
5173                 children = children->next;
5174               else
5175                 children = children->prev;
5176             }
5177           break;
5178         }
5179       if (direction == STEP_PREV)
5180         return;
5181       pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5182       direction = STEP_PREV;
5183       children = last_list;
5184     }
5185 }
5186
5187 static void
5188 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5189 {
5190   GList *list;
5191
5192   for (list = notebook->children; list != NULL; list = list->next)
5193     {
5194       GtkNotebookPage *page = list->data;
5195       
5196       if (page->tab_label)
5197         {
5198           if (page == notebook->cur_page)
5199             gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5200           else
5201             gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5202         }
5203     }
5204 }
5205
5206 /* Private GtkNotebook Page Switch Methods:
5207  *
5208  * gtk_notebook_real_switch_page
5209  */
5210 static void
5211 gtk_notebook_real_switch_page (GtkNotebook     *notebook,
5212                                GtkNotebookPage *page,
5213                                guint            page_num)
5214 {
5215   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5216   g_return_if_fail (page != NULL);
5217
5218   if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5219     return;
5220
5221   if (notebook->cur_page)
5222     gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5223   
5224   notebook->cur_page = page;
5225
5226   if (!notebook->focus_tab ||
5227       notebook->focus_tab->data != (gpointer) notebook->cur_page)
5228     notebook->focus_tab = 
5229       g_list_find (notebook->children, notebook->cur_page);
5230
5231   gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5232
5233   /* If the focus was on the previous page, move it to the first
5234    * element on the new page, if possible, or if not, to the
5235    * notebook itself.
5236    */
5237   if (notebook->child_has_focus)
5238     {
5239       if (notebook->cur_page->last_focus_child &&
5240           gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5241         gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5242       else
5243         if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5244           gtk_widget_grab_focus (GTK_WIDGET (notebook));
5245     }
5246   
5247   gtk_notebook_update_tab_states (notebook);
5248   gtk_widget_queue_resize (GTK_WIDGET (notebook));
5249   g_object_notify (G_OBJECT (notebook), "page");
5250 }
5251
5252 /* Private GtkNotebook Page Switch Functions:
5253  *
5254  * gtk_notebook_switch_page
5255  * gtk_notebook_page_select
5256  * gtk_notebook_switch_focus_tab
5257  * gtk_notebook_menu_switch_page
5258  */
5259 static void
5260 gtk_notebook_switch_page (GtkNotebook     *notebook,
5261                           GtkNotebookPage *page,
5262                           gint             page_num)
5263
5264   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5265   g_return_if_fail (page != NULL);
5266  
5267   if (notebook->cur_page == page)
5268     return;
5269
5270   if (page_num < 0)
5271     page_num = g_list_index (notebook->children, page);
5272
5273   g_signal_emit (notebook,
5274                  notebook_signals[SWITCH_PAGE],
5275                  0,
5276                  page,
5277                  page_num);
5278 }
5279
5280 static gint
5281 gtk_notebook_page_select (GtkNotebook *notebook,
5282                           gboolean     move_focus)
5283 {
5284   GtkNotebookPage *page;
5285   GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5286   gint tab_pos = get_effective_tab_pos (notebook);
5287
5288   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
5289
5290   if (!notebook->focus_tab)
5291     return FALSE;
5292
5293   page = notebook->focus_tab->data;
5294   gtk_notebook_switch_page (notebook, page, -1);
5295
5296   if (move_focus)
5297     {
5298       switch (tab_pos)
5299         {
5300         case GTK_POS_TOP:
5301           dir = GTK_DIR_DOWN;
5302           break;
5303         case GTK_POS_BOTTOM:
5304           dir = GTK_DIR_UP;
5305           break;
5306         case GTK_POS_LEFT:
5307           dir = GTK_DIR_RIGHT;
5308           break;
5309         case GTK_POS_RIGHT:
5310           dir = GTK_DIR_LEFT;
5311           break;
5312         }
5313
5314       if (gtk_widget_child_focus (page->child, dir))
5315         return TRUE;
5316     }
5317   return FALSE;
5318 }
5319
5320 static void
5321 gtk_notebook_switch_focus_tab (GtkNotebook *notebook, 
5322                                GList       *new_child)
5323 {
5324   GList *old_child;
5325   GtkNotebookPage *page;
5326
5327   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5328
5329   if (notebook->focus_tab == new_child)
5330     return;
5331
5332   old_child = notebook->focus_tab;
5333   notebook->focus_tab = new_child;
5334
5335   if (notebook->scrollable)
5336     gtk_notebook_redraw_arrows (notebook);
5337
5338   if (!notebook->show_tabs || !notebook->focus_tab)
5339     return;
5340
5341   page = notebook->focus_tab->data;
5342   if (GTK_WIDGET_MAPPED (page->tab_label))
5343     gtk_notebook_redraw_tabs (notebook);
5344   else
5345     gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
5346   
5347   gtk_notebook_switch_page (notebook, page,
5348                             g_list_index (notebook->children, page));
5349 }
5350
5351 static void
5352 gtk_notebook_menu_switch_page (GtkWidget       *widget,
5353                                GtkNotebookPage *page)
5354 {
5355   GtkNotebook *notebook;
5356   GList *children;
5357   guint page_num;
5358
5359   g_return_if_fail (widget != NULL);
5360   g_return_if_fail (page != NULL);
5361
5362   notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5363                            (GTK_MENU (widget->parent)));
5364
5365   if (notebook->cur_page == page)
5366     return;
5367
5368   page_num = 0;
5369   children = notebook->children;
5370   while (children && children->data != page)
5371     {
5372       children = children->next;
5373       page_num++;
5374     }
5375
5376   g_signal_emit (notebook,
5377                  notebook_signals[SWITCH_PAGE],
5378                  0,
5379                  page,
5380                  page_num);
5381 }
5382
5383 /* Private GtkNotebook Menu Functions:
5384  *
5385  * gtk_notebook_menu_item_create
5386  * gtk_notebook_menu_label_unparent
5387  * gtk_notebook_menu_detacher
5388  */
5389 static void
5390 gtk_notebook_menu_item_create (GtkNotebook *notebook, 
5391                                GList       *list)
5392 {       
5393   GtkNotebookPage *page;
5394   GtkWidget *menu_item;
5395
5396   page = list->data;
5397   if (page->default_menu)
5398     {
5399       if (page->tab_label && GTK_IS_LABEL (page->tab_label))
5400         page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5401       else
5402         page->menu_label = gtk_label_new ("");
5403       gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5404     }
5405
5406   gtk_widget_show (page->menu_label);
5407   menu_item = gtk_menu_item_new ();
5408   gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5409   gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5410                          gtk_notebook_real_page_position (notebook, list));
5411   g_signal_connect (menu_item, "activate",
5412                     G_CALLBACK (gtk_notebook_menu_switch_page), page);
5413   if (GTK_WIDGET_VISIBLE (page->child))
5414     gtk_widget_show (menu_item);
5415 }
5416
5417 static void
5418 gtk_notebook_menu_label_unparent (GtkWidget *widget, 
5419                                   gpointer  data)
5420 {
5421   gtk_widget_unparent (GTK_BIN(widget)->child);
5422   GTK_BIN(widget)->child = NULL;
5423 }
5424
5425 static void
5426 gtk_notebook_menu_detacher (GtkWidget *widget,
5427                             GtkMenu   *menu)
5428 {
5429   GtkNotebook *notebook;
5430
5431   g_return_if_fail (GTK_IS_NOTEBOOK (widget));
5432
5433   notebook = GTK_NOTEBOOK (widget);
5434   g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5435
5436   notebook->menu = NULL;
5437 }
5438
5439 /* Private GtkNotebook Setter Functions:
5440  *
5441  * gtk_notebook_set_homogeneous_tabs_internal
5442  * gtk_notebook_set_tab_border_internal
5443  * gtk_notebook_set_tab_hborder_internal
5444  * gtk_notebook_set_tab_vborder_internal
5445  */
5446 static void
5447 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5448                                             gboolean     homogeneous)
5449 {
5450   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5451
5452   if (homogeneous == notebook->homogeneous)
5453     return;
5454
5455   notebook->homogeneous = homogeneous;
5456   gtk_widget_queue_resize (GTK_WIDGET (notebook));
5457
5458   g_object_notify (G_OBJECT (notebook), "homogeneous");
5459 }
5460
5461 static void
5462 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
5463                                       guint        border_width)
5464 {
5465   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5466
5467   notebook->tab_hborder = border_width;
5468   notebook->tab_vborder = border_width;
5469
5470   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5471     gtk_widget_queue_resize (GTK_WIDGET (notebook));
5472
5473   g_object_freeze_notify (G_OBJECT (notebook));
5474   g_object_notify (G_OBJECT (notebook), "tab-hborder");
5475   g_object_notify (G_OBJECT (notebook), "tab-vborder");
5476   g_object_thaw_notify (G_OBJECT (notebook));
5477 }
5478
5479 static void
5480 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
5481                                        guint        tab_hborder)
5482 {
5483   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5484
5485   if (notebook->tab_hborder == tab_hborder)
5486     return;
5487
5488   notebook->tab_hborder = tab_hborder;
5489
5490   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5491     gtk_widget_queue_resize (GTK_WIDGET (notebook));
5492
5493   g_object_notify (G_OBJECT (notebook), "tab-hborder");
5494 }
5495
5496 static void
5497 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
5498                                        guint        tab_vborder)
5499 {
5500   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5501
5502   if (notebook->tab_vborder == tab_vborder)
5503     return;
5504
5505   notebook->tab_vborder = tab_vborder;
5506
5507   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5508     gtk_widget_queue_resize (GTK_WIDGET (notebook));
5509
5510   g_object_notify (G_OBJECT (notebook), "tab-vborder");
5511 }
5512
5513 /* Public GtkNotebook Page Insert/Remove Methods :
5514  *
5515  * gtk_notebook_append_page
5516  * gtk_notebook_append_page_menu
5517  * gtk_notebook_prepend_page
5518  * gtk_notebook_prepend_page_menu
5519  * gtk_notebook_insert_page
5520  * gtk_notebook_insert_page_menu
5521  * gtk_notebook_remove_page
5522  */
5523 /**
5524  * gtk_notebook_append_page:
5525  * @notebook: a #GtkNotebook
5526  * @child: the #GtkWidget to use as the contents of the page.
5527  * @tab_label: the #GtkWidget to be used as the label for the page,
5528  *             or %NULL to use the default label, 'page N'.
5529  * 
5530  * Appends a page to @notebook.
5531  *
5532  * Return value: the index (starting from 0) of the appended
5533  * page in the notebook, or -1 if function fails
5534  **/
5535 gint
5536 gtk_notebook_append_page (GtkNotebook *notebook,
5537                           GtkWidget   *child,
5538                           GtkWidget   *tab_label)
5539 {
5540   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5541   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5542   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5543   
5544   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
5545 }
5546
5547 /**
5548  * gtk_notebook_append_page_menu:
5549  * @notebook: a #GtkNotebook
5550  * @child: the #GtkWidget to use as the contents of the page.
5551  * @tab_label: the #GtkWidget to be used as the label for the page,
5552  *             or %NULL to use the default label, 'page N'.
5553  * @menu_label: the widget to use as a label for the page-switch
5554  *              menu, if that is enabled. If %NULL, and @tab_label
5555  *              is a #GtkLabel or %NULL, then the menu label will be
5556  *              a newly created label with the same text as @tab_label;
5557  *              If @tab_label is not a #GtkLabel, @menu_label must be
5558  *              specified if the page-switch menu is to be used.
5559  * 
5560  * Appends a page to @notebook, specifying the widget to use as the
5561  * label in the popup menu.
5562  *
5563  * Return value: the index (starting from 0) of the appended
5564  * page in the notebook, or -1 if function fails
5565  **/
5566 gint
5567 gtk_notebook_append_page_menu (GtkNotebook *notebook,
5568                                GtkWidget   *child,
5569                                GtkWidget   *tab_label,
5570                                GtkWidget   *menu_label)
5571 {
5572   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5573   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5574   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5575   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
5576   
5577   return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
5578 }
5579
5580 /**
5581  * gtk_notebook_prepend_page:
5582  * @notebook: a #GtkNotebook
5583  * @child: the #GtkWidget to use as the contents of the page.
5584  * @tab_label: the #GtkWidget to be used as the label for the page,
5585  *             or %NULL to use the default label, 'page N'.
5586  *
5587  * Prepends a page to @notebook.
5588  *
5589  * Return value: the index (starting from 0) of the prepended
5590  * page in the notebook, or -1 if function fails
5591  **/
5592 gint
5593 gtk_notebook_prepend_page (GtkNotebook *notebook,
5594                            GtkWidget   *child,
5595                            GtkWidget   *tab_label)
5596 {
5597   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5598   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5599   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5600   
5601   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
5602 }
5603
5604 /**
5605  * gtk_notebook_prepend_page_menu:
5606  * @notebook: a #GtkNotebook
5607  * @child: the #GtkWidget to use as the contents of the page.
5608  * @tab_label: the #GtkWidget to be used as the label for the page,
5609  *             or %NULL to use the default label, 'page N'.
5610  * @menu_label: the widget to use as a label for the page-switch
5611  *              menu, if that is enabled. If %NULL, and @tab_label
5612  *              is a #GtkLabel or %NULL, then the menu label will be
5613  *              a newly created label with the same text as @tab_label;
5614  *              If @tab_label is not a #GtkLabel, @menu_label must be
5615  *              specified if the page-switch menu is to be used.
5616  * 
5617  * Prepends a page to @notebook, specifying the widget to use as the
5618  * label in the popup menu.
5619  *
5620  * Return value: the index (starting from 0) of the prepended
5621  * page in the notebook, or -1 if function fails
5622  **/
5623 gint
5624 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
5625                                 GtkWidget   *child,
5626                                 GtkWidget   *tab_label,
5627                                 GtkWidget   *menu_label)
5628 {
5629   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5630   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5631   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5632   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
5633   
5634   return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
5635 }
5636
5637 /**
5638  * gtk_notebook_insert_page:
5639  * @notebook: a #GtkNotebook
5640  * @child: the #GtkWidget to use as the contents of the page.
5641  * @tab_label: the #GtkWidget to be used as the label for the page,
5642  *             or %NULL to use the default label, 'page N'.
5643  * @position: the index (starting at 0) at which to insert the page,
5644  *            or -1 to append the page after all other pages.
5645  * 
5646  * Insert a page into @notebook at the given position.
5647  *
5648  * Return value: the index (starting from 0) of the inserted
5649  * page in the notebook, or -1 if function fails
5650  **/
5651 gint
5652 gtk_notebook_insert_page (GtkNotebook *notebook,
5653                           GtkWidget   *child,
5654                           GtkWidget   *tab_label,
5655                           gint         position)
5656 {
5657   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5658   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5659   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5660   
5661   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
5662 }
5663
5664
5665 static gint
5666 gtk_notebook_page_compare_tab (gconstpointer a,
5667                                gconstpointer b)
5668 {
5669   return (((GtkNotebookPage *) a)->tab_label != b);
5670 }
5671
5672 static gboolean
5673 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
5674                                             gboolean overload,
5675                                             gpointer data)
5676 {
5677   GtkNotebook *notebook = GTK_NOTEBOOK (data);
5678   GList *list;
5679   
5680   list = g_list_find_custom (notebook->children, child,
5681                              gtk_notebook_page_compare_tab);
5682   if (list)
5683     {
5684       GtkNotebookPage *page = list->data;
5685
5686       gtk_widget_grab_focus (GTK_WIDGET (notebook));    /* Do this first to avoid focusing new page */
5687       gtk_notebook_switch_page (notebook, page,  -1);
5688       focus_tabs_in (notebook);
5689     }
5690
5691   return TRUE;
5692 }
5693
5694 /**
5695  * gtk_notebook_insert_page_menu:
5696  * @notebook: a #GtkNotebook
5697  * @child: the #GtkWidget to use as the contents of the page.
5698  * @tab_label: the #GtkWidget to be used as the label for the page,
5699  *             or %NULL to use the default label, 'page N'.
5700  * @menu_label: the widget to use as a label for the page-switch
5701  *              menu, if that is enabled. If %NULL, and @tab_label
5702  *              is a #GtkLabel or %NULL, then the menu label will be
5703  *              a newly created label with the same text as @tab_label;
5704  *              If @tab_label is not a #GtkLabel, @menu_label must be
5705  *              specified if the page-switch menu is to be used.
5706  * @position: the index (starting at 0) at which to insert the page,
5707  *            or -1 to append the page after all other pages.
5708  * 
5709  * Insert a page into @notebook at the given position, specifying
5710  * the widget to use as the label in the popup menu.
5711  *
5712  * Return value: the index (starting from 0) of the inserted
5713  * page in the notebook
5714  **/
5715 gint
5716 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
5717                                GtkWidget   *child,
5718                                GtkWidget   *tab_label,
5719                                GtkWidget   *menu_label,
5720                                gint         position)
5721 {
5722   GtkNotebookClass *class;
5723
5724   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5725   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
5726   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
5727   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
5728
5729   class = GTK_NOTEBOOK_GET_CLASS (notebook);
5730
5731   return (class->insert_page) (notebook, child, tab_label, menu_label, position);
5732 }
5733
5734 /**
5735  * gtk_notebook_remove_page:
5736  * @notebook: a #GtkNotebook.
5737  * @page_num: the index of a notebook page, starting
5738  *            from 0. If -1, the last page will
5739  *            be removed.
5740  * 
5741  * Removes a page from the notebook given its index
5742  * in the notebook.
5743  **/
5744 void
5745 gtk_notebook_remove_page (GtkNotebook *notebook,
5746                           gint         page_num)
5747 {
5748   GList *list = NULL;
5749
5750   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5751
5752   if (page_num >= 0)
5753     list = g_list_nth (notebook->children, page_num);
5754   else
5755     list = g_list_last (notebook->children);
5756
5757   if (list)
5758     gtk_container_remove (GTK_CONTAINER (notebook),
5759                           ((GtkNotebookPage *) list->data)->child);
5760 }
5761
5762 /* Public GtkNotebook Page Switch Methods :
5763  * gtk_notebook_get_current_page
5764  * gtk_notebook_page_num
5765  * gtk_notebook_set_current_page
5766  * gtk_notebook_next_page
5767  * gtk_notebook_prev_page
5768  */
5769 /**
5770  * gtk_notebook_get_current_page:
5771  * @notebook: a #GtkNotebook
5772  * 
5773  * Returns the page number of the current page.
5774  * 
5775  * Return value: the index (starting from 0) of the current
5776  * page in the notebook. If the notebook has no pages, then
5777  * -1 will be returned.
5778  **/
5779 gint
5780 gtk_notebook_get_current_page (GtkNotebook *notebook)
5781 {
5782   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5783
5784   if (!notebook->cur_page)
5785     return -1;
5786
5787   return g_list_index (notebook->children, notebook->cur_page);
5788 }
5789
5790 /**
5791  * gtk_notebook_get_nth_page:
5792  * @notebook: a #GtkNotebook
5793  * @page_num: the index of a page in the noteobok, or -1
5794  *            to get the last page.
5795  * 
5796  * Returns the child widget contained in page number @page_num.
5797  * 
5798  * Return value: the child widget, or %NULL if @page_num is
5799  * out of bounds.
5800  **/
5801 GtkWidget*
5802 gtk_notebook_get_nth_page (GtkNotebook *notebook,
5803                            gint         page_num)
5804 {
5805   GtkNotebookPage *page;
5806   GList *list;
5807
5808   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
5809
5810   if (page_num >= 0)
5811     list = g_list_nth (notebook->children, page_num);
5812   else
5813     list = g_list_last (notebook->children);
5814
5815   if (list)
5816     {
5817       page = list->data;
5818       return page->child;
5819     }
5820
5821   return NULL;
5822 }
5823
5824 /**
5825  * gtk_notebook_get_n_pages:
5826  * @notebook: a #GtkNotebook
5827  * 
5828  * Gets the number of pages in a notebook.
5829  * 
5830  * Return value: the number of pages in the notebook.
5831  *
5832  * Since: 2.2
5833  **/
5834 gint
5835 gtk_notebook_get_n_pages (GtkNotebook *notebook)
5836 {
5837   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
5838
5839   return g_list_length (notebook->children);
5840 }
5841
5842 /**
5843  * gtk_notebook_page_num:
5844  * @notebook: a #GtkNotebook
5845  * @child: a #GtkWidget
5846  * 
5847  * Finds the index of the page which contains the given child
5848  * widget.
5849  * 
5850  * Return value: the index of the page containing @child, or
5851  *   -1 if @child is not in the notebook.
5852  **/
5853 gint
5854 gtk_notebook_page_num (GtkNotebook      *notebook,
5855                        GtkWidget        *child)
5856 {
5857   GList *children;
5858   gint num;
5859
5860   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
5861
5862   num = 0;
5863   children = notebook->children;
5864   while (children)
5865     {
5866       GtkNotebookPage *page =  children->data;
5867       
5868       if (page->child == child)
5869         return num;
5870
5871       children = children->next;
5872       num++;
5873     }
5874
5875   return -1;
5876 }
5877
5878 /**
5879  * gtk_notebook_set_current_page:
5880  * @notebook: a #GtkNotebook
5881  * @page_num: index of the page to switch to, starting from 0.
5882  *            If negative, the last page will be used. If greater
5883  *            than the number of pages in the notebook, nothing
5884  *            will be done.
5885  *                
5886  * Switches to the page number @page_num.
5887  **/
5888 void
5889 gtk_notebook_set_current_page (GtkNotebook *notebook,
5890                                gint         page_num)
5891 {
5892   GList *list;
5893
5894   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5895
5896   if (page_num >= 0)
5897     list = g_list_nth (notebook->children, page_num);
5898   else
5899     list = g_list_last (notebook->children);
5900
5901   page_num = g_list_index (notebook->children, list);
5902
5903   if (list)
5904     gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num);
5905 }
5906
5907 /**
5908  * gtk_notebook_next_page:
5909  * @notebook: a #GtkNotebook
5910  * 
5911  * Switches to the next page. Nothing happens if the current page is
5912  * the last page.
5913  **/
5914 void
5915 gtk_notebook_next_page (GtkNotebook *notebook)
5916 {
5917   GList *list;
5918
5919   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5920
5921   list = g_list_find (notebook->children, notebook->cur_page);
5922   if (!list)
5923     return;
5924
5925   list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
5926   if (!list)
5927     return;
5928
5929   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
5930 }
5931
5932 /**
5933  * gtk_notebook_prev_page:
5934  * @notebook: a #GtkNotebook
5935  * 
5936  * Switches to the previous page. Nothing happens if the current page
5937  * is the first page.
5938  **/
5939 void
5940 gtk_notebook_prev_page (GtkNotebook *notebook)
5941 {
5942   GList *list;
5943
5944   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5945
5946   list = g_list_find (notebook->children, notebook->cur_page);
5947   if (!list)
5948     return;
5949
5950   list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
5951   if (!list)
5952     return;
5953
5954   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1);
5955 }
5956
5957 /* Public GtkNotebook/Tab Style Functions
5958  *
5959  * gtk_notebook_set_show_border
5960  * gtk_notebook_set_show_tabs
5961  * gtk_notebook_set_tab_pos
5962  * gtk_notebook_set_homogeneous_tabs
5963  * gtk_notebook_set_tab_border
5964  * gtk_notebook_set_tab_hborder
5965  * gtk_notebook_set_tab_vborder
5966  * gtk_notebook_set_scrollable
5967  */
5968 /**
5969  * gtk_notebook_set_show_border:
5970  * @notebook: a #GtkNotebook
5971  * @show_border: %TRUE if a bevel should be drawn around the notebook.
5972  * 
5973  * Sets whether a bevel will be drawn around the notebook pages.
5974  * This only has a visual effect when the tabs are not shown.
5975  * See gtk_notebook_set_show_tabs().
5976  **/
5977 void
5978 gtk_notebook_set_show_border (GtkNotebook *notebook,
5979                               gboolean     show_border)
5980 {
5981   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
5982
5983   if (notebook->show_border != show_border)
5984     {
5985       notebook->show_border = show_border;
5986
5987       if (GTK_WIDGET_VISIBLE (notebook))
5988         gtk_widget_queue_resize (GTK_WIDGET (notebook));
5989       
5990       g_object_notify (G_OBJECT (notebook), "show-border");
5991     }
5992 }
5993
5994 /**
5995  * gtk_notebook_get_show_border:
5996  * @notebook: a #GtkNotebook
5997  *
5998  * Returns whether a bevel will be drawn around the notebook pages. See
5999  * gtk_notebook_set_show_border().
6000  *
6001  * Return value: %TRUE if the bevel is drawn
6002  **/
6003 gboolean
6004 gtk_notebook_get_show_border (GtkNotebook *notebook)
6005 {
6006   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6007
6008   return notebook->show_border;
6009 }
6010
6011 /**
6012  * gtk_notebook_set_show_tabs:
6013  * @notebook: a #GtkNotebook
6014  * @show_tabs: %TRUE if the tabs should be shown.
6015  * 
6016  * Sets whether to show the tabs for the notebook or not.
6017  **/
6018 void
6019 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6020                             gboolean     show_tabs)
6021 {
6022   GtkNotebookPage *page;
6023   GList *children;
6024
6025   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6026
6027   show_tabs = show_tabs != FALSE;
6028
6029   if (notebook->show_tabs == show_tabs)
6030     return;
6031
6032   notebook->show_tabs = show_tabs;
6033   children = notebook->children;
6034
6035   if (!show_tabs)
6036     {
6037       GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6038       
6039       while (children)
6040         {
6041           page = children->data;
6042           children = children->next;
6043           if (page->default_tab)
6044             {
6045               gtk_widget_destroy (page->tab_label);
6046               page->tab_label = NULL;
6047             }
6048           else
6049             gtk_widget_hide (page->tab_label);
6050         }
6051     }
6052   else
6053     {
6054       GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6055       gtk_notebook_update_labels (notebook);
6056     }
6057   gtk_widget_queue_resize (GTK_WIDGET (notebook));
6058
6059   g_object_notify (G_OBJECT (notebook), "show-tabs");
6060 }
6061
6062 /**
6063  * gtk_notebook_get_show_tabs:
6064  * @notebook: a #GtkNotebook
6065  *
6066  * Returns whether the tabs of the notebook are shown. See
6067  * gtk_notebook_set_show_tabs().
6068  *
6069  * Return value: %TRUE if the tabs are shown
6070  **/
6071 gboolean
6072 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6073 {
6074   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6075
6076   return notebook->show_tabs;
6077 }
6078
6079 /**
6080  * gtk_notebook_set_tab_pos:
6081  * @notebook: a #GtkNotebook.
6082  * @pos: the edge to draw the tabs at.
6083  * 
6084  * Sets the edge at which the tabs for switching pages in the
6085  * notebook are drawn.
6086  **/
6087 void
6088 gtk_notebook_set_tab_pos (GtkNotebook     *notebook,
6089                           GtkPositionType  pos)
6090 {
6091   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6092
6093   if (notebook->tab_pos != pos)
6094     {
6095       notebook->tab_pos = pos;
6096       if (GTK_WIDGET_VISIBLE (notebook))
6097         gtk_widget_queue_resize (GTK_WIDGET (notebook));
6098     }
6099
6100   g_object_notify (G_OBJECT (notebook), "tab-pos");
6101 }
6102
6103 /**
6104  * gtk_notebook_get_tab_pos:
6105  * @notebook: a #GtkNotebook
6106  *
6107  * Gets the edge at which the tabs for switching pages in the
6108  * notebook are drawn.
6109  *
6110  * Return value: the edge at which the tabs are drawn
6111  **/
6112 GtkPositionType
6113 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6114 {
6115   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6116
6117   return notebook->tab_pos;
6118 }
6119
6120 /**
6121  * gtk_notebook_set_homogeneous_tabs:
6122  * @notebook: a #GtkNotebook
6123  * @homogeneous: %TRUE if all tabs should be the same size.
6124  * 
6125  * Sets whether the tabs must have all the same size or not.
6126  **/
6127 void
6128 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6129                                    gboolean     homogeneous)
6130 {
6131   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6132
6133   gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6134 }
6135
6136 /**
6137  * gtk_notebook_set_tab_border:
6138  * @notebook: a #GtkNotebook
6139  * @border_width: width of the border around the tab labels.
6140  * 
6141  * Sets the width the border around the tab labels
6142  * in a notebook. This is equivalent to calling
6143  * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6144  * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6145  **/
6146 void
6147 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6148                              guint        border_width)
6149 {
6150   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6151
6152   gtk_notebook_set_tab_border_internal (notebook, border_width);
6153 }
6154
6155 /**
6156  * gtk_notebook_set_tab_hborder:
6157  * @notebook: a #GtkNotebook
6158  * @tab_hborder: width of the horizontal border of tab labels.
6159  * 
6160  * Sets the width of the horizontal border of tab labels.
6161  **/
6162 void
6163 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6164                               guint        tab_hborder)
6165 {
6166   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6167
6168   gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6169 }
6170
6171 /**
6172  * gtk_notebook_set_tab_vborder:
6173  * @notebook: a #GtkNotebook
6174  * @tab_vborder: width of the vertical border of tab labels.
6175  * 
6176  * Sets the width of the vertical border of tab labels.
6177  **/
6178 void
6179 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6180                               guint        tab_vborder)
6181 {
6182   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6183
6184   gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6185 }
6186
6187 /**
6188  * gtk_notebook_set_scrollable:
6189  * @notebook: a #GtkNotebook
6190  * @scrollable: %TRUE if scroll arrows should be added
6191  * 
6192  * Sets whether the tab label area will have arrows for scrolling if
6193  * there are too many tabs to fit in the area.
6194  **/
6195 void
6196 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6197                              gboolean     scrollable)
6198 {
6199   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6200
6201   scrollable = (scrollable != FALSE);
6202
6203   if (scrollable != notebook->scrollable)
6204     {
6205       notebook->scrollable = scrollable;
6206
6207       if (GTK_WIDGET_VISIBLE (notebook))
6208         gtk_widget_queue_resize (GTK_WIDGET (notebook));
6209
6210       g_object_notify (G_OBJECT (notebook), "scrollable");
6211     }
6212 }
6213
6214 /**
6215  * gtk_notebook_get_scrollable:
6216  * @notebook: a #GtkNotebook
6217  *
6218  * Returns whether the tab label area has arrows for scrolling. See
6219  * gtk_notebook_set_scrollable().
6220  *
6221  * Return value: %TRUE if arrows for scrolling are present
6222  **/
6223 gboolean
6224 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6225 {
6226   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6227
6228   return notebook->scrollable;
6229 }
6230
6231 /* Public GtkNotebook Popup Menu Methods:
6232  *
6233  * gtk_notebook_popup_enable
6234  * gtk_notebook_popup_disable
6235  */
6236
6237
6238 /**
6239  * gtk_notebook_popup_enable:
6240  * @notebook: a #GtkNotebook
6241  * 
6242  * Enables the popup menu: if the user clicks with the right mouse button on
6243  * the bookmarks, a menu with all the pages will be popped up.
6244  **/
6245 void
6246 gtk_notebook_popup_enable (GtkNotebook *notebook)
6247 {
6248   GList *list;
6249
6250   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6251
6252   if (notebook->menu)
6253     return;
6254
6255   notebook->menu = gtk_menu_new ();
6256   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6257        list;
6258        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6259     gtk_notebook_menu_item_create (notebook, list);
6260
6261   gtk_notebook_update_labels (notebook);
6262   gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6263                              GTK_WIDGET (notebook),
6264                              gtk_notebook_menu_detacher);
6265
6266   g_object_notify (G_OBJECT (notebook), "enable-popup");
6267 }
6268
6269 /**
6270  * gtk_notebook_popup_disable:
6271  * @notebook: a #GtkNotebook
6272  * 
6273  * Disables the popup menu.
6274  **/
6275 void       
6276 gtk_notebook_popup_disable  (GtkNotebook *notebook)
6277 {
6278   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6279
6280   if (!notebook->menu)
6281     return;
6282
6283   gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6284                          (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6285   gtk_widget_destroy (notebook->menu);
6286
6287   g_object_notify (G_OBJECT (notebook), "enable-popup");
6288 }
6289
6290 /* Public GtkNotebook Page Properties Functions:
6291  *
6292  * gtk_notebook_get_tab_label
6293  * gtk_notebook_set_tab_label
6294  * gtk_notebook_set_tab_label_text
6295  * gtk_notebook_get_menu_label
6296  * gtk_notebook_set_menu_label
6297  * gtk_notebook_set_menu_label_text
6298  * gtk_notebook_set_tab_label_packing
6299  * gtk_notebook_query_tab_label_packing
6300  * gtk_notebook_get_tab_reorderable
6301  * gtk_notebook_set_tab_reorderable
6302  * gtk_notebook_get_tab_detachable
6303  * gtk_notebook_set_tab_detachable
6304  */
6305
6306 /**
6307  * gtk_notebook_get_tab_label:
6308  * @notebook: a #GtkNotebook
6309  * @child: the page
6310  * 
6311  * Returns the tab label widget for the page @child. %NULL is returned
6312  * if @child is not in @notebook or if no tab label has specifically
6313  * been set for @child.
6314  * 
6315  * Return value: the tab label
6316  **/
6317 GtkWidget *
6318 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6319                             GtkWidget   *child)
6320 {
6321   GList *list;
6322
6323   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6324   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6325
6326   list = CHECK_FIND_CHILD (notebook, child);
6327   if (!list)  
6328     return NULL;
6329
6330   if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6331     return NULL;
6332
6333   return GTK_NOTEBOOK_PAGE (list)->tab_label;
6334 }  
6335
6336 /**
6337  * gtk_notebook_set_tab_label:
6338  * @notebook: a #GtkNotebook
6339  * @child: the page
6340  * @tab_label: the tab label widget to use, or %NULL for default tab
6341  *             label.
6342  * 
6343  * Changes the tab label for @child. If %NULL is specified
6344  * for @tab_label, then the page will have the label 'page N'.
6345  **/
6346 void
6347 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6348                             GtkWidget   *child,
6349                             GtkWidget   *tab_label)
6350 {
6351   GtkNotebookPage *page;
6352   GList *list;
6353
6354   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6355   g_return_if_fail (GTK_IS_WIDGET (child));
6356
6357   list = CHECK_FIND_CHILD (notebook, child);
6358   if (!list)  
6359     return;
6360
6361   /* a NULL pointer indicates a default_tab setting, otherwise
6362    * we need to set the associated label
6363    */
6364   page = list->data;
6365   
6366   if (page->tab_label == tab_label)
6367     return;
6368   
6369
6370   gtk_notebook_remove_tab_label (notebook, page);
6371   
6372   if (tab_label)
6373     {
6374       page->default_tab = FALSE;
6375       page->tab_label = tab_label;
6376       gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6377     }
6378   else
6379     {
6380       page->default_tab = TRUE;
6381       page->tab_label = NULL;
6382
6383       if (notebook->show_tabs)
6384         {
6385           gchar string[32];
6386
6387           g_snprintf (string, sizeof(string), _("Page %u"), 
6388                       gtk_notebook_real_page_position (notebook, list));
6389           page->tab_label = gtk_label_new (string);
6390           gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6391         }
6392     }
6393
6394   if (page->tab_label)
6395     page->mnemonic_activate_signal =
6396       g_signal_connect (page->tab_label,
6397                         "mnemonic_activate",
6398                         G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6399                         notebook);
6400
6401   if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6402     {
6403       gtk_widget_show (page->tab_label);
6404       gtk_widget_queue_resize (GTK_WIDGET (notebook));
6405     }
6406
6407   gtk_notebook_update_tab_states (notebook);
6408   gtk_widget_child_notify (child, "tab-label");
6409 }
6410
6411 /**
6412  * gtk_notebook_set_tab_label_text:
6413  * @notebook: a #GtkNotebook
6414  * @child: the page
6415  * @tab_text: the label text
6416  * 
6417  * Creates a new label and sets it as the tab label for the page
6418  * containing @child.
6419  **/
6420 void
6421 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6422                                  GtkWidget   *child,
6423                                  const gchar *tab_text)
6424 {
6425   GtkWidget *tab_label = NULL;
6426
6427   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6428
6429   if (tab_text)
6430     tab_label = gtk_label_new (tab_text);
6431   gtk_notebook_set_tab_label (notebook, child, tab_label);
6432   gtk_widget_child_notify (child, "tab-label");
6433 }
6434
6435 /**
6436  * gtk_notebook_get_tab_label_text:
6437  * @notebook: a #GtkNotebook
6438  * @child: a widget contained in a page of @notebook
6439  *
6440  * Retrieves the text of the tab label for the page containing
6441  *    @child.
6442  *
6443  * Returns value: the text of the tab label, or %NULL if the
6444  *                tab label widget is not a #GtkLabel. The
6445  *                string is owned by the widget and must not
6446  *                be freed.
6447  **/
6448 G_CONST_RETURN gchar *
6449 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6450                                  GtkWidget   *child)
6451 {
6452   GtkWidget *tab_label;
6453
6454   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6455   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6456
6457   tab_label = gtk_notebook_get_tab_label (notebook, child);
6458
6459   if (tab_label && GTK_IS_LABEL (tab_label))
6460     return gtk_label_get_text (GTK_LABEL (tab_label));
6461   else
6462     return NULL;
6463 }
6464
6465 /**
6466  * gtk_notebook_get_menu_label:
6467  * @notebook: a #GtkNotebook
6468  * @child: a widget contained in a page of @notebook
6469  * 
6470  * Retrieves the menu label widget of the page containing @child.
6471  * 
6472  * Return value: the menu label, or %NULL if the
6473  *               notebook page does not have a menu label other
6474  *               than the default (the tab label).
6475  **/
6476 GtkWidget*
6477 gtk_notebook_get_menu_label (GtkNotebook *notebook,
6478                              GtkWidget   *child)
6479 {
6480   GList *list;
6481
6482   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6483   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6484
6485   list = CHECK_FIND_CHILD (notebook, child);
6486   if (!list)  
6487     return NULL;
6488
6489   if (GTK_NOTEBOOK_PAGE (list)->default_menu)
6490     return NULL;
6491
6492   return GTK_NOTEBOOK_PAGE (list)->menu_label;
6493 }  
6494
6495 /**
6496  * gtk_notebook_set_menu_label:
6497  * @notebook: a #GtkNotebook
6498  * @child: the child widget
6499  * @menu_label: the menu label, or NULL for default
6500  * 
6501  * Changes the menu label for the page containing @child. 
6502  **/
6503 void
6504 gtk_notebook_set_menu_label (GtkNotebook *notebook,
6505                              GtkWidget   *child,
6506                              GtkWidget   *menu_label)
6507 {
6508   GtkNotebookPage *page;
6509   GList *list;
6510
6511   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6512   g_return_if_fail (GTK_IS_WIDGET (child));
6513
6514   list = CHECK_FIND_CHILD (notebook, child);
6515   if (!list)  
6516     return;
6517
6518   page = list->data;
6519   if (page->menu_label)
6520     {
6521       if (notebook->menu)
6522         gtk_container_remove (GTK_CONTAINER (notebook->menu), 
6523                               page->menu_label->parent);
6524
6525       if (!page->default_menu)
6526         g_object_unref (page->menu_label);
6527     }
6528
6529   if (menu_label)
6530     {
6531       page->menu_label = menu_label;
6532       g_object_ref_sink (page->menu_label);
6533       page->default_menu = FALSE;
6534     }
6535   else
6536     page->default_menu = TRUE;
6537
6538   if (notebook->menu)
6539     gtk_notebook_menu_item_create (notebook, list);
6540   gtk_widget_child_notify (child, "menu-label");
6541 }
6542
6543 /**
6544  * gtk_notebook_set_menu_label_text:
6545  * @notebook: a #GtkNotebook
6546  * @child: the child widget
6547  * @menu_text: the label text
6548  * 
6549  * Creates a new label and sets it as the menu label of @child.
6550  **/
6551 void
6552 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
6553                                   GtkWidget   *child,
6554                                   const gchar *menu_text)
6555 {
6556   GtkWidget *menu_label = NULL;
6557
6558   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6559
6560   if (menu_text)
6561     menu_label = gtk_label_new (menu_text);
6562   gtk_notebook_set_menu_label (notebook, child, menu_label);
6563   gtk_widget_child_notify (child, "menu-label");
6564 }
6565
6566 /**
6567  * gtk_notebook_get_menu_label_text:
6568  * @notebook: a #GtkNotebook
6569  * @child: the child widget of a page of the notebook.
6570  *
6571  * Retrieves the text of the menu label for the page containing
6572  *    @child.
6573  *
6574  * Returns value: the text of the tab label, or %NULL if the
6575  *                widget does not have a menu label other than
6576  *                the default menu label, or the menu label widget
6577  *                is not a #GtkLabel. The string is owned by
6578  *                the widget and must not be freed.
6579  **/
6580 G_CONST_RETURN gchar *
6581 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
6582                                   GtkWidget *child)
6583 {
6584   GtkWidget *menu_label;
6585
6586   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6587   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6588  
6589   menu_label = gtk_notebook_get_menu_label (notebook, child);
6590
6591   if (menu_label && GTK_IS_LABEL (menu_label))
6592     return gtk_label_get_text (GTK_LABEL (menu_label));
6593   else
6594     return NULL;
6595 }
6596   
6597 /* Helper function called when pages are reordered
6598  */
6599 static void
6600 gtk_notebook_child_reordered (GtkNotebook     *notebook,
6601                               GtkNotebookPage *page)
6602 {
6603   if (notebook->menu)
6604     {
6605       GtkWidget *menu_item;
6606       
6607       menu_item = page->menu_label->parent;
6608       gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
6609       gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
6610       gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
6611     }
6612
6613   gtk_notebook_update_tab_states (notebook);
6614   gtk_notebook_update_labels (notebook);
6615 }
6616
6617 /**
6618  * gtk_notebook_set_tab_label_packing:
6619  * @notebook: a #GtkNotebook
6620  * @child: the child widget
6621  * @expand: whether to expand the bookmark or not
6622  * @fill: whether the bookmark should fill the allocated area or not
6623  * @pack_type: the position of the bookmark
6624  * 
6625  * Sets the packing parameters for the tab label of the page
6626  * containing @child. See gtk_box_pack_start() for the exact meaning
6627  * of the parameters.
6628  **/
6629 void
6630 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
6631                                     GtkWidget   *child,
6632                                     gboolean     expand,
6633                                     gboolean     fill,
6634                                     GtkPackType  pack_type)
6635 {
6636   GtkNotebookPage *page;
6637   GList *list;
6638
6639   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6640   g_return_if_fail (GTK_IS_WIDGET (child));
6641
6642   list = CHECK_FIND_CHILD (notebook, child);
6643   if (!list)  
6644     return;
6645
6646   page = list->data;
6647   expand = expand != FALSE;
6648   fill = fill != FALSE;
6649   if (page->pack == pack_type && page->expand == expand && page->fill == fill)
6650     return;
6651
6652   gtk_widget_freeze_child_notify (child);
6653   page->expand = expand;
6654   gtk_widget_child_notify (child, "tab-expand");
6655   page->fill = fill;
6656   gtk_widget_child_notify (child, "tab-fill");
6657   if (page->pack != pack_type)
6658     {
6659       page->pack = pack_type;
6660       gtk_notebook_child_reordered (notebook, page);
6661     }
6662   gtk_widget_child_notify (child, "tab-pack");
6663   gtk_widget_child_notify (child, "position");
6664   if (notebook->show_tabs)
6665     gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
6666   gtk_widget_thaw_child_notify (child);
6667 }  
6668
6669 /**
6670  * gtk_notebook_query_tab_label_packing:
6671  * @notebook: a #GtkNotebook
6672  * @child: the page
6673  * @expand: location to store the expand value (or NULL)
6674  * @fill: location to store the fill value (or NULL)
6675  * @pack_type: location to store the pack_type (or NULL)
6676  * 
6677  * Query the packing attributes for the tab label of the page
6678  * containing @child.
6679  **/
6680 void
6681 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
6682                                       GtkWidget   *child,
6683                                       gboolean    *expand,
6684                                       gboolean    *fill,
6685                                       GtkPackType *pack_type)
6686 {
6687   GList *list;
6688
6689   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6690   g_return_if_fail (GTK_IS_WIDGET (child));
6691
6692   list = CHECK_FIND_CHILD (notebook, child);
6693   if (!list)
6694     return;
6695
6696   if (expand)
6697     *expand = GTK_NOTEBOOK_PAGE (list)->expand;
6698   if (fill)
6699     *fill = GTK_NOTEBOOK_PAGE (list)->fill;
6700   if (pack_type)
6701     *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
6702 }
6703
6704 /**
6705  * gtk_notebook_reorder_child:
6706  * @notebook: a #GtkNotebook
6707  * @child: the child to move
6708  * @position: the new position, or -1 to move to the end
6709  * 
6710  * Reorders the page containing @child, so that it appears in position
6711  * @position. If @position is greater than or equal to the number of
6712  * children in the list or negative, @child will be moved to the end
6713  * of the list.
6714  **/
6715 void
6716 gtk_notebook_reorder_child (GtkNotebook *notebook,
6717                             GtkWidget   *child,
6718                             gint         position)
6719 {
6720   GList *list, *new_list;
6721   GtkNotebookPage *page;
6722   gint old_pos;
6723   gint max_pos;
6724
6725   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6726   g_return_if_fail (GTK_IS_WIDGET (child));
6727
6728   list = CHECK_FIND_CHILD (notebook, child);
6729   if (!list)
6730     return;
6731
6732   max_pos = g_list_length (notebook->children) - 1;
6733   if (position < 0 || position > max_pos)
6734     position = max_pos;
6735
6736   old_pos = g_list_position (notebook->children, list);
6737
6738   if (old_pos == position)
6739     return;
6740
6741   page = list->data;
6742   notebook->children = g_list_delete_link (notebook->children, list);
6743
6744   notebook->children = g_list_insert (notebook->children, page, position);
6745   new_list = g_list_nth (notebook->children, position);
6746
6747   /* Fix up GList references in GtkNotebook structure */
6748   if (notebook->first_tab == list)
6749     notebook->first_tab = new_list;
6750   if (notebook->focus_tab == list)
6751     notebook->focus_tab = new_list;
6752
6753   gtk_widget_freeze_child_notify (child);
6754
6755   /* Move around the menu items if necessary */
6756   gtk_notebook_child_reordered (notebook, page);
6757   gtk_widget_child_notify (child, "tab-pack");
6758   gtk_widget_child_notify (child, "position");
6759
6760   if (notebook->show_tabs)
6761     gtk_notebook_pages_allocate (notebook, DRAG_OPERATION_NONE);
6762
6763   gtk_widget_thaw_child_notify (child);
6764 }
6765
6766 /**
6767  * gtk_notebook_set_window_creation_hook:
6768  * @func: the #GtkNotebookWindowCreationFunc, or NULL
6769  * @data: user data for @func.
6770  *
6771  * Installs a global function used to create a window
6772  * when a detached tab is dropped in an empty area.
6773  * 
6774  * Since: 2.10
6775  **/
6776 void
6777 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc  func,
6778                                        gpointer                       data)
6779 {
6780   window_creation_hook = func;
6781   window_creation_hook_data = data;
6782 }
6783
6784 /**
6785  * gtk_notebook_set_group_id:
6786  * @notebook: a #GtkNotebook
6787  * @group_id: a group identificator, or -1 to unset it
6788  *
6789  * Sets an group identificator for @notebook, notebooks sharing
6790  * the same group identificator will be able to exchange tabs
6791  * via drag and drop. A notebook with group identificator -1 will
6792  * not be able to exchange tabs with any other notebook.
6793  * 
6794  * Since: 2.10
6795  **/
6796 void
6797 gtk_notebook_set_group_id (GtkNotebook *notebook,
6798                            gint         group_id)
6799 {
6800   GtkNotebookPrivate *priv;
6801
6802   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6803
6804   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
6805
6806   if (priv->group_id != group_id)
6807     {
6808       priv->group_id = group_id;
6809       g_object_notify (G_OBJECT (notebook), "group-id");
6810     }
6811 }
6812
6813 /**
6814  * gtk_notebook_get_group_id:
6815  * @notebook: a #GtkNotebook
6816  * 
6817  * Gets the current group identificator for @notebook.
6818  * 
6819  * Return Value: the group identificator, or -1 if none is set.
6820  *
6821  * Since: 2.10
6822  **/
6823 gint
6824 gtk_notebook_get_group_id (GtkNotebook *notebook)
6825 {
6826   GtkNotebookPrivate *priv;
6827
6828   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6829
6830   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
6831   return priv->group_id;
6832 }
6833
6834 /**
6835  * gtk_notebook_get_tab_reorderable:
6836  * @notebook: a #GtkNotebook
6837  * @child: a child #GtkWidget
6838  * 
6839  * Gets whether the tab can be reordered via drag and drop or not.
6840  * 
6841  * Return Value: TRUE if the tab is reorderable.
6842  **/
6843 gboolean
6844 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
6845                                   GtkWidget   *child)
6846 {
6847   GList *list;
6848
6849   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6850   g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
6851
6852   list = CHECK_FIND_CHILD (notebook, child);
6853   if (!list)  
6854     return FALSE;
6855
6856   return GTK_NOTEBOOK_PAGE (list)->reorderable;
6857 }
6858
6859 /**
6860  * gtk_notebook_set_tab_reorderable:
6861  * @notebook: a #GtkNotebook
6862  * @child: a child #GtkWidget
6863  * @reorderable: whether the tab is reorderable or not.
6864  *
6865  * Sets whether the notebook tab can be reordered
6866  * via drag and drop or not.
6867  * 
6868  * Since: 2.10
6869  **/
6870 void
6871 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
6872                                   GtkWidget   *child,
6873                                   gboolean     reorderable)
6874 {
6875   GList *list;
6876
6877   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6878   g_return_if_fail (GTK_IS_WIDGET (child));
6879
6880   list = CHECK_FIND_CHILD (notebook, child);
6881   if (!list)  
6882     return;
6883
6884   if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
6885     {
6886       GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
6887       gtk_widget_child_notify (child, "reorderable");
6888     }
6889 }
6890
6891 /**
6892  * gtk_notebook_get_tab_detachable:
6893  * @notebook: a #GtkNotebook
6894  * @child: a child #GtkWidget
6895  * 
6896  * Returns whether the tab contents can be detached from @notebook.
6897  * 
6898  * Return Value: TRUE if the tab is detachable.
6899  *
6900  * Since: 2.10
6901  **/
6902 gboolean
6903 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
6904                                  GtkWidget   *child)
6905 {
6906   GList *list;
6907
6908   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6909   g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
6910
6911   list = CHECK_FIND_CHILD (notebook, child);
6912   if (!list)  
6913     return FALSE;
6914
6915   return GTK_NOTEBOOK_PAGE (list)->detachable;
6916 }
6917
6918 /**
6919  * gtk_notebook_set_tab_detachable:
6920  * @notebook: a #GtkNotebook
6921  * @child: a child #GtkWidget
6922  * @detachable: whether the tab is detachable or not
6923  *
6924  * Sets whether the tab can be detached from @notebook to another notebook.
6925  *
6926  * Note that 2 notebooks must share a common group identificator
6927  * (see gtk_notebook_set_group_id ()) to allow tabs interchange between them.
6928  *
6929  * Since: 2.10
6930  **/
6931 void
6932 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
6933                                   GtkWidget   *child,
6934                                   gboolean     detachable)
6935 {
6936   GList *list;
6937
6938   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6939   g_return_if_fail (GTK_IS_WIDGET (child));
6940
6941   list = CHECK_FIND_CHILD (notebook, child);
6942   if (!list)  
6943     return;
6944
6945   if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
6946     {
6947       GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
6948       gtk_widget_child_notify (child, "detachable");
6949     }
6950 }
6951
6952 #define __GTK_NOTEBOOK_C__
6953 #include "gtkaliasdef.c"