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