]> Pileus Git - ~andy/gtk/blob - gtk/gtknotebook.c
3c639da8c4a6bf96e117c1a0b5aa20085e6a29da
[~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_is_toplevel (toplevel))
1341     return;
1342
1343   g_object_ref (notebook);
1344   
1345   notebook->focus_out = TRUE;
1346   g_signal_emit_by_name (toplevel, "move-focus", direction_type);
1347   notebook->focus_out = FALSE;
1348   
1349   g_object_unref (notebook);
1350 }
1351
1352 static gint
1353 reorder_tab (GtkNotebook *notebook, GList *position, GList *tab)
1354 {
1355   GList *elem;
1356
1357   if (position == tab)
1358     return g_list_position (notebook->children, tab);
1359
1360   /* check that we aren't inserting the tab in the
1361    * same relative position, taking packing into account */
1362   elem = (position) ? position->prev : g_list_last (notebook->children);
1363
1364   while (elem && elem != tab && GTK_NOTEBOOK_PAGE (elem)->pack != GTK_NOTEBOOK_PAGE (tab)->pack)
1365     elem = elem->prev;
1366
1367   if (elem == tab)
1368     return g_list_position (notebook->children, tab);
1369
1370   /* now actually reorder the tab */
1371   if (notebook->first_tab == tab)
1372     notebook->first_tab = gtk_notebook_search_page (notebook, notebook->first_tab,
1373                                                     STEP_NEXT, TRUE);
1374
1375   notebook->children = g_list_remove_link (notebook->children, tab);
1376
1377   if (!position)
1378     elem = g_list_last (notebook->children);
1379   else
1380     {
1381       elem = position->prev;
1382       position->prev = tab;
1383     }
1384
1385   if (elem)
1386     elem->next = tab;
1387   else
1388     notebook->children = tab;
1389
1390   tab->prev = elem;
1391   tab->next = position;
1392
1393   return g_list_position (notebook->children, tab);
1394 }
1395
1396 static gboolean
1397 gtk_notebook_reorder_tab (GtkNotebook      *notebook,
1398                           GtkDirectionType  direction_type,
1399                           gboolean          move_to_last)
1400 {
1401   GtkDirectionType effective_direction = get_effective_direction (notebook, direction_type);
1402   GtkNotebookPage *page;
1403   GList *last, *child;
1404   gint page_num;
1405
1406   if (!gtk_widget_is_focus (GTK_WIDGET (notebook)) || !notebook->show_tabs)
1407     return FALSE;
1408
1409   if (!notebook->cur_page ||
1410       !notebook->cur_page->reorderable)
1411     return FALSE;
1412
1413   if (effective_direction != GTK_DIR_LEFT &&
1414       effective_direction != GTK_DIR_RIGHT)
1415     return FALSE;
1416
1417   if (move_to_last)
1418     {
1419       child = notebook->focus_tab;
1420
1421       do
1422         {
1423           last = child;
1424           child = gtk_notebook_search_page (notebook, last, 
1425                                             (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1426                                             TRUE);
1427         }
1428       while (child && GTK_NOTEBOOK_PAGE (last)->pack == GTK_NOTEBOOK_PAGE (child)->pack);
1429
1430       child = last;
1431     }
1432   else
1433     child = gtk_notebook_search_page (notebook, notebook->focus_tab,
1434                                       (effective_direction == GTK_DIR_RIGHT) ? STEP_NEXT : STEP_PREV,
1435                                       TRUE);
1436
1437   if (!child || child->data == notebook->cur_page)
1438     return FALSE;
1439
1440   page = child->data;
1441
1442   if (page->pack == notebook->cur_page->pack)
1443     {
1444       if (effective_direction == GTK_DIR_RIGHT)
1445         page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child->next : child, notebook->focus_tab);
1446       else
1447         page_num = reorder_tab (notebook, (page->pack == GTK_PACK_START) ? child : child->next, notebook->focus_tab);
1448
1449       gtk_notebook_pages_allocate (notebook);
1450
1451       g_signal_emit (notebook,
1452                      notebook_signals[PAGE_REORDERED],
1453                      0,
1454                      ((GtkNotebookPage *) notebook->focus_tab->data)->child,
1455                      page_num);
1456
1457       return TRUE;
1458     }
1459
1460   return FALSE;
1461 }
1462
1463 /**
1464  * gtk_notebook_new:
1465  * 
1466  * Creates a new #GtkNotebook widget with no pages.
1467
1468  * Return value: the newly created #GtkNotebook
1469  **/
1470 GtkWidget*
1471 gtk_notebook_new (void)
1472 {
1473   return g_object_new (GTK_TYPE_NOTEBOOK, NULL);
1474 }
1475
1476 /* Private GtkObject Methods :
1477  * 
1478  * gtk_notebook_destroy
1479  * gtk_notebook_set_arg
1480  * gtk_notebook_get_arg
1481  */
1482 static void
1483 gtk_notebook_destroy (GtkObject *object)
1484 {
1485   GtkNotebook *notebook = GTK_NOTEBOOK (object);
1486   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1487
1488   if (notebook->menu)
1489     gtk_notebook_popup_disable (notebook);
1490
1491   if (priv->source_targets)
1492     {
1493       gtk_target_list_unref (priv->source_targets);
1494       priv->source_targets = NULL;
1495     }
1496
1497   if (priv->switch_tab_timer)
1498     {
1499       g_source_remove (priv->switch_tab_timer);
1500       priv->switch_tab_timer = 0;
1501     }
1502
1503   GTK_OBJECT_CLASS (gtk_notebook_parent_class)->destroy (object);
1504 }
1505
1506 static void
1507 gtk_notebook_set_property (GObject         *object,
1508                            guint            prop_id,
1509                            const GValue    *value,
1510                            GParamSpec      *pspec)
1511 {
1512   GtkNotebook *notebook;
1513
1514   notebook = GTK_NOTEBOOK (object);
1515
1516   switch (prop_id)
1517     {
1518     case PROP_SHOW_TABS:
1519       gtk_notebook_set_show_tabs (notebook, g_value_get_boolean (value));
1520       break;
1521     case PROP_SHOW_BORDER:
1522       gtk_notebook_set_show_border (notebook, g_value_get_boolean (value));
1523       break;
1524     case PROP_SCROLLABLE:
1525       gtk_notebook_set_scrollable (notebook, g_value_get_boolean (value));
1526       break;
1527     case PROP_ENABLE_POPUP:
1528       if (g_value_get_boolean (value))
1529         gtk_notebook_popup_enable (notebook);
1530       else
1531         gtk_notebook_popup_disable (notebook);
1532       break;
1533     case PROP_HOMOGENEOUS:
1534       gtk_notebook_set_homogeneous_tabs_internal (notebook, g_value_get_boolean (value));
1535       break;  
1536     case PROP_PAGE:
1537       gtk_notebook_set_current_page (notebook, g_value_get_int (value));
1538       break;
1539     case PROP_TAB_POS:
1540       gtk_notebook_set_tab_pos (notebook, g_value_get_enum (value));
1541       break;
1542     case PROP_TAB_BORDER:
1543       gtk_notebook_set_tab_border_internal (notebook, g_value_get_uint (value));
1544       break;
1545     case PROP_TAB_HBORDER:
1546       gtk_notebook_set_tab_hborder_internal (notebook, g_value_get_uint (value));
1547       break;
1548     case PROP_TAB_VBORDER:
1549       gtk_notebook_set_tab_vborder_internal (notebook, g_value_get_uint (value));
1550       break;
1551     case PROP_GROUP_ID:
1552       gtk_notebook_set_group_id (notebook, g_value_get_int (value));
1553       break;
1554     case PROP_GROUP:
1555       gtk_notebook_set_group (notebook, g_value_get_pointer (value));
1556       break;
1557     default:
1558       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1559       break;
1560     }
1561 }
1562
1563 static void
1564 gtk_notebook_get_property (GObject         *object,
1565                            guint            prop_id,
1566                            GValue          *value,
1567                            GParamSpec      *pspec)
1568 {
1569   GtkNotebook *notebook;
1570   GtkNotebookPrivate *priv;
1571
1572   notebook = GTK_NOTEBOOK (object);
1573   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1574
1575   switch (prop_id)
1576     {
1577     case PROP_SHOW_TABS:
1578       g_value_set_boolean (value, notebook->show_tabs);
1579       break;
1580     case PROP_SHOW_BORDER:
1581       g_value_set_boolean (value, notebook->show_border);
1582       break;
1583     case PROP_SCROLLABLE:
1584       g_value_set_boolean (value, notebook->scrollable);
1585       break;
1586     case PROP_ENABLE_POPUP:
1587       g_value_set_boolean (value, notebook->menu != NULL);
1588       break;
1589     case PROP_HOMOGENEOUS:
1590       g_value_set_boolean (value, notebook->homogeneous);
1591       break;
1592     case PROP_PAGE:
1593       g_value_set_int (value, gtk_notebook_get_current_page (notebook));
1594       break;
1595     case PROP_TAB_POS:
1596       g_value_set_enum (value, notebook->tab_pos);
1597       break;
1598     case PROP_TAB_HBORDER:
1599       g_value_set_uint (value, notebook->tab_hborder);
1600       break;
1601     case PROP_TAB_VBORDER:
1602       g_value_set_uint (value, notebook->tab_vborder);
1603       break;
1604     case PROP_GROUP_ID:
1605       g_value_set_int (value, gtk_notebook_get_group_id (notebook));
1606       break;
1607     case PROP_GROUP:
1608       g_value_set_pointer (value, priv->group);
1609       break;
1610     default:
1611       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1612       break;
1613     }
1614 }
1615
1616 /* Private GtkWidget Methods :
1617  * 
1618  * gtk_notebook_map
1619  * gtk_notebook_unmap
1620  * gtk_notebook_realize
1621  * gtk_notebook_size_request
1622  * gtk_notebook_size_allocate
1623  * gtk_notebook_expose
1624  * gtk_notebook_scroll
1625  * gtk_notebook_button_press
1626  * gtk_notebook_button_release
1627  * gtk_notebook_popup_menu
1628  * gtk_notebook_leave_notify
1629  * gtk_notebook_motion_notify
1630  * gtk_notebook_focus_in
1631  * gtk_notebook_focus_out
1632  * gtk_notebook_draw_focus
1633  * gtk_notebook_style_set
1634  * gtk_notebook_drag_begin
1635  * gtk_notebook_drag_end
1636  * gtk_notebook_drag_failed
1637  * gtk_notebook_drag_motion
1638  * gtk_notebook_drag_drop
1639  * gtk_notebook_drag_data_get
1640  * gtk_notebook_drag_data_received
1641  */
1642 static gboolean
1643 gtk_notebook_get_event_window_position (GtkNotebook  *notebook,
1644                                         GdkRectangle *rectangle)
1645 {
1646   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
1647   GtkWidget *widget = GTK_WIDGET (notebook);
1648   gint border_width = GTK_CONTAINER (notebook)->border_width;
1649   GtkNotebookPage *visible_page = NULL;
1650   GList *tmp_list;
1651   gint tab_pos = get_effective_tab_pos (notebook);
1652   gboolean is_rtl;
1653   gint i;
1654
1655   for (tmp_list = notebook->children; tmp_list; tmp_list = tmp_list->next)
1656     {
1657       GtkNotebookPage *page = tmp_list->data;
1658       if (GTK_WIDGET_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   for (i = 0; i < N_ACTION_WIDGETS; i++)
1750     {
1751       if (priv->action_widget[i] &&
1752           GTK_WIDGET_VISIBLE (priv->action_widget[i]) &&
1753           GTK_WIDGET_CHILD_VISIBLE (priv->action_widget[i]) &&
1754           !GTK_WIDGET_MAPPED (priv->action_widget[i]))
1755         gtk_widget_map (priv->action_widget[i]);
1756     }
1757
1758   if (notebook->scrollable)
1759     gtk_notebook_pages_allocate (notebook);
1760   else
1761     {
1762       children = notebook->children;
1763
1764       while (children)
1765         {
1766           page = children->data;
1767           children = children->next;
1768
1769           if (page->tab_label &&
1770               GTK_WIDGET_VISIBLE (page->tab_label) &&
1771               !GTK_WIDGET_MAPPED (page->tab_label))
1772             gtk_widget_map (page->tab_label);
1773         }
1774     }
1775
1776   if (gtk_notebook_get_event_window_position (notebook, NULL))
1777     gdk_window_show_unraised (notebook->event_window);
1778 }
1779
1780 static void
1781 gtk_notebook_unmap (GtkWidget *widget)
1782 {
1783   stop_scrolling (GTK_NOTEBOOK (widget));
1784   
1785   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1786
1787   gdk_window_hide (GTK_NOTEBOOK (widget)->event_window);
1788
1789   GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unmap (widget);
1790 }
1791
1792 static void
1793 gtk_notebook_realize (GtkWidget *widget)
1794 {
1795   GtkNotebook *notebook;
1796   GdkWindowAttr attributes;
1797   gint attributes_mask;
1798   GdkRectangle event_window_pos;
1799
1800   notebook = GTK_NOTEBOOK (widget);
1801   GTK_WIDGET_SET_FLAGS (notebook, GTK_REALIZED);
1802
1803   gtk_notebook_get_event_window_position (notebook, &event_window_pos);
1804   
1805   widget->window = gtk_widget_get_parent_window (widget);
1806   g_object_ref (widget->window);
1807   
1808   attributes.window_type = GDK_WINDOW_CHILD;
1809   attributes.x = event_window_pos.x;
1810   attributes.y = event_window_pos.y;
1811   attributes.width = event_window_pos.width;
1812   attributes.height = event_window_pos.height;
1813   attributes.wclass = GDK_INPUT_ONLY;
1814   attributes.event_mask = gtk_widget_get_events (widget);
1815   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1816                             GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK |
1817                             GDK_POINTER_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK |
1818                             GDK_SCROLL_MASK);
1819   attributes_mask = GDK_WA_X | GDK_WA_Y;
1820
1821   notebook->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), 
1822                                            &attributes, attributes_mask);
1823   gdk_window_set_user_data (notebook->event_window, notebook);
1824
1825   widget->style = gtk_style_attach (widget->style, widget->window);
1826 }
1827
1828 static void
1829 gtk_notebook_unrealize (GtkWidget *widget)
1830 {
1831   GtkNotebook *notebook;
1832   GtkNotebookPrivate *priv;
1833
1834   notebook = GTK_NOTEBOOK (widget);
1835   priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1836
1837   gdk_window_set_user_data (notebook->event_window, NULL);
1838   gdk_window_destroy (notebook->event_window);
1839   notebook->event_window = NULL;
1840
1841   if (priv->drag_window)
1842     {
1843       gdk_window_set_user_data (priv->drag_window, NULL);
1844       gdk_window_destroy (priv->drag_window);
1845       priv->drag_window = NULL;
1846     }
1847
1848   GTK_WIDGET_CLASS (gtk_notebook_parent_class)->unrealize (widget);
1849 }
1850
1851 static void
1852 gtk_notebook_size_request (GtkWidget      *widget,
1853                            GtkRequisition *requisition)
1854 {
1855   GtkNotebookPrivate *priv = GTK_NOTEBOOK_GET_PRIVATE (widget);
1856   GtkNotebook *notebook = GTK_NOTEBOOK (widget);
1857   GtkNotebookPage *page;
1858   GList *children;
1859   GtkRequisition child_requisition;
1860   GtkRequisition action_widget_requisition[2] = { { 0 }, { 0 } };
1861   gboolean switch_page = FALSE;
1862   gint vis_pages;
1863   gint focus_width;
1864   gint tab_overlap;
1865   gint tab_curvature;
1866   gint arrow_spacing;
1867   gint scroll_arrow_hlength;
1868   gint scroll_arrow_vlength;
1869
1870   gtk_widget_style_get (widget,
1871                         "focus-line-width", &focus_width,
1872                         "tab-overlap", &tab_overlap,
1873                         "tab-curvature", &tab_curvature,
1874                         "arrow-spacing", &arrow_spacing,
1875                         "scroll-arrow-hlength", &scroll_arrow_hlength,
1876                         "scroll-arrow-vlength", &scroll_arrow_vlength,
1877                         NULL);
1878
1879   widget->requisition.width = 0;
1880   widget->requisition.height = 0;
1881
1882   for (children = notebook->children, vis_pages = 0; children;
1883        children = children->next)
1884     {
1885       page = children->data;
1886
1887       if (GTK_WIDGET_VISIBLE (page->child))
1888         {
1889           vis_pages++;
1890           gtk_widget_size_request (page->child, &child_requisition);
1891           
1892           widget->requisition.width = MAX (widget->requisition.width,
1893                                            child_requisition.width);
1894           widget->requisition.height = MAX (widget->requisition.height,
1895                                             child_requisition.height);
1896
1897           if (notebook->menu && page->menu_label->parent &&
1898               !GTK_WIDGET_VISIBLE (page->menu_label->parent))
1899             gtk_widget_show (page->menu_label->parent);
1900         }
1901       else
1902         {
1903           if (page == notebook->cur_page)
1904             switch_page = TRUE;
1905           if (notebook->menu && page->menu_label->parent &&
1906               GTK_WIDGET_VISIBLE (page->menu_label->parent))
1907             gtk_widget_hide (page->menu_label->parent);
1908         }
1909     }
1910
1911   if (notebook->show_border || notebook->show_tabs)
1912     {
1913       widget->requisition.width += widget->style->xthickness * 2;
1914       widget->requisition.height += widget->style->ythickness * 2;
1915
1916       if (notebook->show_tabs)
1917         {
1918           gint tab_width = 0;
1919           gint tab_height = 0;
1920           gint tab_max = 0;
1921           gint padding;
1922           gint i;
1923           gint action_width = 0;
1924           gint action_height = 0;
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                   action_width += action_widget_requisition[ACTION_WIDGET_START].width;
2021                   action_width += action_widget_requisition[ACTION_WIDGET_END].width;
2022                   if (notebook->homogeneous && !notebook->scrollable)
2023                     widget->requisition.width = MAX (widget->requisition.width,
2024                                                      vis_pages * tab_max +
2025                                                      tab_overlap + action_width);
2026                   else
2027                     widget->requisition.width = MAX (widget->requisition.width,
2028                                                      tab_width + tab_overlap + action_width);
2029
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                   action_height += action_widget_requisition[ACTION_WIDGET_START].height;
2071                   action_height += action_widget_requisition[ACTION_WIDGET_END].height;
2072
2073                   if (notebook->homogeneous && !notebook->scrollable)
2074                     widget->requisition.height =
2075                       MAX (widget->requisition.height,
2076                            vis_pages * tab_max + tab_overlap + action_height);
2077                   else
2078                     widget->requisition.height =
2079                       MAX (widget->requisition.height,
2080                            tab_height + tab_overlap + action_height);
2081
2082                   if (!notebook->homogeneous || notebook->scrollable)
2083                     vis_pages = 1;
2084                   widget->requisition.height = MAX (widget->requisition.height,
2085                                                     vis_pages * tab_max +
2086                                                     tab_overlap);
2087
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_is_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_is_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_is_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_is_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_is_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_is_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   widget = GTK_WIDGET (notebook);
5018
5019   if (gtk_widget_is_drawable (widget))
5020     {
5021       gint scroll_arrow_hlength;
5022       gint scroll_arrow_vlength;
5023       gint arrow_size;
5024
5025       gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
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   GtkNotebookPrivate *priv;
6885   GtkNotebookPage *page;
6886   GList *children;
6887   gint i;
6888
6889   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6890
6891   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
6892
6893   show_tabs = show_tabs != FALSE;
6894
6895   if (notebook->show_tabs == show_tabs)
6896     return;
6897
6898   notebook->show_tabs = show_tabs;
6899   children = notebook->children;
6900
6901   if (!show_tabs)
6902     {
6903       GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6904
6905       while (children)
6906         {
6907           page = children->data;
6908           children = children->next;
6909           if (page->default_tab)
6910             {
6911               gtk_widget_destroy (page->tab_label);
6912               page->tab_label = NULL;
6913             }
6914           else
6915             gtk_widget_hide (page->tab_label);
6916         }
6917     }
6918   else
6919     {
6920       GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6921       gtk_notebook_update_labels (notebook);
6922     }
6923
6924   for (i = 0; i < N_ACTION_WIDGETS; i++)
6925     {
6926       if (priv->action_widget[i])
6927         gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
6928     }
6929
6930   gtk_widget_queue_resize (GTK_WIDGET (notebook));
6931
6932   g_object_notify (G_OBJECT (notebook), "show-tabs");
6933 }
6934
6935 /**
6936  * gtk_notebook_get_show_tabs:
6937  * @notebook: a #GtkNotebook
6938  *
6939  * Returns whether the tabs of the notebook are shown. See
6940  * gtk_notebook_set_show_tabs().
6941  *
6942  * Return value: %TRUE if the tabs are shown
6943  **/
6944 gboolean
6945 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6946 {
6947   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6948
6949   return notebook->show_tabs;
6950 }
6951
6952 /**
6953  * gtk_notebook_set_tab_pos:
6954  * @notebook: a #GtkNotebook.
6955  * @pos: the edge to draw the tabs at.
6956  * 
6957  * Sets the edge at which the tabs for switching pages in the
6958  * notebook are drawn.
6959  **/
6960 void
6961 gtk_notebook_set_tab_pos (GtkNotebook     *notebook,
6962                           GtkPositionType  pos)
6963 {
6964   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6965
6966   if (notebook->tab_pos != pos)
6967     {
6968       notebook->tab_pos = pos;
6969       if (GTK_WIDGET_VISIBLE (notebook))
6970         gtk_widget_queue_resize (GTK_WIDGET (notebook));
6971     }
6972
6973   g_object_notify (G_OBJECT (notebook), "tab-pos");
6974 }
6975
6976 /**
6977  * gtk_notebook_get_tab_pos:
6978  * @notebook: a #GtkNotebook
6979  *
6980  * Gets the edge at which the tabs for switching pages in the
6981  * notebook are drawn.
6982  *
6983  * Return value: the edge at which the tabs are drawn
6984  **/
6985 GtkPositionType
6986 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6987 {
6988   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6989
6990   return notebook->tab_pos;
6991 }
6992
6993 /**
6994  * gtk_notebook_set_homogeneous_tabs:
6995  * @notebook: a #GtkNotebook
6996  * @homogeneous: %TRUE if all tabs should be the same size.
6997  * 
6998  * Sets whether the tabs must have all the same size or not.
6999  **/
7000 void
7001 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
7002                                    gboolean     homogeneous)
7003 {
7004   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7005
7006   gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
7007 }
7008
7009 /**
7010  * gtk_notebook_set_tab_border:
7011  * @notebook: a #GtkNotebook
7012  * @border_width: width of the border around the tab labels.
7013  * 
7014  * Sets the width the border around the tab labels
7015  * in a notebook. This is equivalent to calling
7016  * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
7017  * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
7018  **/
7019 void
7020 gtk_notebook_set_tab_border (GtkNotebook *notebook,
7021                              guint        border_width)
7022 {
7023   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7024
7025   gtk_notebook_set_tab_border_internal (notebook, border_width);
7026 }
7027
7028 /**
7029  * gtk_notebook_set_tab_hborder:
7030  * @notebook: a #GtkNotebook
7031  * @tab_hborder: width of the horizontal border of tab labels.
7032  * 
7033  * Sets the width of the horizontal border of tab labels.
7034  **/
7035 void
7036 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
7037                               guint        tab_hborder)
7038 {
7039   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7040
7041   gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
7042 }
7043
7044 /**
7045  * gtk_notebook_set_tab_vborder:
7046  * @notebook: a #GtkNotebook
7047  * @tab_vborder: width of the vertical border of tab labels.
7048  * 
7049  * Sets the width of the vertical border of tab labels.
7050  **/
7051 void
7052 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
7053                               guint        tab_vborder)
7054 {
7055   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7056
7057   gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
7058 }
7059
7060 /**
7061  * gtk_notebook_set_scrollable:
7062  * @notebook: a #GtkNotebook
7063  * @scrollable: %TRUE if scroll arrows should be added
7064  * 
7065  * Sets whether the tab label area will have arrows for scrolling if
7066  * there are too many tabs to fit in the area.
7067  **/
7068 void
7069 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7070                              gboolean     scrollable)
7071 {
7072   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7073
7074   scrollable = (scrollable != FALSE);
7075
7076   if (scrollable != notebook->scrollable)
7077     {
7078       notebook->scrollable = scrollable;
7079
7080       if (GTK_WIDGET_VISIBLE (notebook))
7081         gtk_widget_queue_resize (GTK_WIDGET (notebook));
7082
7083       g_object_notify (G_OBJECT (notebook), "scrollable");
7084     }
7085 }
7086
7087 /**
7088  * gtk_notebook_get_scrollable:
7089  * @notebook: a #GtkNotebook
7090  *
7091  * Returns whether the tab label area has arrows for scrolling. See
7092  * gtk_notebook_set_scrollable().
7093  *
7094  * Return value: %TRUE if arrows for scrolling are present
7095  **/
7096 gboolean
7097 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7098 {
7099   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7100
7101   return notebook->scrollable;
7102 }
7103
7104 /* Public GtkNotebook Popup Menu Methods:
7105  *
7106  * gtk_notebook_popup_enable
7107  * gtk_notebook_popup_disable
7108  */
7109
7110
7111 /**
7112  * gtk_notebook_popup_enable:
7113  * @notebook: a #GtkNotebook
7114  * 
7115  * Enables the popup menu: if the user clicks with the right mouse button on
7116  * the bookmarks, a menu with all the pages will be popped up.
7117  **/
7118 void
7119 gtk_notebook_popup_enable (GtkNotebook *notebook)
7120 {
7121   GList *list;
7122
7123   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7124
7125   if (notebook->menu)
7126     return;
7127
7128   notebook->menu = gtk_menu_new ();
7129   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7130        list;
7131        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7132     gtk_notebook_menu_item_create (notebook, list);
7133
7134   gtk_notebook_update_labels (notebook);
7135   gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
7136                              GTK_WIDGET (notebook),
7137                              gtk_notebook_menu_detacher);
7138
7139   g_object_notify (G_OBJECT (notebook), "enable-popup");
7140 }
7141
7142 /**
7143  * gtk_notebook_popup_disable:
7144  * @notebook: a #GtkNotebook
7145  * 
7146  * Disables the popup menu.
7147  **/
7148 void       
7149 gtk_notebook_popup_disable  (GtkNotebook *notebook)
7150 {
7151   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7152
7153   if (!notebook->menu)
7154     return;
7155
7156   gtk_container_foreach (GTK_CONTAINER (notebook->menu),
7157                          (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7158   gtk_widget_destroy (notebook->menu);
7159
7160   g_object_notify (G_OBJECT (notebook), "enable-popup");
7161 }
7162
7163 /* Public GtkNotebook Page Properties Functions:
7164  *
7165  * gtk_notebook_get_tab_label
7166  * gtk_notebook_set_tab_label
7167  * gtk_notebook_set_tab_label_text
7168  * gtk_notebook_get_menu_label
7169  * gtk_notebook_set_menu_label
7170  * gtk_notebook_set_menu_label_text
7171  * gtk_notebook_set_tab_label_packing
7172  * gtk_notebook_query_tab_label_packing
7173  * gtk_notebook_get_tab_reorderable
7174  * gtk_notebook_set_tab_reorderable
7175  * gtk_notebook_get_tab_detachable
7176  * gtk_notebook_set_tab_detachable
7177  */
7178
7179 /**
7180  * gtk_notebook_get_tab_label:
7181  * @notebook: a #GtkNotebook
7182  * @child: the page
7183  * 
7184  * Returns the tab label widget for the page @child. %NULL is returned
7185  * if @child is not in @notebook or if no tab label has specifically
7186  * been set for @child.
7187  *
7188  * Return value: (transfer none): the tab label
7189  **/
7190 GtkWidget *
7191 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7192                             GtkWidget   *child)
7193 {
7194   GList *list;
7195
7196   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7197   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7198
7199   list = CHECK_FIND_CHILD (notebook, child);
7200   if (!list)  
7201     return NULL;
7202
7203   if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7204     return NULL;
7205
7206   return GTK_NOTEBOOK_PAGE (list)->tab_label;
7207 }  
7208
7209 /**
7210  * gtk_notebook_set_tab_label:
7211  * @notebook: a #GtkNotebook
7212  * @child: the page
7213  * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7214  *             label.
7215  *
7216  * Changes the tab label for @child. If %NULL is specified
7217  * for @tab_label, then the page will have the label 'page N'.
7218  **/
7219 void
7220 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7221                             GtkWidget   *child,
7222                             GtkWidget   *tab_label)
7223 {
7224   GtkNotebookPage *page;
7225   GList *list;
7226
7227   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7228   g_return_if_fail (GTK_IS_WIDGET (child));
7229
7230   list = CHECK_FIND_CHILD (notebook, child);
7231   if (!list)  
7232     return;
7233
7234   /* a NULL pointer indicates a default_tab setting, otherwise
7235    * we need to set the associated label
7236    */
7237   page = list->data;
7238   
7239   if (page->tab_label == tab_label)
7240     return;
7241   
7242
7243   gtk_notebook_remove_tab_label (notebook, page);
7244   
7245   if (tab_label)
7246     {
7247       page->default_tab = FALSE;
7248       page->tab_label = tab_label;
7249       gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7250     }
7251   else
7252     {
7253       page->default_tab = TRUE;
7254       page->tab_label = NULL;
7255
7256       if (notebook->show_tabs)
7257         {
7258           gchar string[32];
7259
7260           g_snprintf (string, sizeof(string), _("Page %u"), 
7261                       gtk_notebook_real_page_position (notebook, list));
7262           page->tab_label = gtk_label_new (string);
7263           gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7264         }
7265     }
7266
7267   if (page->tab_label)
7268     page->mnemonic_activate_signal =
7269       g_signal_connect (page->tab_label,
7270                         "mnemonic-activate",
7271                         G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7272                         notebook);
7273
7274   if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
7275     {
7276       gtk_widget_show (page->tab_label);
7277       gtk_widget_queue_resize (GTK_WIDGET (notebook));
7278     }
7279
7280   gtk_notebook_update_tab_states (notebook);
7281   gtk_widget_child_notify (child, "tab-label");
7282 }
7283
7284 /**
7285  * gtk_notebook_set_tab_label_text:
7286  * @notebook: a #GtkNotebook
7287  * @child: the page
7288  * @tab_text: the label text
7289  * 
7290  * Creates a new label and sets it as the tab label for the page
7291  * containing @child.
7292  **/
7293 void
7294 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7295                                  GtkWidget   *child,
7296                                  const gchar *tab_text)
7297 {
7298   GtkWidget *tab_label = NULL;
7299
7300   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7301
7302   if (tab_text)
7303     tab_label = gtk_label_new (tab_text);
7304   gtk_notebook_set_tab_label (notebook, child, tab_label);
7305   gtk_widget_child_notify (child, "tab-label");
7306 }
7307
7308 /**
7309  * gtk_notebook_get_tab_label_text:
7310  * @notebook: a #GtkNotebook
7311  * @child: a widget contained in a page of @notebook
7312  *
7313  * Retrieves the text of the tab label for the page containing
7314  *    @child.
7315  *
7316  * Return value: the text of the tab label, or %NULL if the
7317  *               tab label widget is not a #GtkLabel. The
7318  *               string is owned by the widget and must not
7319  *               be freed.
7320  **/
7321 G_CONST_RETURN gchar *
7322 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7323                                  GtkWidget   *child)
7324 {
7325   GtkWidget *tab_label;
7326
7327   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7328   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7329
7330   tab_label = gtk_notebook_get_tab_label (notebook, child);
7331
7332   if (GTK_IS_LABEL (tab_label))
7333     return gtk_label_get_text (GTK_LABEL (tab_label));
7334   else
7335     return NULL;
7336 }
7337
7338 /**
7339  * gtk_notebook_get_menu_label:
7340  * @notebook: a #GtkNotebook
7341  * @child: a widget contained in a page of @notebook
7342  * 
7343  * Retrieves the menu label widget of the page containing @child.
7344  * 
7345  * Return value: the menu label, or %NULL if the
7346  *               notebook page does not have a menu label other
7347  *               than the default (the tab label).
7348  **/
7349 GtkWidget*
7350 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7351                              GtkWidget   *child)
7352 {
7353   GList *list;
7354
7355   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7356   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7357
7358   list = CHECK_FIND_CHILD (notebook, child);
7359   if (!list)  
7360     return NULL;
7361
7362   if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7363     return NULL;
7364
7365   return GTK_NOTEBOOK_PAGE (list)->menu_label;
7366 }  
7367
7368 /**
7369  * gtk_notebook_set_menu_label:
7370  * @notebook: a #GtkNotebook
7371  * @child: the child widget
7372  * @menu_label: (allow-none): the menu label, or NULL for default
7373  *
7374  * Changes the menu label for the page containing @child.
7375  **/
7376 void
7377 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7378                              GtkWidget   *child,
7379                              GtkWidget   *menu_label)
7380 {
7381   GtkNotebookPage *page;
7382   GList *list;
7383
7384   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7385   g_return_if_fail (GTK_IS_WIDGET (child));
7386
7387   list = CHECK_FIND_CHILD (notebook, child);
7388   if (!list)  
7389     return;
7390
7391   page = list->data;
7392   if (page->menu_label)
7393     {
7394       if (notebook->menu)
7395         gtk_container_remove (GTK_CONTAINER (notebook->menu), 
7396                               page->menu_label->parent);
7397
7398       if (!page->default_menu)
7399         g_object_unref (page->menu_label);
7400     }
7401
7402   if (menu_label)
7403     {
7404       page->menu_label = menu_label;
7405       g_object_ref_sink (page->menu_label);
7406       page->default_menu = FALSE;
7407     }
7408   else
7409     page->default_menu = TRUE;
7410
7411   if (notebook->menu)
7412     gtk_notebook_menu_item_create (notebook, list);
7413   gtk_widget_child_notify (child, "menu-label");
7414 }
7415
7416 /**
7417  * gtk_notebook_set_menu_label_text:
7418  * @notebook: a #GtkNotebook
7419  * @child: the child widget
7420  * @menu_text: the label text
7421  * 
7422  * Creates a new label and sets it as the menu label of @child.
7423  **/
7424 void
7425 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7426                                   GtkWidget   *child,
7427                                   const gchar *menu_text)
7428 {
7429   GtkWidget *menu_label = NULL;
7430
7431   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7432
7433   if (menu_text)
7434     {
7435       menu_label = gtk_label_new (menu_text);
7436       gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7437     }
7438   gtk_notebook_set_menu_label (notebook, child, menu_label);
7439   gtk_widget_child_notify (child, "menu-label");
7440 }
7441
7442 /**
7443  * gtk_notebook_get_menu_label_text:
7444  * @notebook: a #GtkNotebook
7445  * @child: the child widget of a page of the notebook.
7446  *
7447  * Retrieves the text of the menu label for the page containing
7448  *    @child.
7449  *
7450  * Return value: the text of the tab label, or %NULL if the
7451  *               widget does not have a menu label other than
7452  *               the default menu label, or the menu label widget
7453  *               is not a #GtkLabel. The string is owned by
7454  *               the widget and must not be freed.
7455  **/
7456 G_CONST_RETURN gchar *
7457 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7458                                   GtkWidget *child)
7459 {
7460   GtkWidget *menu_label;
7461
7462   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7463   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7464  
7465   menu_label = gtk_notebook_get_menu_label (notebook, child);
7466
7467   if (GTK_IS_LABEL (menu_label))
7468     return gtk_label_get_text (GTK_LABEL (menu_label));
7469   else
7470     return NULL;
7471 }
7472   
7473 /* Helper function called when pages are reordered
7474  */
7475 static void
7476 gtk_notebook_child_reordered (GtkNotebook     *notebook,
7477                               GtkNotebookPage *page)
7478 {
7479   if (notebook->menu)
7480     {
7481       GtkWidget *menu_item;
7482       
7483       menu_item = page->menu_label->parent;
7484       gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7485       gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7486       gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7487     }
7488
7489   gtk_notebook_update_tab_states (notebook);
7490   gtk_notebook_update_labels (notebook);
7491 }
7492
7493 /**
7494  * gtk_notebook_set_tab_label_packing:
7495  * @notebook: a #GtkNotebook
7496  * @child: the child widget
7497  * @expand: whether to expand the bookmark or not
7498  * @fill: whether the bookmark should fill the allocated area or not
7499  * @pack_type: the position of the bookmark
7500  *
7501  * Sets the packing parameters for the tab label of the page
7502  * containing @child. See gtk_box_pack_start() for the exact meaning
7503  * of the parameters.
7504  *
7505  * Deprecated: 2.20: Modify the #GtkNotebook:tab-expand and
7506  *   #GtkNotebook:tab-fill child properties instead.
7507  **/
7508 void
7509 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7510                                     GtkWidget   *child,
7511                                     gboolean     expand,
7512                                     gboolean     fill,
7513                                     GtkPackType  pack_type)
7514 {
7515   GtkNotebookPage *page;
7516   GList *list;
7517
7518   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7519   g_return_if_fail (GTK_IS_WIDGET (child));
7520
7521   list = CHECK_FIND_CHILD (notebook, child);
7522   if (!list)  
7523     return;
7524
7525   page = list->data;
7526   expand = expand != FALSE;
7527   fill = fill != FALSE;
7528   if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7529     return;
7530
7531   gtk_widget_freeze_child_notify (child);
7532   page->expand = expand;
7533   gtk_widget_child_notify (child, "tab-expand");
7534   page->fill = fill;
7535   gtk_widget_child_notify (child, "tab-fill");
7536   if (page->pack != pack_type)
7537     {
7538       page->pack = pack_type;
7539       gtk_notebook_child_reordered (notebook, page);
7540     }
7541   gtk_widget_child_notify (child, "tab-pack");
7542   gtk_widget_child_notify (child, "position");
7543   if (notebook->show_tabs)
7544     gtk_notebook_pages_allocate (notebook);
7545   gtk_widget_thaw_child_notify (child);
7546 }  
7547
7548 /**
7549  * gtk_notebook_query_tab_label_packing:
7550  * @notebook: a #GtkNotebook
7551  * @child: the page
7552  * @expand: location to store the expand value (or NULL)
7553  * @fill: location to store the fill value (or NULL)
7554  * @pack_type: location to store the pack_type (or NULL)
7555  * 
7556  * Query the packing attributes for the tab label of the page
7557  * containing @child.
7558  *
7559  * Deprecated: 2.20: Modify the #GtkNotebook:tab-expand and
7560  *   #GtkNotebook:tab-fill child properties instead.
7561  **/
7562 void
7563 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7564                                       GtkWidget   *child,
7565                                       gboolean    *expand,
7566                                       gboolean    *fill,
7567                                       GtkPackType *pack_type)
7568 {
7569   GList *list;
7570
7571   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7572   g_return_if_fail (GTK_IS_WIDGET (child));
7573
7574   list = CHECK_FIND_CHILD (notebook, child);
7575   if (!list)
7576     return;
7577
7578   if (expand)
7579     *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7580   if (fill)
7581     *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7582   if (pack_type)
7583     *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7584 }
7585
7586 /**
7587  * gtk_notebook_reorder_child:
7588  * @notebook: a #GtkNotebook
7589  * @child: the child to move
7590  * @position: the new position, or -1 to move to the end
7591  * 
7592  * Reorders the page containing @child, so that it appears in position
7593  * @position. If @position is greater than or equal to the number of
7594  * children in the list or negative, @child will be moved to the end
7595  * of the list.
7596  **/
7597 void
7598 gtk_notebook_reorder_child (GtkNotebook *notebook,
7599                             GtkWidget   *child,
7600                             gint         position)
7601 {
7602   GList *list, *new_list;
7603   GtkNotebookPage *page;
7604   gint old_pos;
7605   gint max_pos;
7606
7607   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7608   g_return_if_fail (GTK_IS_WIDGET (child));
7609
7610   list = CHECK_FIND_CHILD (notebook, child);
7611   if (!list)
7612     return;
7613
7614   max_pos = g_list_length (notebook->children) - 1;
7615   if (position < 0 || position > max_pos)
7616     position = max_pos;
7617
7618   old_pos = g_list_position (notebook->children, list);
7619
7620   if (old_pos == position)
7621     return;
7622
7623   page = list->data;
7624   notebook->children = g_list_delete_link (notebook->children, list);
7625
7626   notebook->children = g_list_insert (notebook->children, page, position);
7627   new_list = g_list_nth (notebook->children, position);
7628
7629   /* Fix up GList references in GtkNotebook structure */
7630   if (notebook->first_tab == list)
7631     notebook->first_tab = new_list;
7632   if (notebook->focus_tab == list)
7633     notebook->focus_tab = new_list;
7634
7635   gtk_widget_freeze_child_notify (child);
7636
7637   /* Move around the menu items if necessary */
7638   gtk_notebook_child_reordered (notebook, page);
7639   gtk_widget_child_notify (child, "tab-pack");
7640   gtk_widget_child_notify (child, "position");
7641
7642   if (notebook->show_tabs)
7643     gtk_notebook_pages_allocate (notebook);
7644
7645   gtk_widget_thaw_child_notify (child);
7646
7647   g_signal_emit (notebook,
7648                  notebook_signals[PAGE_REORDERED],
7649                  0,
7650                  child,
7651                  position);
7652 }
7653
7654 /**
7655  * gtk_notebook_set_window_creation_hook:
7656  * @func: (allow-none): the #GtkNotebookWindowCreationFunc, or %NULL
7657  * @data: user data for @func
7658  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
7659  *
7660  * Installs a global function used to create a window
7661  * when a detached tab is dropped in an empty area.
7662  * 
7663  * Since: 2.10
7664  **/
7665 void
7666 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc  func,
7667                                        gpointer                       data,
7668                                        GDestroyNotify                 destroy)
7669 {
7670   if (window_creation_hook_destroy)
7671     window_creation_hook_destroy (window_creation_hook_data);
7672
7673   window_creation_hook = func;
7674   window_creation_hook_data = data;
7675   window_creation_hook_destroy = destroy;
7676 }
7677
7678 /**
7679  * gtk_notebook_set_group_id:
7680  * @notebook: a #GtkNotebook
7681  * @group_id: a group identificator, or -1 to unset it
7682  *
7683  * Sets an group identificator for @notebook, notebooks sharing
7684  * the same group identificator will be able to exchange tabs
7685  * via drag and drop. A notebook with group identificator -1 will
7686  * not be able to exchange tabs with any other notebook.
7687  * 
7688  * Since: 2.10
7689  * Deprecated: 2.12: use gtk_notebook_set_group() instead.
7690  */
7691 void
7692 gtk_notebook_set_group_id (GtkNotebook *notebook,
7693                            gint         group_id)
7694 {
7695   gpointer group;
7696
7697   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7698
7699   /* add 1 to get rid of the -1/NULL difference */
7700   group = GINT_TO_POINTER (group_id + 1);
7701   gtk_notebook_set_group (notebook, group);
7702 }
7703
7704 /**
7705  * gtk_notebook_set_group:
7706  * @notebook: a #GtkNotebook
7707  * @group: (allow-none): a pointer to identify the notebook group, or %NULL to unset it
7708  *
7709  * Sets a group identificator pointer for @notebook, notebooks sharing
7710  * the same group identificator pointer will be able to exchange tabs
7711  * via drag and drop. A notebook with a %NULL group identificator will
7712  * not be able to exchange tabs with any other notebook.
7713  * 
7714  * Since: 2.12
7715  */
7716 void
7717 gtk_notebook_set_group (GtkNotebook *notebook,
7718                         gpointer     group)
7719 {
7720   GtkNotebookPrivate *priv;
7721
7722   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7723
7724   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7725
7726   if (priv->group != group)
7727     {
7728       priv->group = group;
7729       g_object_notify (G_OBJECT (notebook), "group-id");
7730       g_object_notify (G_OBJECT (notebook), "group");
7731     }
7732 }
7733
7734 /**
7735  * gtk_notebook_get_group_id:
7736  * @notebook: a #GtkNotebook
7737  * 
7738  * Gets the current group identificator for @notebook.
7739  * 
7740  * Return Value: the group identificator, or -1 if none is set.
7741  *
7742  * Since: 2.10
7743  * Deprecated: 2.12: use gtk_notebook_get_group() instead.
7744  */
7745 gint
7746 gtk_notebook_get_group_id (GtkNotebook *notebook)
7747 {
7748   GtkNotebookPrivate *priv;
7749
7750   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7751
7752   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7753
7754   /* substract 1 to get rid of the -1/NULL difference */
7755   return GPOINTER_TO_INT (priv->group) - 1;
7756 }
7757
7758 /**
7759  * gtk_notebook_get_group:
7760  * @notebook: a #GtkNotebook
7761  * 
7762  * Gets the current group identificator pointer for @notebook.
7763  * 
7764  * Return Value: the group identificator, or %NULL if none is set.
7765  *
7766  * Since: 2.12
7767  **/
7768 gpointer
7769 gtk_notebook_get_group (GtkNotebook *notebook)
7770 {
7771   GtkNotebookPrivate *priv;
7772
7773   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7774
7775   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7776   return priv->group;
7777 }
7778
7779 /**
7780  * gtk_notebook_get_tab_reorderable:
7781  * @notebook: a #GtkNotebook
7782  * @child: a child #GtkWidget
7783  * 
7784  * Gets whether the tab can be reordered via drag and drop or not.
7785  * 
7786  * Return Value: %TRUE if the tab is reorderable.
7787  * 
7788  * Since: 2.10
7789  **/
7790 gboolean
7791 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7792                                   GtkWidget   *child)
7793 {
7794   GList *list;
7795
7796   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7797   g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7798
7799   list = CHECK_FIND_CHILD (notebook, child);
7800   if (!list)  
7801     return FALSE;
7802
7803   return GTK_NOTEBOOK_PAGE (list)->reorderable;
7804 }
7805
7806 /**
7807  * gtk_notebook_set_tab_reorderable:
7808  * @notebook: a #GtkNotebook
7809  * @child: a child #GtkWidget
7810  * @reorderable: whether the tab is reorderable or not.
7811  *
7812  * Sets whether the notebook tab can be reordered
7813  * via drag and drop or not.
7814  * 
7815  * Since: 2.10
7816  **/
7817 void
7818 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7819                                   GtkWidget   *child,
7820                                   gboolean     reorderable)
7821 {
7822   GList *list;
7823
7824   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7825   g_return_if_fail (GTK_IS_WIDGET (child));
7826
7827   list = CHECK_FIND_CHILD (notebook, child);
7828   if (!list)  
7829     return;
7830
7831   if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7832     {
7833       GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7834       gtk_widget_child_notify (child, "reorderable");
7835     }
7836 }
7837
7838 /**
7839  * gtk_notebook_get_tab_detachable:
7840  * @notebook: a #GtkNotebook
7841  * @child: a child #GtkWidget
7842  * 
7843  * Returns whether the tab contents can be detached from @notebook.
7844  * 
7845  * Return Value: TRUE if the tab is detachable.
7846  *
7847  * Since: 2.10
7848  **/
7849 gboolean
7850 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7851                                  GtkWidget   *child)
7852 {
7853   GList *list;
7854
7855   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7856   g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7857
7858   list = CHECK_FIND_CHILD (notebook, child);
7859   if (!list)  
7860     return FALSE;
7861
7862   return GTK_NOTEBOOK_PAGE (list)->detachable;
7863 }
7864
7865 /**
7866  * gtk_notebook_set_tab_detachable:
7867  * @notebook: a #GtkNotebook
7868  * @child: a child #GtkWidget
7869  * @detachable: whether the tab is detachable or not
7870  *
7871  * Sets whether the tab can be detached from @notebook to another
7872  * notebook or widget.
7873  *
7874  * Note that 2 notebooks must share a common group identificator
7875  * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7876  * interchange between them.
7877  *
7878  * If you want a widget to interact with a notebook through DnD
7879  * (i.e.: accept dragged tabs from it) it must be set as a drop
7880  * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7881  * will fill the selection with a GtkWidget** pointing to the child
7882  * widget that corresponds to the dropped tab.
7883  * |[
7884  *  static void
7885  *  on_drop_zone_drag_data_received (GtkWidget        *widget,
7886  *                                   GdkDragContext   *context,
7887  *                                   gint              x,
7888  *                                   gint              y,
7889  *                                   GtkSelectionData *selection_data,
7890  *                                   guint             info,
7891  *                                   guint             time,
7892  *                                   gpointer          user_data)
7893  *  {
7894  *    GtkWidget *notebook;
7895  *    GtkWidget **child;
7896  *    
7897  *    notebook = gtk_drag_get_source_widget (context);
7898  *    child = (void*) selection_data->data;
7899  *    
7900  *    process_widget (*child);
7901  *    gtk_container_remove (GTK_CONTAINER (notebook), *child);
7902  *  }
7903  * ]|
7904  *
7905  * If you want a notebook to accept drags from other widgets,
7906  * you will have to set your own DnD code to do it.
7907  *
7908  * Since: 2.10
7909  **/
7910 void
7911 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7912                                  GtkWidget  *child,
7913                                  gboolean    detachable)
7914 {
7915   GList *list;
7916
7917   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7918   g_return_if_fail (GTK_IS_WIDGET (child));
7919
7920   list = CHECK_FIND_CHILD (notebook, child);
7921   if (!list)  
7922     return;
7923
7924   if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7925     {
7926       GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7927       gtk_widget_child_notify (child, "detachable");
7928     }
7929 }
7930
7931 /**
7932  * gtk_notebook_get_action_widget:
7933  * @notebook: a #GtkNotebook
7934  * @pack_type: pack type of the action widget to receive
7935  *
7936  * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7937  *
7938  * Returns: The action widget with the given @pack_type or
7939  *     %NULL when this action widget has not been set
7940  *
7941  * Since: 2.20
7942  */
7943 GtkWidget*
7944 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7945                                 GtkPackType  pack_type)
7946 {
7947   GtkNotebookPrivate *priv;
7948
7949   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7950
7951   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7952   return priv->action_widget[pack_type];
7953 }
7954
7955 /**
7956  * gtk_notebook_set_action_widget:
7957  * @notebook: a #GtkNotebook
7958  * @widget: a #GtkWidget
7959  * @pack_type: pack type of the action widget
7960  *
7961  * Sets @widget as one of the action widgets. Depending on the pack type
7962  * the widget will be placed before or after the tabs. You can use
7963  * a #GtkBox if you need to pack more than one widget on the same side.
7964  *
7965  * Note that action widgets are "internal" children of the notebook and thus
7966  * not included in the list returned from gtk_container_foreach().
7967  *
7968  * Since: 2.20
7969  */
7970 void
7971 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7972                                 GtkWidget   *widget,
7973                                 GtkPackType  pack_type)
7974 {
7975   GtkNotebookPrivate *priv;
7976
7977   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7978   g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7979   g_return_if_fail (!widget || widget->parent == NULL);
7980
7981   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7982
7983   if (priv->action_widget[pack_type])
7984     gtk_widget_unparent (priv->action_widget[pack_type]);
7985
7986   priv->action_widget[pack_type] = widget;
7987
7988   if (widget)
7989     {
7990       gtk_widget_set_child_visible (widget, notebook->show_tabs);
7991       gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
7992     }
7993
7994   gtk_widget_queue_resize (GTK_WIDGET (notebook));
7995 }
7996
7997 #define __GTK_NOTEBOOK_C__
7998 #include "gtkaliasdef.c"