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