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