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