]> Pileus Git - ~andy/gtk/blob - gtk/gtknotebook.c
Deprecate widget flag: GTK_WIDGET_VISIBLE
[~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_get_visible (page->child))
1659         {
1660           visible_page = page;
1661           break;
1662         }
1663     }
1664
1665   if (notebook->show_tabs && visible_page)
1666     {
1667       if (rectangle)
1668         {
1669           is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1670           rectangle->x = widget->allocation.x + border_width;
1671           rectangle->y = widget->allocation.y + border_width;
1672
1673           switch (tab_pos)
1674             {
1675             case GTK_POS_TOP:
1676             case GTK_POS_BOTTOM:
1677               rectangle->width = widget->allocation.width - 2 * border_width;
1678               rectangle->height = visible_page->requisition.height;
1679               if (tab_pos == GTK_POS_BOTTOM)
1680                 rectangle->y += widget->allocation.height - 2 * border_width - rectangle->height;
1681
1682               for (i = 0; i < N_ACTION_WIDGETS; i++)
1683                 {
1684                   if (priv->action_widget[i] &&
1685                       gtk_widget_get_visible (priv->action_widget[i]))
1686                     {
1687                       rectangle->width -= priv->action_widget[i]->allocation.width;
1688                       if ((!is_rtl && i == ACTION_WIDGET_START) ||
1689                           (is_rtl && i == ACTION_WIDGET_END))
1690                         rectangle->x += priv->action_widget[i]->allocation.width;
1691                     }
1692                 }
1693               break;
1694             case GTK_POS_LEFT:
1695             case GTK_POS_RIGHT:
1696               rectangle->width = visible_page->requisition.width;
1697               rectangle->height = widget->allocation.height - 2 * border_width;
1698               if (tab_pos == GTK_POS_RIGHT)
1699                 rectangle->x += widget->allocation.width - 2 * border_width - rectangle->width;
1700
1701               for (i = 0; i < N_ACTION_WIDGETS; i++)
1702                 {
1703                   if (priv->action_widget[i] &&
1704                       gtk_widget_get_visible (priv->action_widget[i]))
1705                     {
1706                       rectangle->height -= priv->action_widget[i]->allocation.height;
1707
1708                       if (i == ACTION_WIDGET_START)
1709                         rectangle->y += priv->action_widget[i]->allocation.height;
1710                     }
1711                 }
1712               break;
1713             }
1714         }
1715
1716       return TRUE;
1717     }
1718   else
1719     {
1720       if (rectangle)
1721         {
1722           rectangle->x = rectangle->y = 0;
1723           rectangle->width = rectangle->height = 10;
1724         }
1725     }
1726
1727   return FALSE;
1728 }
1729
1730 static void
1731 gtk_notebook_map (GtkWidget *widget)
1732 {
1733   GtkNotebookPrivate *priv;
1734   GtkNotebook *notebook;
1735   GtkNotebookPage *page;
1736   GList *children;
1737   gint i;
1738
1739   GTK_WIDGET_SET_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_get_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_get_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_get_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_get_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_get_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_get_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_get_visible (page->child))
1932                 {
1933                   if (!gtk_widget_get_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_get_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_get_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_get_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_get_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_get_visible (page->child))
2118                 {
2119                   gtk_notebook_switch_page (notebook, page);
2120                   break;
2121                 }
2122             }
2123         }
2124       else if (gtk_widget_get_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_get_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_get_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_get_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_get_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_get_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_get_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_get_visible (page->child) &&
4644       gtk_widget_get_visible (GTK_WIDGET (notebook)))
4645     need_resize = TRUE;
4646
4647   gtk_widget_unparent (page->child);
4648
4649   tab_label = page->tab_label;
4650   if (tab_label)
4651     {
4652       g_object_ref (tab_label);
4653       gtk_notebook_remove_tab_label (notebook, page);
4654       if (destroying)
4655         gtk_widget_destroy (tab_label);
4656       g_object_unref (tab_label);
4657     } 
4658
4659   if (notebook->menu)
4660     {
4661       gtk_container_remove (GTK_CONTAINER (notebook->menu), 
4662                             page->menu_label->parent);
4663       gtk_widget_queue_resize (notebook->menu);
4664     }
4665   if (!page->default_menu)
4666     g_object_unref (page->menu_label);
4667   
4668   g_list_free (list);
4669
4670   if (page->last_focus_child)
4671     {
4672       g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4673       page->last_focus_child = NULL;
4674     }
4675   
4676   g_slice_free (GtkNotebookPage, page);
4677
4678   gtk_notebook_update_labels (notebook);
4679   if (need_resize)
4680     gtk_widget_queue_resize (GTK_WIDGET (notebook));
4681 }
4682
4683 static void
4684 gtk_notebook_update_labels (GtkNotebook *notebook)
4685 {
4686   GtkNotebookPage *page;
4687   GList *list;
4688   gchar string[32];
4689   gint page_num = 1;
4690
4691   if (!notebook->show_tabs && !notebook->menu)
4692     return;
4693
4694   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4695        list;
4696        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4697     {
4698       page = list->data;
4699       g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4700       if (notebook->show_tabs)
4701         {
4702           if (page->default_tab)
4703             {
4704               if (!page->tab_label)
4705                 {
4706                   page->tab_label = gtk_label_new (string);
4707                   gtk_widget_set_parent (page->tab_label,
4708                                          GTK_WIDGET (notebook));
4709                 }
4710               else
4711                 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4712             }
4713
4714           if (gtk_widget_get_visible (page->child) &&
4715               !gtk_widget_get_visible (page->tab_label))
4716             gtk_widget_show (page->tab_label);
4717           else if (!gtk_widget_get_visible (page->child) &&
4718                    gtk_widget_get_visible (page->tab_label))
4719             gtk_widget_hide (page->tab_label);
4720         }
4721       if (notebook->menu && page->default_menu)
4722         {
4723           if (GTK_IS_LABEL (page->tab_label))
4724             gtk_label_set_text (GTK_LABEL (page->menu_label),
4725                                 GTK_LABEL (page->tab_label)->label);
4726           else
4727             gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4728         }
4729     }  
4730 }
4731
4732 static gint
4733 gtk_notebook_real_page_position (GtkNotebook *notebook,
4734                                  GList       *list)
4735 {
4736   GList *work;
4737   gint count_start;
4738
4739   for (work = notebook->children, count_start = 0;
4740        work && work != list; work = work->next)
4741     if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4742       count_start++;
4743
4744   if (!work)
4745     return -1;
4746
4747   if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4748     return count_start;
4749
4750   return (count_start + g_list_length (list) - 1);
4751 }
4752
4753 static GList *
4754 gtk_notebook_search_page (GtkNotebook *notebook,
4755                           GList       *list,
4756                           gint         direction,
4757                           gboolean     find_visible)
4758 {
4759   GtkNotebookPage *page = NULL;
4760   GList *old_list = NULL;
4761   gint flag = 0;
4762
4763   switch (direction)
4764     {
4765     case STEP_PREV:
4766       flag = GTK_PACK_END;
4767       break;
4768
4769     case STEP_NEXT:
4770       flag = GTK_PACK_START;
4771       break;
4772     }
4773
4774   if (list)
4775     page = list->data;
4776
4777   if (!page || page->pack == flag)
4778     {
4779       if (list)
4780         {
4781           old_list = list;
4782           list = list->next;
4783         }
4784       else
4785         list = notebook->children;
4786
4787       while (list)
4788         {
4789           page = list->data;
4790           if (page->pack == flag &&
4791               (!find_visible ||
4792                (gtk_widget_get_visible (page->child) &&
4793                 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4794             return list;
4795           old_list = list;
4796           list = list->next;
4797         }
4798       list = old_list;
4799     }
4800   else
4801     {
4802       old_list = list;
4803       list = list->prev;
4804     }
4805   while (list)
4806     {
4807       page = list->data;
4808       if (page->pack != flag &&
4809           (!find_visible ||
4810            (gtk_widget_get_visible (page->child) &&
4811             (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4812         return list;
4813       old_list = list;
4814       list = list->prev;
4815     }
4816   return NULL;
4817 }
4818
4819 /* Private GtkNotebook Drawing Functions:
4820  *
4821  * gtk_notebook_paint
4822  * gtk_notebook_draw_tab
4823  * gtk_notebook_draw_arrow
4824  */
4825 static void
4826 gtk_notebook_paint (GtkWidget    *widget,
4827                     GdkRectangle *area)
4828 {
4829   GtkNotebook *notebook;
4830   GtkNotebookPrivate *priv;
4831   GtkNotebookPage *page;
4832   GList *children;
4833   gboolean showarrow;
4834   gint width, height;
4835   gint x, y;
4836   gint border_width = GTK_CONTAINER (widget)->border_width;
4837   gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4838   gboolean is_rtl;
4839   gint tab_pos;
4840    
4841   if (!gtk_widget_is_drawable (widget))
4842     return;
4843
4844   notebook = GTK_NOTEBOOK (widget);
4845   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4846   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4847   tab_pos = get_effective_tab_pos (notebook);
4848
4849   if ((!notebook->show_tabs && !notebook->show_border) ||
4850       !notebook->cur_page || !gtk_widget_get_visible (notebook->cur_page->child))
4851     return;
4852
4853   x = widget->allocation.x + border_width;
4854   y = widget->allocation.y + border_width;
4855   width = widget->allocation.width - border_width * 2;
4856   height = widget->allocation.height - border_width * 2;
4857
4858   if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4859     {
4860       gtk_paint_box (widget->style, widget->window,
4861                      GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4862                      area, widget, "notebook",
4863                      x, y, width, height);
4864       return;
4865     }
4866
4867   if (!notebook->first_tab)
4868     notebook->first_tab = notebook->children;
4869
4870   if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4871     page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4872   else
4873     page = notebook->cur_page;
4874
4875   switch (tab_pos)
4876     {
4877     case GTK_POS_TOP:
4878       y += page->allocation.height;
4879       /* fall thru */
4880     case GTK_POS_BOTTOM:
4881       height -= page->allocation.height;
4882       break;
4883     case GTK_POS_LEFT:
4884       x += page->allocation.width;
4885       /* fall thru */
4886     case GTK_POS_RIGHT:
4887       width -= page->allocation.width;
4888       break;
4889     }
4890
4891   if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4892       !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4893     {
4894       gap_x = 0;
4895       gap_width = 0;
4896     }
4897   else
4898     {
4899       switch (tab_pos)
4900         {
4901         case GTK_POS_TOP:
4902         case GTK_POS_BOTTOM:
4903           if (priv->operation == DRAG_OPERATION_REORDER)
4904             gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4905           else
4906             gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4907
4908           gap_width = notebook->cur_page->allocation.width;
4909           step = is_rtl ? STEP_NEXT : STEP_PREV;
4910           break;
4911         case GTK_POS_LEFT:
4912         case GTK_POS_RIGHT:
4913           if (priv->operation == DRAG_OPERATION_REORDER)
4914             gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4915           else
4916             gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4917
4918           gap_width = notebook->cur_page->allocation.height;
4919           step = STEP_PREV;
4920           break;
4921         }
4922     }
4923   gtk_paint_box_gap (widget->style, widget->window,
4924                      GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4925                      area, widget, "notebook",
4926                      x, y, width, height,
4927                      tab_pos, gap_x, gap_width);
4928
4929   showarrow = FALSE;
4930   children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4931   while (children)
4932     {
4933       page = children->data;
4934       children = gtk_notebook_search_page (notebook, children,
4935                                            step, TRUE);
4936       if (!gtk_widget_get_visible (page->child))
4937         continue;
4938       if (!GTK_WIDGET_MAPPED (page->tab_label))
4939         showarrow = TRUE;
4940       else if (page != notebook->cur_page)
4941         gtk_notebook_draw_tab (notebook, page, area);
4942     }
4943
4944   if (showarrow && notebook->scrollable) 
4945     {
4946       if (notebook->has_before_previous)
4947         gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4948       if (notebook->has_before_next)
4949         gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4950       if (notebook->has_after_previous)
4951         gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4952       if (notebook->has_after_next)
4953         gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4954     }
4955   gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4956 }
4957
4958 static void
4959 gtk_notebook_draw_tab (GtkNotebook     *notebook,
4960                        GtkNotebookPage *page,
4961                        GdkRectangle    *area)
4962 {
4963   GtkNotebookPrivate *priv;
4964   GdkRectangle child_area;
4965   GdkRectangle page_area;
4966   GtkStateType state_type;
4967   GtkPositionType gap_side;
4968   GdkWindow *window;
4969   GtkWidget *widget;
4970   
4971   if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4972       !GTK_WIDGET_MAPPED (page->tab_label) ||
4973       (page->allocation.width == 0) || (page->allocation.height == 0))
4974     return;
4975
4976   widget = GTK_WIDGET (notebook);
4977   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4978
4979   if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4980     window = priv->drag_window;
4981   else
4982     window = widget->window;
4983
4984   page_area.x = page->allocation.x;
4985   page_area.y = page->allocation.y;
4986   page_area.width = page->allocation.width;
4987   page_area.height = page->allocation.height;
4988
4989   if (gdk_rectangle_intersect (&page_area, area, &child_area))
4990     {
4991       gap_side = get_tab_gap_pos (notebook);
4992
4993       if (notebook->cur_page == page)
4994         state_type = GTK_STATE_NORMAL;
4995       else 
4996         state_type = GTK_STATE_ACTIVE;
4997
4998       gtk_paint_extension (widget->style, window,
4999                            state_type, GTK_SHADOW_OUT,
5000                            area, widget, "tab",
5001                            page_area.x, page_area.y,
5002                            page_area.width, page_area.height,
5003                            gap_side);
5004     }
5005 }
5006
5007 static void
5008 gtk_notebook_draw_arrow (GtkNotebook      *notebook,
5009                          GtkNotebookArrow  nbarrow)
5010 {
5011   GtkStateType state_type;
5012   GtkShadowType shadow_type;
5013   GtkWidget *widget;
5014   GdkRectangle arrow_rect;
5015   GtkArrowType arrow;
5016   gboolean is_rtl, left;
5017
5018   widget = GTK_WIDGET (notebook);
5019
5020   if (gtk_widget_is_drawable (widget))
5021     {
5022       gint scroll_arrow_hlength;
5023       gint scroll_arrow_vlength;
5024       gint arrow_size;
5025
5026       gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
5027
5028       is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5029       left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
5030              (!ARROW_IS_LEFT (nbarrow) && is_rtl); 
5031
5032       gtk_widget_style_get (widget,
5033                             "scroll-arrow-hlength", &scroll_arrow_hlength,
5034                             "scroll-arrow-vlength", &scroll_arrow_vlength,
5035                             NULL);
5036
5037       if (notebook->in_child == nbarrow)
5038         {
5039           if (notebook->click_child == nbarrow)
5040             state_type = GTK_STATE_ACTIVE;
5041           else
5042             state_type = GTK_STATE_PRELIGHT;
5043         }
5044       else
5045         state_type = GTK_WIDGET_STATE (widget);
5046
5047       if (notebook->click_child == nbarrow)
5048         shadow_type = GTK_SHADOW_IN;
5049       else
5050         shadow_type = GTK_SHADOW_OUT;
5051
5052       if (notebook->focus_tab &&
5053           !gtk_notebook_search_page (notebook, notebook->focus_tab,
5054                                      left ? STEP_PREV : STEP_NEXT, TRUE))
5055         {
5056           shadow_type = GTK_SHADOW_ETCHED_IN;
5057           state_type = GTK_STATE_INSENSITIVE;
5058         }
5059       
5060       if (notebook->tab_pos == GTK_POS_LEFT ||
5061           notebook->tab_pos == GTK_POS_RIGHT)
5062         {
5063           arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
5064           arrow_size = scroll_arrow_vlength;
5065         }
5066       else
5067         {
5068           arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
5069           arrow_size = scroll_arrow_hlength;
5070         }
5071      
5072       gtk_paint_arrow (widget->style, widget->window, state_type, 
5073                        shadow_type, NULL, widget, "notebook",
5074                        arrow, TRUE, arrow_rect.x, arrow_rect.y, 
5075                        arrow_size, arrow_size);
5076     }
5077 }
5078
5079 /* Private GtkNotebook Size Allocate Functions:
5080  *
5081  * gtk_notebook_tab_space
5082  * gtk_notebook_calculate_shown_tabs
5083  * gtk_notebook_calculate_tabs_allocation
5084  * gtk_notebook_pages_allocate
5085  * gtk_notebook_page_allocate
5086  * gtk_notebook_calc_tabs
5087  */
5088 static void
5089 gtk_notebook_tab_space (GtkNotebook *notebook,
5090                         gboolean    *show_arrows,
5091                         gint        *min,
5092                         gint        *max,
5093                         gint        *tab_space)
5094 {
5095   GtkNotebookPrivate *priv;
5096   GtkWidget *widget;
5097   GList *children;
5098   gint tab_pos = get_effective_tab_pos (notebook);
5099   gint tab_overlap;
5100   gint arrow_spacing;
5101   gint scroll_arrow_hlength;
5102   gint scroll_arrow_vlength;
5103   gboolean is_rtl;
5104   gint i;
5105
5106   widget = GTK_WIDGET (notebook);
5107   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5108   children = notebook->children;
5109   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
5110
5111   gtk_widget_style_get (GTK_WIDGET (notebook),
5112                         "arrow-spacing", &arrow_spacing,
5113                         "scroll-arrow-hlength", &scroll_arrow_hlength,
5114                         "scroll-arrow-vlength", &scroll_arrow_vlength,
5115                         NULL);
5116
5117   switch (tab_pos)
5118     {
5119     case GTK_POS_TOP:
5120     case GTK_POS_BOTTOM:
5121       *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
5122       *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
5123
5124       for (i = 0; i < N_ACTION_WIDGETS; i++)
5125         {
5126           if (priv->action_widget[i])
5127             {
5128               if ((i == ACTION_WIDGET_START && !is_rtl) ||
5129                   (i == ACTION_WIDGET_END && is_rtl))
5130                 *min += priv->action_widget[i]->allocation.width + widget->style->xthickness;
5131               else
5132                 *max -= priv->action_widget[i]->allocation.width + widget->style->xthickness;
5133             }
5134         }
5135
5136       while (children)
5137         {
5138           GtkNotebookPage *page;
5139
5140           page = children->data;
5141           children = children->next;
5142
5143           if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5144               gtk_widget_get_visible (page->child))
5145             *tab_space += page->requisition.width;
5146         }
5147       break;
5148     case GTK_POS_RIGHT:
5149     case GTK_POS_LEFT:
5150       *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
5151       *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
5152
5153       for (i = 0; i < N_ACTION_WIDGETS; i++)
5154         {
5155           if (priv->action_widget[i])
5156             {
5157               if (i == ACTION_WIDGET_START)
5158                 *min += priv->action_widget[i]->allocation.height + widget->style->ythickness;
5159               else
5160                 *max -= priv->action_widget[i]->allocation.height + widget->style->ythickness;
5161             }
5162         }
5163
5164       while (children)
5165         {
5166           GtkNotebookPage *page;
5167
5168           page = children->data;
5169           children = children->next;
5170
5171           if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5172               gtk_widget_get_visible (page->child))
5173             *tab_space += page->requisition.height;
5174         }
5175       break;
5176     }
5177
5178   if (!notebook->scrollable)
5179     *show_arrows = FALSE;
5180   else
5181     {
5182       gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5183
5184       switch (tab_pos)
5185         {
5186         case GTK_POS_TOP:
5187         case GTK_POS_BOTTOM:
5188           if (*tab_space > *max - *min - tab_overlap)
5189             {
5190               *show_arrows = TRUE;
5191
5192               /* take arrows into account */
5193               *tab_space = *max - *min - tab_overlap;
5194
5195               if (notebook->has_after_previous)
5196                 {
5197                   *tab_space -= arrow_spacing + scroll_arrow_hlength;
5198                   *max -= arrow_spacing + scroll_arrow_hlength;
5199                 }
5200
5201               if (notebook->has_after_next)
5202                 {
5203                   *tab_space -= arrow_spacing + scroll_arrow_hlength;
5204                   *max -= arrow_spacing + scroll_arrow_hlength;
5205                 }
5206
5207               if (notebook->has_before_previous)
5208                 {
5209                   *tab_space -= arrow_spacing + scroll_arrow_hlength;
5210                   *min += arrow_spacing + scroll_arrow_hlength;
5211                 }
5212
5213               if (notebook->has_before_next)
5214                 {
5215                   *tab_space -= arrow_spacing + scroll_arrow_hlength;
5216                   *min += arrow_spacing + scroll_arrow_hlength;
5217                 }
5218             }
5219           break;
5220         case GTK_POS_LEFT:
5221         case GTK_POS_RIGHT:
5222           if (*tab_space > *max - *min - tab_overlap)
5223             {
5224               *show_arrows = TRUE;
5225
5226               /* take arrows into account */
5227               *tab_space = *max - *min - tab_overlap;
5228
5229               if (notebook->has_after_previous || notebook->has_after_next)
5230                 {
5231                   *tab_space -= arrow_spacing + scroll_arrow_vlength;
5232                   *max -= arrow_spacing + scroll_arrow_vlength;
5233                 }
5234
5235               if (notebook->has_before_previous || notebook->has_before_next)
5236                 {
5237                   *tab_space -= arrow_spacing + scroll_arrow_vlength;
5238                   *min += arrow_spacing + scroll_arrow_vlength;
5239                 }
5240             }
5241           break;
5242         }
5243     }
5244 }
5245
5246 static void
5247 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
5248                                    gboolean     show_arrows,
5249                                    gint         min,
5250                                    gint         max,
5251                                    gint         tab_space,
5252                                    GList      **last_child,
5253                                    gint        *n,
5254                                    gint        *remaining_space)
5255 {
5256   GtkWidget *widget;
5257   GtkContainer *container;
5258   GList *children;
5259   GtkNotebookPage *page;
5260   gint tab_pos, tab_overlap;
5261   
5262   widget = GTK_WIDGET (notebook);
5263   container = GTK_CONTAINER (notebook);
5264   gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5265   tab_pos = get_effective_tab_pos (notebook);
5266
5267   if (show_arrows) /* first_tab <- focus_tab */
5268     {
5269       *remaining_space = tab_space;
5270
5271       if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
5272           gtk_widget_get_visible (notebook->cur_page->child))
5273         {
5274           gtk_notebook_calc_tabs (notebook,
5275                                   notebook->focus_tab,
5276                                   &(notebook->focus_tab),
5277                                   remaining_space, STEP_NEXT);
5278         }
5279
5280       if (tab_space <= 0 || *remaining_space <= 0)
5281         {
5282           /* show 1 tab */
5283           notebook->first_tab = notebook->focus_tab;
5284           *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5285                                                   STEP_NEXT, TRUE);
5286           page = notebook->first_tab->data;
5287           *remaining_space = tab_space - page->requisition.width;
5288           *n = 1;
5289         }
5290       else
5291         {
5292           children = NULL;
5293
5294           if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
5295             {
5296               /* Is first_tab really predecessor of focus_tab? */
5297               page = notebook->first_tab->data;
5298               if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5299                   gtk_widget_get_visible (page->child))
5300                 for (children = notebook->focus_tab;
5301                      children && children != notebook->first_tab;
5302                      children = gtk_notebook_search_page (notebook,
5303                                                           children,
5304                                                           STEP_PREV,
5305                                                           TRUE));
5306             }
5307
5308           if (!children)
5309             {
5310               if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
5311                 notebook->first_tab = notebook->focus_tab;
5312               else
5313                 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
5314                                                                 STEP_NEXT, TRUE);
5315             }
5316           else
5317             /* calculate shown tabs counting backwards from the focus tab */
5318             gtk_notebook_calc_tabs (notebook,
5319                                     gtk_notebook_search_page (notebook,
5320                                                               notebook->focus_tab,
5321                                                               STEP_PREV,
5322                                                               TRUE),
5323                                     &(notebook->first_tab), remaining_space,
5324                                     STEP_PREV);
5325
5326           if (*remaining_space < 0)
5327             {
5328               notebook->first_tab =
5329                 gtk_notebook_search_page (notebook, notebook->first_tab,
5330                                           STEP_NEXT, TRUE);
5331               if (!notebook->first_tab)
5332                 notebook->first_tab = notebook->focus_tab;
5333
5334               *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5335                                                       STEP_NEXT, TRUE); 
5336             }
5337           else /* focus_tab -> end */   
5338             {
5339               if (!notebook->first_tab)
5340                 notebook->first_tab = gtk_notebook_search_page (notebook,
5341                                                                 NULL,
5342                                                                 STEP_NEXT,
5343                                                                 TRUE);
5344               children = NULL;
5345               gtk_notebook_calc_tabs (notebook,
5346                                       gtk_notebook_search_page (notebook,
5347                                                                 notebook->focus_tab,
5348                                                                 STEP_NEXT,
5349                                                                 TRUE),
5350                                       &children, remaining_space, STEP_NEXT);
5351
5352               if (*remaining_space <= 0) 
5353                 *last_child = children;
5354               else /* start <- first_tab */
5355                 {
5356                   *last_child = NULL;
5357                   children = NULL;
5358
5359                   gtk_notebook_calc_tabs (notebook,
5360                                           gtk_notebook_search_page (notebook,
5361                                                                     notebook->first_tab,
5362                                                                     STEP_PREV,
5363                                                                     TRUE),
5364                                           &children, remaining_space, STEP_PREV);
5365
5366                   if (*remaining_space == 0)
5367                     notebook->first_tab = children;
5368                   else
5369                     notebook->first_tab = gtk_notebook_search_page(notebook,
5370                                                                    children,
5371                                                                    STEP_NEXT,
5372                                                                    TRUE);
5373                 }
5374             }
5375
5376           if (*remaining_space < 0)
5377             {
5378               /* calculate number of tabs */
5379               *remaining_space = - (*remaining_space);
5380               *n = 0;
5381
5382               for (children = notebook->first_tab;
5383                    children && children != *last_child;
5384                    children = gtk_notebook_search_page (notebook, children,
5385                                                         STEP_NEXT, TRUE))
5386                 (*n)++;
5387             }
5388           else
5389             *remaining_space = 0;
5390         }
5391
5392       /* unmap all non-visible tabs */
5393       for (children = gtk_notebook_search_page (notebook, NULL,
5394                                                 STEP_NEXT, TRUE);
5395            children && children != notebook->first_tab;
5396            children = gtk_notebook_search_page (notebook, children,
5397                                                 STEP_NEXT, TRUE))
5398         {
5399           page = children->data;
5400
5401           if (page->tab_label &&
5402               NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5403             gtk_widget_set_child_visible (page->tab_label, FALSE);
5404         }
5405
5406       for (children = *last_child; children;
5407            children = gtk_notebook_search_page (notebook, children,
5408                                                 STEP_NEXT, TRUE))
5409         {
5410           page = children->data;
5411
5412           if (page->tab_label &&
5413               NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5414             gtk_widget_set_child_visible (page->tab_label, FALSE);
5415         }
5416     }
5417   else /* !show_arrows */
5418     {
5419       gint c = 0;
5420       *n = 0;
5421
5422       *remaining_space = max - min - tab_overlap - tab_space;
5423       children = notebook->children;
5424       notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5425                                                       STEP_NEXT, TRUE);
5426       while (children)
5427         {
5428           page = children->data;
5429           children = children->next;
5430
5431           if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5432               !gtk_widget_get_visible (page->child))
5433             continue;
5434
5435           c++;
5436
5437           if (page->expand)
5438             (*n)++;
5439         }
5440
5441       /* if notebook is homogeneous, all tabs are expanded */
5442       if (notebook->homogeneous && *n)
5443         *n = c;
5444     }
5445 }
5446
5447 static gboolean
5448 get_allocate_at_bottom (GtkWidget *widget,
5449                         gint       search_direction)
5450 {
5451   gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5452   gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5453
5454   switch (tab_pos)
5455     {
5456     case GTK_POS_TOP:
5457     case GTK_POS_BOTTOM:
5458       if (!is_rtl)
5459         return (search_direction == STEP_PREV);
5460       else
5461         return (search_direction == STEP_NEXT);
5462
5463       break;
5464     case GTK_POS_RIGHT:
5465     case GTK_POS_LEFT:
5466       return (search_direction == STEP_PREV);
5467       break;
5468     }
5469
5470   return FALSE;
5471 }
5472
5473 static void
5474 gtk_notebook_calculate_tabs_allocation (GtkNotebook  *notebook,
5475                                         GList       **children,
5476                                         GList        *last_child,
5477                                         gboolean      showarrow,
5478                                         gint          direction,
5479                                         gint         *remaining_space,
5480                                         gint         *expanded_tabs,
5481                                         gint          min,
5482                                         gint          max)
5483 {
5484   GtkWidget *widget;
5485   GtkContainer *container;
5486   GtkNotebookPrivate *priv;
5487   GtkNotebookPage *page;
5488   gboolean allocate_at_bottom;
5489   gint tab_overlap, tab_pos, tab_extra_space;
5490   gint left_x, right_x, top_y, bottom_y, anchor;
5491   gint xthickness, ythickness;
5492   gboolean gap_left, packing_changed;
5493   GtkAllocation child_allocation = { 0, };
5494
5495   widget = GTK_WIDGET (notebook);
5496   container = GTK_CONTAINER (notebook);
5497   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5498   gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5499   tab_pos = get_effective_tab_pos (notebook);
5500   allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5501   anchor = 0;
5502
5503   child_allocation.x = widget->allocation.x + container->border_width;
5504   child_allocation.y = widget->allocation.y + container->border_width;
5505
5506   xthickness = widget->style->xthickness;
5507   ythickness = widget->style->ythickness;
5508
5509   switch (tab_pos)
5510     {
5511     case GTK_POS_BOTTOM:
5512       child_allocation.y = widget->allocation.y + widget->allocation.height -
5513         notebook->cur_page->requisition.height - container->border_width;
5514       /* fall through */
5515     case GTK_POS_TOP:
5516       child_allocation.x = (allocate_at_bottom) ? max : min;
5517       child_allocation.height = notebook->cur_page->requisition.height;
5518       anchor = child_allocation.x;
5519       break;
5520       
5521     case GTK_POS_RIGHT:
5522       child_allocation.x = widget->allocation.x + widget->allocation.width -
5523         notebook->cur_page->requisition.width - container->border_width;
5524       /* fall through */
5525     case GTK_POS_LEFT:
5526       child_allocation.y = (allocate_at_bottom) ? max : min;
5527       child_allocation.width = notebook->cur_page->requisition.width;
5528       anchor = child_allocation.y;
5529       break;
5530     }
5531
5532   left_x   = CLAMP (priv->mouse_x - priv->drag_offset_x,
5533                     min, max - notebook->cur_page->allocation.width);
5534   top_y    = CLAMP (priv->mouse_y - priv->drag_offset_y,
5535                     min, max - notebook->cur_page->allocation.height);
5536   right_x  = left_x + notebook->cur_page->allocation.width;
5537   bottom_y = top_y + notebook->cur_page->allocation.height;
5538   gap_left = packing_changed = FALSE;
5539
5540   while (*children && *children != last_child)
5541     {
5542       page = (*children)->data;
5543
5544       if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5545         {
5546           if (!showarrow)
5547             break;
5548           else if (priv->operation == DRAG_OPERATION_REORDER)
5549             packing_changed = TRUE;
5550         }
5551
5552       if (direction == STEP_NEXT)
5553         *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5554       else
5555         {
5556           *children = (*children)->next;
5557
5558           if (page->pack != GTK_PACK_END || !gtk_widget_get_visible (page->child))
5559             continue;
5560         }
5561
5562       if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5563         continue;
5564
5565       tab_extra_space = 0;
5566       if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5567         {
5568           tab_extra_space = *remaining_space / *expanded_tabs;
5569           *remaining_space -= tab_extra_space;
5570           (*expanded_tabs)--;
5571         }
5572
5573       switch (tab_pos)
5574         {
5575         case GTK_POS_TOP:
5576         case GTK_POS_BOTTOM:
5577           child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5578
5579           /* make sure that the reordered tab doesn't go past the last position */
5580           if (priv->operation == DRAG_OPERATION_REORDER &&
5581               !gap_left && packing_changed)
5582             {
5583               if (!allocate_at_bottom)
5584                 {
5585                   if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5586                       (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5587                     {
5588                       left_x = priv->drag_window_x = anchor;
5589                       anchor += notebook->cur_page->allocation.width - tab_overlap;
5590                     }
5591                 }
5592               else
5593                 {
5594                   if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5595                       (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5596                     {
5597                       anchor -= notebook->cur_page->allocation.width;
5598                       left_x = priv->drag_window_x = anchor;
5599                       anchor += tab_overlap;
5600                     }
5601                 }
5602
5603               gap_left = TRUE;
5604             }
5605
5606           if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5607             {
5608               priv->drag_window_x = left_x;
5609               priv->drag_window_y = child_allocation.y;
5610             }
5611           else
5612             {
5613               if (allocate_at_bottom)
5614                 anchor -= child_allocation.width;
5615  
5616               if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5617                 {
5618                   if (!allocate_at_bottom &&
5619                       left_x >= anchor &&
5620                       left_x <= anchor + child_allocation.width / 2)
5621                     anchor += notebook->cur_page->allocation.width - tab_overlap;
5622                   else if (allocate_at_bottom &&
5623                            right_x >= anchor + child_allocation.width / 2 &&
5624                            right_x <= anchor + child_allocation.width)
5625                     anchor -= notebook->cur_page->allocation.width - tab_overlap;
5626                 }
5627
5628               child_allocation.x = anchor;
5629             }
5630
5631           break;
5632         case GTK_POS_LEFT:
5633         case GTK_POS_RIGHT:
5634           child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5635
5636           /* make sure that the reordered tab doesn't go past the last position */
5637           if (priv->operation == DRAG_OPERATION_REORDER &&
5638               !gap_left && packing_changed)
5639             {
5640               if (!allocate_at_bottom &&
5641                   ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5642                    (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5643                 {
5644                   top_y = priv->drag_window_y = anchor;
5645                   anchor += notebook->cur_page->allocation.height - tab_overlap;
5646                 }
5647  
5648               gap_left = TRUE;
5649             }
5650
5651           if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5652             {
5653               priv->drag_window_x = child_allocation.x;
5654               priv->drag_window_y = top_y;
5655             }
5656           else
5657             {
5658               if (allocate_at_bottom)
5659                 anchor -= child_allocation.height;
5660
5661               if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5662                 {
5663                   if (!allocate_at_bottom &&
5664                       top_y >= anchor &&
5665                       top_y <= anchor + child_allocation.height / 2)
5666                     anchor += notebook->cur_page->allocation.height - tab_overlap;
5667                   else if (allocate_at_bottom &&
5668                            bottom_y >= anchor + child_allocation.height / 2 &&
5669                            bottom_y <= anchor + child_allocation.height)
5670                     anchor -= notebook->cur_page->allocation.height - tab_overlap;
5671                 }
5672
5673               child_allocation.y = anchor;
5674             }
5675
5676           break;
5677         }
5678
5679       page->allocation = child_allocation;
5680
5681       if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5682           (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5683         {
5684           /* needs to be allocated at 0,0
5685            * to be shown in the drag window */
5686           page->allocation.x = 0;
5687           page->allocation.y = 0;
5688         }
5689       
5690       if (page != notebook->cur_page)
5691         {
5692           switch (tab_pos)
5693             {
5694             case GTK_POS_TOP:
5695               page->allocation.y += ythickness;
5696               /* fall through */
5697             case GTK_POS_BOTTOM:
5698               page->allocation.height = MAX (1, page->allocation.height - ythickness);
5699               break;
5700             case GTK_POS_LEFT:
5701               page->allocation.x += xthickness;
5702               /* fall through */
5703             case GTK_POS_RIGHT:
5704               page->allocation.width = MAX (1, page->allocation.width - xthickness);
5705               break;
5706             }
5707         }
5708
5709       /* calculate whether to leave a gap based on reorder operation or not */
5710       switch (tab_pos)
5711         {
5712         case GTK_POS_TOP:
5713         case GTK_POS_BOTTOM:
5714           if (priv->operation != DRAG_OPERATION_REORDER ||
5715               (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5716             {
5717               if (priv->operation == DRAG_OPERATION_REORDER)
5718                 {
5719                   if (page->pack == notebook->cur_page->pack &&
5720                       !allocate_at_bottom &&
5721                       left_x >  anchor + child_allocation.width / 2 &&
5722                       left_x <= anchor + child_allocation.width)
5723                     anchor += notebook->cur_page->allocation.width - tab_overlap;
5724                   else if (page->pack == notebook->cur_page->pack &&
5725                            allocate_at_bottom &&
5726                            right_x >= anchor &&
5727                            right_x <= anchor + child_allocation.width / 2)
5728                     anchor -= notebook->cur_page->allocation.width - tab_overlap;
5729                 }
5730  
5731               if (!allocate_at_bottom)
5732                 anchor += child_allocation.width - tab_overlap;
5733               else
5734                 anchor += tab_overlap;
5735             }
5736
5737           break;
5738         case GTK_POS_LEFT:
5739         case GTK_POS_RIGHT:
5740           if (priv->operation != DRAG_OPERATION_REORDER  ||
5741               (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5742             {
5743               if (priv->operation == DRAG_OPERATION_REORDER)
5744                 {
5745                   if (page->pack == notebook->cur_page->pack &&
5746                       !allocate_at_bottom &&
5747                       top_y >= anchor + child_allocation.height / 2 &&
5748                       top_y <= anchor + child_allocation.height)
5749                     anchor += notebook->cur_page->allocation.height - tab_overlap;
5750                   else if (page->pack == notebook->cur_page->pack &&
5751                            allocate_at_bottom &&
5752                            bottom_y >= anchor &&
5753                            bottom_y <= anchor + child_allocation.height / 2)
5754                     anchor -= notebook->cur_page->allocation.height - tab_overlap;
5755                 }
5756
5757               if (!allocate_at_bottom)
5758                 anchor += child_allocation.height - tab_overlap;
5759               else
5760                 anchor += tab_overlap;
5761             }
5762
5763           break;
5764         }
5765
5766       /* set child visible */
5767       if (page->tab_label)
5768         gtk_widget_set_child_visible (page->tab_label, TRUE);
5769     }
5770
5771   /* Don't move the current tab past the last position during tabs reordering */
5772   if (children &&
5773       priv->operation == DRAG_OPERATION_REORDER &&
5774       ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5775        ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5776     {
5777       switch (tab_pos)
5778         {
5779         case GTK_POS_TOP:
5780         case GTK_POS_BOTTOM:
5781           if (allocate_at_bottom)
5782             anchor -= notebook->cur_page->allocation.width;
5783
5784           if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5785               (allocate_at_bottom && priv->drag_window_x < anchor))
5786             priv->drag_window_x = anchor;
5787           break;
5788         case GTK_POS_LEFT:
5789         case GTK_POS_RIGHT:
5790           if (allocate_at_bottom)
5791             anchor -= notebook->cur_page->allocation.height;
5792
5793           if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5794               (allocate_at_bottom && priv->drag_window_y < anchor))
5795             priv->drag_window_y = anchor;
5796           break;
5797         }
5798     }
5799 }
5800
5801 static void
5802 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5803 {
5804   GList *children = NULL;
5805   GList *last_child = NULL;
5806   gboolean showarrow = FALSE;
5807   gint tab_space, min, max, remaining_space;
5808   gint expanded_tabs, operation;
5809   gboolean tab_allocations_changed = FALSE;
5810
5811   if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5812     return;
5813
5814   min = max = tab_space = remaining_space = 0;
5815   expanded_tabs = 1;
5816
5817   gtk_notebook_tab_space (notebook, &showarrow,
5818                           &min, &max, &tab_space);
5819
5820   gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5821                                      min, max, tab_space, &last_child,
5822                                      &expanded_tabs, &remaining_space);
5823
5824   children = notebook->first_tab;
5825   gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5826                                           showarrow, STEP_NEXT,
5827                                           &remaining_space, &expanded_tabs, min, max);
5828   if (children && children != last_child)
5829     {
5830       children = notebook->children;
5831       gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5832                                               showarrow, STEP_PREV,
5833                                               &remaining_space, &expanded_tabs, min, max);
5834     }
5835
5836   children = notebook->children;
5837
5838   while (children)
5839     {
5840       if (gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children)))
5841         tab_allocations_changed = TRUE;
5842       children = children->next;
5843     }
5844
5845   operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5846
5847   if (!notebook->first_tab)
5848     notebook->first_tab = notebook->children;
5849
5850   if (tab_allocations_changed)
5851     gtk_notebook_redraw_tabs (notebook);
5852 }
5853
5854 static gboolean
5855 gtk_notebook_page_allocate (GtkNotebook     *notebook,
5856                             GtkNotebookPage *page)
5857 {
5858   GtkWidget *widget = GTK_WIDGET (notebook);
5859   GtkAllocation child_allocation;
5860   GtkRequisition tab_requisition;
5861   gint xthickness;
5862   gint ythickness;
5863   gint padding;
5864   gint focus_width;
5865   gint tab_curvature;
5866   gint tab_pos = get_effective_tab_pos (notebook);
5867   gboolean tab_allocation_changed;
5868   gboolean was_visible = page->tab_allocated_visible;
5869
5870   if (!page->tab_label ||
5871       !gtk_widget_get_visible (page->tab_label) ||
5872       !gtk_widget_get_child_visible (page->tab_label))
5873     {
5874       page->tab_allocated_visible = FALSE;
5875       return was_visible;
5876     }
5877
5878   xthickness = widget->style->xthickness;
5879   ythickness = widget->style->ythickness;
5880
5881   gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5882   gtk_widget_style_get (widget,
5883                         "focus-line-width", &focus_width,
5884                         "tab-curvature", &tab_curvature,
5885                         NULL);
5886   switch (tab_pos)
5887     {
5888     case GTK_POS_TOP:
5889     case GTK_POS_BOTTOM:
5890       padding = tab_curvature + focus_width + notebook->tab_hborder;
5891       if (page->fill)
5892         {
5893           child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5894           child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5895           child_allocation.x += page->allocation.x;
5896         }
5897       else
5898         {
5899           child_allocation.x = page->allocation.x +
5900             (page->allocation.width - tab_requisition.width) / 2;
5901
5902           child_allocation.width = tab_requisition.width;
5903         }
5904
5905       child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5906
5907       if (tab_pos == GTK_POS_TOP)
5908         child_allocation.y += ythickness;
5909
5910       child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5911                                          2 * (notebook->tab_vborder + focus_width)));
5912       break;
5913     case GTK_POS_LEFT:
5914     case GTK_POS_RIGHT:
5915       padding = tab_curvature + focus_width + notebook->tab_vborder;
5916       if (page->fill)
5917         {
5918           child_allocation.y = ythickness + padding;
5919           child_allocation.height = MAX (1, (page->allocation.height -
5920                                              2 * child_allocation.y));
5921           child_allocation.y += page->allocation.y;
5922         }
5923       else
5924         {
5925           child_allocation.y = page->allocation.y +
5926             (page->allocation.height - tab_requisition.height) / 2;
5927
5928           child_allocation.height = tab_requisition.height;
5929         }
5930
5931       child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5932
5933       if (tab_pos == GTK_POS_LEFT)
5934         child_allocation.x += xthickness;
5935
5936       child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5937                                         2 * (notebook->tab_hborder + focus_width)));
5938       break;
5939     }
5940
5941   tab_allocation_changed = (child_allocation.x != page->tab_label->allocation.x ||
5942                             child_allocation.y != page->tab_label->allocation.y ||
5943                             child_allocation.width != page->tab_label->allocation.width ||
5944                             child_allocation.height != page->tab_label->allocation.height);
5945
5946   gtk_widget_size_allocate (page->tab_label, &child_allocation);
5947
5948   if (!was_visible)
5949     {
5950       page->tab_allocated_visible = TRUE;
5951       tab_allocation_changed = TRUE;
5952     }
5953
5954   return tab_allocation_changed;
5955 }
5956
5957 static void 
5958 gtk_notebook_calc_tabs (GtkNotebook  *notebook,
5959                         GList        *start,
5960                         GList       **end,
5961                         gint         *tab_space,
5962                         guint         direction)
5963 {
5964   GtkNotebookPage *page = NULL;
5965   GList *children;
5966   GList *last_list = NULL;
5967   GList *last_calculated_child = NULL;
5968   gboolean pack;
5969   gint tab_pos = get_effective_tab_pos (notebook);
5970   guint real_direction;
5971
5972   if (!start)
5973     return;
5974
5975   children = start;
5976   pack = GTK_NOTEBOOK_PAGE (start)->pack;
5977   if (pack == GTK_PACK_END)
5978     real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5979   else
5980     real_direction = direction;
5981
5982   while (1)
5983     {
5984       switch (tab_pos)
5985         {
5986         case GTK_POS_TOP:
5987         case GTK_POS_BOTTOM:
5988           while (children)
5989             {
5990               page = children->data;
5991               if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5992                   gtk_widget_get_visible (page->child))
5993                 {
5994                   if (page->pack == pack)
5995                     {
5996                       *tab_space -= page->requisition.width;
5997                       if (*tab_space < 0 || children == *end)
5998                         {
5999                           if (*tab_space < 0) 
6000                             {
6001                               *tab_space = - (*tab_space +
6002                                               page->requisition.width);
6003
6004                               if (*tab_space == 0 && direction == STEP_PREV)
6005                                 children = last_calculated_child;
6006
6007                               *end = children;
6008                             }
6009                           return;
6010                         }
6011
6012                       last_calculated_child = children;
6013                     }
6014                   last_list = children;
6015                 }
6016               if (real_direction == STEP_NEXT)
6017                 children = children->next;
6018               else
6019                 children = children->prev;
6020             }
6021           break;
6022         case GTK_POS_LEFT:
6023         case GTK_POS_RIGHT:
6024           while (children)
6025             {
6026               page = children->data;
6027               if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
6028                   gtk_widget_get_visible (page->child))
6029                 {
6030                   if (page->pack == pack)
6031                     {
6032                       *tab_space -= page->requisition.height;
6033                       if (*tab_space < 0 || children == *end)
6034                         {
6035                           if (*tab_space < 0)
6036                             {
6037                               *tab_space = - (*tab_space +
6038                                               page->requisition.height);
6039
6040                               if (*tab_space == 0 && direction == STEP_PREV)
6041                                 children = last_calculated_child;
6042
6043                               *end = children;
6044                             }
6045                           return;
6046                         }
6047
6048                       last_calculated_child = children;
6049                     }
6050                   last_list = children;
6051                 }
6052               if (real_direction == STEP_NEXT)
6053                 children = children->next;
6054               else
6055                 children = children->prev;
6056             }
6057           break;
6058         }
6059       if (real_direction == STEP_PREV)
6060         return;
6061       pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
6062       real_direction = STEP_PREV;
6063       children = last_list;
6064     }
6065 }
6066
6067 static void
6068 gtk_notebook_update_tab_states (GtkNotebook *notebook)
6069 {
6070   GList *list;
6071
6072   for (list = notebook->children; list != NULL; list = list->next)
6073     {
6074       GtkNotebookPage *page = list->data;
6075       
6076       if (page->tab_label)
6077         {
6078           if (page == notebook->cur_page)
6079             gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
6080           else
6081             gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
6082         }
6083     }
6084 }
6085
6086 /* Private GtkNotebook Page Switch Methods:
6087  *
6088  * gtk_notebook_real_switch_page
6089  */
6090 static void
6091 gtk_notebook_real_switch_page (GtkNotebook     *notebook,
6092                                GtkNotebookPage *page,
6093                                guint            page_num)
6094 {
6095   gboolean child_has_focus;
6096
6097   if (notebook->cur_page == page || !gtk_widget_get_visible (page->child))
6098     return;
6099
6100   /* save the value here, changing visibility changes focus */
6101   child_has_focus = notebook->child_has_focus;
6102
6103   if (notebook->cur_page)
6104     gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
6105
6106   notebook->cur_page = page;
6107
6108   if (!notebook->focus_tab ||
6109       notebook->focus_tab->data != (gpointer) notebook->cur_page)
6110     notebook->focus_tab = 
6111       g_list_find (notebook->children, notebook->cur_page);
6112
6113   gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
6114
6115   /* If the focus was on the previous page, move it to the first
6116    * element on the new page, if possible, or if not, to the
6117    * notebook itself.
6118    */
6119   if (child_has_focus)
6120     {
6121       if (notebook->cur_page->last_focus_child &&
6122           gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
6123         gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
6124       else
6125         if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
6126           gtk_widget_grab_focus (GTK_WIDGET (notebook));
6127     }
6128   
6129   gtk_notebook_update_tab_states (notebook);
6130   gtk_widget_queue_resize (GTK_WIDGET (notebook));
6131   g_object_notify (G_OBJECT (notebook), "page");
6132 }
6133
6134 /* Private GtkNotebook Page Switch Functions:
6135  *
6136  * gtk_notebook_switch_page
6137  * gtk_notebook_page_select
6138  * gtk_notebook_switch_focus_tab
6139  * gtk_notebook_menu_switch_page
6140  */
6141 static void
6142 gtk_notebook_switch_page (GtkNotebook     *notebook,
6143                           GtkNotebookPage *page)
6144
6145   guint page_num;
6146
6147   if (notebook->cur_page == page)
6148     return;
6149
6150   page_num = g_list_index (notebook->children, page);
6151
6152   g_signal_emit (notebook,
6153                  notebook_signals[SWITCH_PAGE],
6154                  0,
6155                  page,
6156                  page_num);
6157 }
6158
6159 static gint
6160 gtk_notebook_page_select (GtkNotebook *notebook,
6161                           gboolean     move_focus)
6162 {
6163   GtkNotebookPage *page;
6164   GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
6165   gint tab_pos = get_effective_tab_pos (notebook);
6166
6167   if (!notebook->focus_tab)
6168     return FALSE;
6169
6170   page = notebook->focus_tab->data;
6171   gtk_notebook_switch_page (notebook, page);
6172
6173   if (move_focus)
6174     {
6175       switch (tab_pos)
6176         {
6177         case GTK_POS_TOP:
6178           dir = GTK_DIR_DOWN;
6179           break;
6180         case GTK_POS_BOTTOM:
6181           dir = GTK_DIR_UP;
6182           break;
6183         case GTK_POS_LEFT:
6184           dir = GTK_DIR_RIGHT;
6185           break;
6186         case GTK_POS_RIGHT:
6187           dir = GTK_DIR_LEFT;
6188           break;
6189         }
6190
6191       if (gtk_widget_child_focus (page->child, dir))
6192         return TRUE;
6193     }
6194   return FALSE;
6195 }
6196
6197 static void
6198 gtk_notebook_switch_focus_tab (GtkNotebook *notebook, 
6199                                GList       *new_child)
6200 {
6201   GList *old_child;
6202   GtkNotebookPage *page;
6203
6204   if (notebook->focus_tab == new_child)
6205     return;
6206
6207   old_child = notebook->focus_tab;
6208   notebook->focus_tab = new_child;
6209
6210   if (notebook->scrollable)
6211     gtk_notebook_redraw_arrows (notebook);
6212
6213   if (!notebook->show_tabs || !notebook->focus_tab)
6214     return;
6215
6216   page = notebook->focus_tab->data;
6217   if (GTK_WIDGET_MAPPED (page->tab_label))
6218     gtk_notebook_redraw_tabs (notebook);
6219   else
6220     gtk_notebook_pages_allocate (notebook);
6221
6222   gtk_notebook_switch_page (notebook, page);
6223 }
6224
6225 static void
6226 gtk_notebook_menu_switch_page (GtkWidget       *widget,
6227                                GtkNotebookPage *page)
6228 {
6229   GtkNotebook *notebook;
6230   GList *children;
6231   guint page_num;
6232
6233   notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
6234                            (GTK_MENU (widget->parent)));
6235
6236   if (notebook->cur_page == page)
6237     return;
6238
6239   page_num = 0;
6240   children = notebook->children;
6241   while (children && children->data != page)
6242     {
6243       children = children->next;
6244       page_num++;
6245     }
6246
6247   g_signal_emit (notebook,
6248                  notebook_signals[SWITCH_PAGE],
6249                  0,
6250                  page,
6251                  page_num);
6252 }
6253
6254 /* Private GtkNotebook Menu Functions:
6255  *
6256  * gtk_notebook_menu_item_create
6257  * gtk_notebook_menu_label_unparent
6258  * gtk_notebook_menu_detacher
6259  */
6260 static void
6261 gtk_notebook_menu_item_create (GtkNotebook *notebook, 
6262                                GList       *list)
6263 {       
6264   GtkNotebookPage *page;
6265   GtkWidget *menu_item;
6266
6267   page = list->data;
6268   if (page->default_menu)
6269     {
6270       if (GTK_IS_LABEL (page->tab_label))
6271         page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
6272       else
6273         page->menu_label = gtk_label_new ("");
6274       gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
6275     }
6276
6277   gtk_widget_show (page->menu_label);
6278   menu_item = gtk_menu_item_new ();
6279   gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
6280   gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
6281                          gtk_notebook_real_page_position (notebook, list));
6282   g_signal_connect (menu_item, "activate",
6283                     G_CALLBACK (gtk_notebook_menu_switch_page), page);
6284   if (gtk_widget_get_visible (page->child))
6285     gtk_widget_show (menu_item);
6286 }
6287
6288 static void
6289 gtk_notebook_menu_label_unparent (GtkWidget *widget, 
6290                                   gpointer  data)
6291 {
6292   gtk_widget_unparent (GTK_BIN (widget)->child);
6293   GTK_BIN (widget)->child = NULL;
6294 }
6295
6296 static void
6297 gtk_notebook_menu_detacher (GtkWidget *widget,
6298                             GtkMenu   *menu)
6299 {
6300   GtkNotebook *notebook;
6301
6302   notebook = GTK_NOTEBOOK (widget);
6303   g_return_if_fail (notebook->menu == (GtkWidget*) menu);
6304
6305   notebook->menu = NULL;
6306 }
6307
6308 /* Private GtkNotebook Setter Functions:
6309  *
6310  * gtk_notebook_set_homogeneous_tabs_internal
6311  * gtk_notebook_set_tab_border_internal
6312  * gtk_notebook_set_tab_hborder_internal
6313  * gtk_notebook_set_tab_vborder_internal
6314  */
6315 static void
6316 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
6317                                             gboolean     homogeneous)
6318 {
6319   if (homogeneous == notebook->homogeneous)
6320     return;
6321
6322   notebook->homogeneous = homogeneous;
6323   gtk_widget_queue_resize (GTK_WIDGET (notebook));
6324
6325   g_object_notify (G_OBJECT (notebook), "homogeneous");
6326 }
6327
6328 static void
6329 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
6330                                       guint        border_width)
6331 {
6332   notebook->tab_hborder = border_width;
6333   notebook->tab_vborder = border_width;
6334
6335   if (notebook->show_tabs &&
6336       gtk_widget_get_visible (GTK_WIDGET (notebook)))
6337     gtk_widget_queue_resize (GTK_WIDGET (notebook));
6338
6339   g_object_freeze_notify (G_OBJECT (notebook));
6340   g_object_notify (G_OBJECT (notebook), "tab-hborder");
6341   g_object_notify (G_OBJECT (notebook), "tab-vborder");
6342   g_object_thaw_notify (G_OBJECT (notebook));
6343 }
6344
6345 static void
6346 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
6347                                        guint        tab_hborder)
6348 {
6349   if (notebook->tab_hborder == tab_hborder)
6350     return;
6351
6352   notebook->tab_hborder = tab_hborder;
6353
6354   if (notebook->show_tabs &&
6355       gtk_widget_get_visible (GTK_WIDGET (notebook)))
6356     gtk_widget_queue_resize (GTK_WIDGET (notebook));
6357
6358   g_object_notify (G_OBJECT (notebook), "tab-hborder");
6359 }
6360
6361 static void
6362 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
6363                                        guint        tab_vborder)
6364 {
6365   if (notebook->tab_vborder == tab_vborder)
6366     return;
6367
6368   notebook->tab_vborder = tab_vborder;
6369
6370   if (notebook->show_tabs &&
6371       gtk_widget_get_visible (GTK_WIDGET (notebook)))
6372     gtk_widget_queue_resize (GTK_WIDGET (notebook));
6373
6374   g_object_notify (G_OBJECT (notebook), "tab-vborder");
6375 }
6376
6377 /* Public GtkNotebook Page Insert/Remove Methods :
6378  *
6379  * gtk_notebook_append_page
6380  * gtk_notebook_append_page_menu
6381  * gtk_notebook_prepend_page
6382  * gtk_notebook_prepend_page_menu
6383  * gtk_notebook_insert_page
6384  * gtk_notebook_insert_page_menu
6385  * gtk_notebook_remove_page
6386  */
6387 /**
6388  * gtk_notebook_append_page:
6389  * @notebook: a #GtkNotebook
6390  * @child: the #GtkWidget to use as the contents of the page.
6391  * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6392  *             or %NULL to use the default label, 'page N'.
6393  *
6394  * Appends a page to @notebook.
6395  *
6396  * Return value: the index (starting from 0) of the appended
6397  * page in the notebook, or -1 if function fails
6398  **/
6399 gint
6400 gtk_notebook_append_page (GtkNotebook *notebook,
6401                           GtkWidget   *child,
6402                           GtkWidget   *tab_label)
6403 {
6404   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6405   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6406   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6407   
6408   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6409 }
6410
6411 /**
6412  * gtk_notebook_append_page_menu:
6413  * @notebook: a #GtkNotebook
6414  * @child: the #GtkWidget to use as the contents of the page.
6415  * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6416  *             or %NULL to use the default label, 'page N'.
6417  * @menu_label: (allow-none): the widget to use as a label for the page-switch
6418  *              menu, if that is enabled. If %NULL, and @tab_label
6419  *              is a #GtkLabel or %NULL, then the menu label will be
6420  *              a newly created label with the same text as @tab_label;
6421  *              If @tab_label is not a #GtkLabel, @menu_label must be
6422  *              specified if the page-switch menu is to be used.
6423  * 
6424  * Appends a page to @notebook, specifying the widget to use as the
6425  * label in the popup menu.
6426  *
6427  * Return value: the index (starting from 0) of the appended
6428  * page in the notebook, or -1 if function fails
6429  **/
6430 gint
6431 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6432                                GtkWidget   *child,
6433                                GtkWidget   *tab_label,
6434                                GtkWidget   *menu_label)
6435 {
6436   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6437   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6438   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6439   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6440   
6441   return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6442 }
6443
6444 /**
6445  * gtk_notebook_prepend_page:
6446  * @notebook: a #GtkNotebook
6447  * @child: the #GtkWidget to use as the contents of the page.
6448  * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6449  *             or %NULL to use the default label, 'page N'.
6450  *
6451  * Prepends a page to @notebook.
6452  *
6453  * Return value: the index (starting from 0) of the prepended
6454  * page in the notebook, or -1 if function fails
6455  **/
6456 gint
6457 gtk_notebook_prepend_page (GtkNotebook *notebook,
6458                            GtkWidget   *child,
6459                            GtkWidget   *tab_label)
6460 {
6461   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6462   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6463   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6464   
6465   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6466 }
6467
6468 /**
6469  * gtk_notebook_prepend_page_menu:
6470  * @notebook: a #GtkNotebook
6471  * @child: the #GtkWidget to use as the contents of the page.
6472  * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6473  *             or %NULL to use the default label, 'page N'.
6474  * @menu_label: (allow-none): the widget to use as a label for the page-switch
6475  *              menu, if that is enabled. If %NULL, and @tab_label
6476  *              is a #GtkLabel or %NULL, then the menu label will be
6477  *              a newly created label with the same text as @tab_label;
6478  *              If @tab_label is not a #GtkLabel, @menu_label must be
6479  *              specified if the page-switch menu is to be used.
6480  * 
6481  * Prepends a page to @notebook, specifying the widget to use as the
6482  * label in the popup menu.
6483  *
6484  * Return value: the index (starting from 0) of the prepended
6485  * page in the notebook, or -1 if function fails
6486  **/
6487 gint
6488 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6489                                 GtkWidget   *child,
6490                                 GtkWidget   *tab_label,
6491                                 GtkWidget   *menu_label)
6492 {
6493   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6494   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6495   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6496   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6497   
6498   return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6499 }
6500
6501 /**
6502  * gtk_notebook_insert_page:
6503  * @notebook: a #GtkNotebook
6504  * @child: the #GtkWidget to use as the contents of the page.
6505  * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6506  *             or %NULL to use the default label, 'page N'.
6507  * @position: the index (starting at 0) at which to insert the page,
6508  *            or -1 to append the page after all other pages.
6509  *
6510  * Insert a page into @notebook at the given position.
6511  *
6512  * Return value: the index (starting from 0) of the inserted
6513  * page in the notebook, or -1 if function fails
6514  **/
6515 gint
6516 gtk_notebook_insert_page (GtkNotebook *notebook,
6517                           GtkWidget   *child,
6518                           GtkWidget   *tab_label,
6519                           gint         position)
6520 {
6521   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6522   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6523   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6524   
6525   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6526 }
6527
6528
6529 static gint
6530 gtk_notebook_page_compare_tab (gconstpointer a,
6531                                gconstpointer b)
6532 {
6533   return (((GtkNotebookPage *) a)->tab_label != b);
6534 }
6535
6536 static gboolean
6537 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6538                                             gboolean overload,
6539                                             gpointer data)
6540 {
6541   GtkNotebook *notebook = GTK_NOTEBOOK (data);
6542   GList *list;
6543   
6544   list = g_list_find_custom (notebook->children, child,
6545                              gtk_notebook_page_compare_tab);
6546   if (list)
6547     {
6548       GtkNotebookPage *page = list->data;
6549
6550       gtk_widget_grab_focus (GTK_WIDGET (notebook));    /* Do this first to avoid focusing new page */
6551       gtk_notebook_switch_page (notebook, page);
6552       focus_tabs_in (notebook);
6553     }
6554
6555   return TRUE;
6556 }
6557
6558 /**
6559  * gtk_notebook_insert_page_menu:
6560  * @notebook: a #GtkNotebook
6561  * @child: the #GtkWidget to use as the contents of the page.
6562  * @tab_label: (allow-none): the #GtkWidget to be used as the label for the page,
6563  *             or %NULL to use the default label, 'page N'.
6564  * @menu_label: (allow-none): the widget to use as a label for the page-switch
6565  *              menu, if that is enabled. If %NULL, and @tab_label
6566  *              is a #GtkLabel or %NULL, then the menu label will be
6567  *              a newly created label with the same text as @tab_label;
6568  *              If @tab_label is not a #GtkLabel, @menu_label must be
6569  *              specified if the page-switch menu is to be used.
6570  * @position: the index (starting at 0) at which to insert the page,
6571  *            or -1 to append the page after all other pages.
6572  * 
6573  * Insert a page into @notebook at the given position, specifying
6574  * the widget to use as the label in the popup menu.
6575  *
6576  * Return value: the index (starting from 0) of the inserted
6577  * page in the notebook
6578  **/
6579 gint
6580 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6581                                GtkWidget   *child,
6582                                GtkWidget   *tab_label,
6583                                GtkWidget   *menu_label,
6584                                gint         position)
6585 {
6586   GtkNotebookClass *class;
6587
6588   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6589   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6590   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6591   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6592
6593   class = GTK_NOTEBOOK_GET_CLASS (notebook);
6594
6595   return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6596 }
6597
6598 /**
6599  * gtk_notebook_remove_page:
6600  * @notebook: a #GtkNotebook.
6601  * @page_num: the index of a notebook page, starting
6602  *            from 0. If -1, the last page will
6603  *            be removed.
6604  * 
6605  * Removes a page from the notebook given its index
6606  * in the notebook.
6607  **/
6608 void
6609 gtk_notebook_remove_page (GtkNotebook *notebook,
6610                           gint         page_num)
6611 {
6612   GList *list = NULL;
6613
6614   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6615
6616   if (page_num >= 0)
6617     list = g_list_nth (notebook->children, page_num);
6618   else
6619     list = g_list_last (notebook->children);
6620
6621   if (list)
6622     gtk_container_remove (GTK_CONTAINER (notebook),
6623                           ((GtkNotebookPage *) list->data)->child);
6624 }
6625
6626 /* Public GtkNotebook Page Switch Methods :
6627  * gtk_notebook_get_current_page
6628  * gtk_notebook_page_num
6629  * gtk_notebook_set_current_page
6630  * gtk_notebook_next_page
6631  * gtk_notebook_prev_page
6632  */
6633 /**
6634  * gtk_notebook_get_current_page:
6635  * @notebook: a #GtkNotebook
6636  * 
6637  * Returns the page number of the current page.
6638  * 
6639  * Return value: the index (starting from 0) of the current
6640  * page in the notebook. If the notebook has no pages, then
6641  * -1 will be returned.
6642  **/
6643 gint
6644 gtk_notebook_get_current_page (GtkNotebook *notebook)
6645 {
6646   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6647
6648   if (!notebook->cur_page)
6649     return -1;
6650
6651   return g_list_index (notebook->children, notebook->cur_page);
6652 }
6653
6654 /**
6655  * gtk_notebook_get_nth_page:
6656  * @notebook: a #GtkNotebook
6657  * @page_num: the index of a page in the notebook, or -1
6658  *            to get the last page.
6659  * 
6660  * Returns the child widget contained in page number @page_num.
6661  *
6662  * Return value: (transfer none): the child widget, or %NULL if @page_num is
6663  * out of bounds.
6664  **/
6665 GtkWidget*
6666 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6667                            gint         page_num)
6668 {
6669   GtkNotebookPage *page;
6670   GList *list;
6671
6672   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6673
6674   if (page_num >= 0)
6675     list = g_list_nth (notebook->children, page_num);
6676   else
6677     list = g_list_last (notebook->children);
6678
6679   if (list)
6680     {
6681       page = list->data;
6682       return page->child;
6683     }
6684
6685   return NULL;
6686 }
6687
6688 /**
6689  * gtk_notebook_get_n_pages:
6690  * @notebook: a #GtkNotebook
6691  * 
6692  * Gets the number of pages in a notebook.
6693  * 
6694  * Return value: the number of pages in the notebook.
6695  *
6696  * Since: 2.2
6697  **/
6698 gint
6699 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6700 {
6701   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6702
6703   return g_list_length (notebook->children);
6704 }
6705
6706 /**
6707  * gtk_notebook_page_num:
6708  * @notebook: a #GtkNotebook
6709  * @child: a #GtkWidget
6710  * 
6711  * Finds the index of the page which contains the given child
6712  * widget.
6713  * 
6714  * Return value: the index of the page containing @child, or
6715  *   -1 if @child is not in the notebook.
6716  **/
6717 gint
6718 gtk_notebook_page_num (GtkNotebook      *notebook,
6719                        GtkWidget        *child)
6720 {
6721   GList *children;
6722   gint num;
6723
6724   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6725
6726   num = 0;
6727   children = notebook->children;
6728   while (children)
6729     {
6730       GtkNotebookPage *page =  children->data;
6731       
6732       if (page->child == child)
6733         return num;
6734
6735       children = children->next;
6736       num++;
6737     }
6738
6739   return -1;
6740 }
6741
6742 /**
6743  * gtk_notebook_set_current_page:
6744  * @notebook: a #GtkNotebook
6745  * @page_num: index of the page to switch to, starting from 0.
6746  *            If negative, the last page will be used. If greater
6747  *            than the number of pages in the notebook, nothing
6748  *            will be done.
6749  *                
6750  * Switches to the page number @page_num. 
6751  *
6752  * Note that due to historical reasons, GtkNotebook refuses
6753  * to switch to a page unless the child widget is visible. 
6754  * Therefore, it is recommended to show child widgets before
6755  * adding them to a notebook. 
6756  */
6757 void
6758 gtk_notebook_set_current_page (GtkNotebook *notebook,
6759                                gint         page_num)
6760 {
6761   GList *list;
6762
6763   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6764
6765   if (page_num < 0)
6766     page_num = g_list_length (notebook->children) - 1;
6767
6768   list = g_list_nth (notebook->children, page_num);
6769   if (list)
6770     gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6771 }
6772
6773 /**
6774  * gtk_notebook_next_page:
6775  * @notebook: a #GtkNotebook
6776  * 
6777  * Switches to the next page. Nothing happens if the current page is
6778  * the last page.
6779  **/
6780 void
6781 gtk_notebook_next_page (GtkNotebook *notebook)
6782 {
6783   GList *list;
6784
6785   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6786
6787   list = g_list_find (notebook->children, notebook->cur_page);
6788   if (!list)
6789     return;
6790
6791   list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6792   if (!list)
6793     return;
6794
6795   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6796 }
6797
6798 /**
6799  * gtk_notebook_prev_page:
6800  * @notebook: a #GtkNotebook
6801  * 
6802  * Switches to the previous page. Nothing happens if the current page
6803  * is the first page.
6804  **/
6805 void
6806 gtk_notebook_prev_page (GtkNotebook *notebook)
6807 {
6808   GList *list;
6809
6810   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6811
6812   list = g_list_find (notebook->children, notebook->cur_page);
6813   if (!list)
6814     return;
6815
6816   list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6817   if (!list)
6818     return;
6819
6820   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6821 }
6822
6823 /* Public GtkNotebook/Tab Style Functions
6824  *
6825  * gtk_notebook_set_show_border
6826  * gtk_notebook_set_show_tabs
6827  * gtk_notebook_set_tab_pos
6828  * gtk_notebook_set_homogeneous_tabs
6829  * gtk_notebook_set_tab_border
6830  * gtk_notebook_set_tab_hborder
6831  * gtk_notebook_set_tab_vborder
6832  * gtk_notebook_set_scrollable
6833  */
6834 /**
6835  * gtk_notebook_set_show_border:
6836  * @notebook: a #GtkNotebook
6837  * @show_border: %TRUE if a bevel should be drawn around the notebook.
6838  * 
6839  * Sets whether a bevel will be drawn around the notebook pages.
6840  * This only has a visual effect when the tabs are not shown.
6841  * See gtk_notebook_set_show_tabs().
6842  **/
6843 void
6844 gtk_notebook_set_show_border (GtkNotebook *notebook,
6845                               gboolean     show_border)
6846 {
6847   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6848
6849   if (notebook->show_border != show_border)
6850     {
6851       notebook->show_border = show_border;
6852
6853       if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6854         gtk_widget_queue_resize (GTK_WIDGET (notebook));
6855       
6856       g_object_notify (G_OBJECT (notebook), "show-border");
6857     }
6858 }
6859
6860 /**
6861  * gtk_notebook_get_show_border:
6862  * @notebook: a #GtkNotebook
6863  *
6864  * Returns whether a bevel will be drawn around the notebook pages. See
6865  * gtk_notebook_set_show_border().
6866  *
6867  * Return value: %TRUE if the bevel is drawn
6868  **/
6869 gboolean
6870 gtk_notebook_get_show_border (GtkNotebook *notebook)
6871 {
6872   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6873
6874   return notebook->show_border;
6875 }
6876
6877 /**
6878  * gtk_notebook_set_show_tabs:
6879  * @notebook: a #GtkNotebook
6880  * @show_tabs: %TRUE if the tabs should be shown.
6881  * 
6882  * Sets whether to show the tabs for the notebook or not.
6883  **/
6884 void
6885 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6886                             gboolean     show_tabs)
6887 {
6888   GtkNotebookPrivate *priv;
6889   GtkNotebookPage *page;
6890   GList *children;
6891   gint i;
6892
6893   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6894
6895   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
6896
6897   show_tabs = show_tabs != FALSE;
6898
6899   if (notebook->show_tabs == show_tabs)
6900     return;
6901
6902   notebook->show_tabs = show_tabs;
6903   children = notebook->children;
6904
6905   if (!show_tabs)
6906     {
6907       GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6908
6909       while (children)
6910         {
6911           page = children->data;
6912           children = children->next;
6913           if (page->default_tab)
6914             {
6915               gtk_widget_destroy (page->tab_label);
6916               page->tab_label = NULL;
6917             }
6918           else
6919             gtk_widget_hide (page->tab_label);
6920         }
6921     }
6922   else
6923     {
6924       GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6925       gtk_notebook_update_labels (notebook);
6926     }
6927
6928   for (i = 0; i < N_ACTION_WIDGETS; i++)
6929     {
6930       if (priv->action_widget[i])
6931         gtk_widget_set_child_visible (priv->action_widget[i], show_tabs);
6932     }
6933
6934   gtk_widget_queue_resize (GTK_WIDGET (notebook));
6935
6936   g_object_notify (G_OBJECT (notebook), "show-tabs");
6937 }
6938
6939 /**
6940  * gtk_notebook_get_show_tabs:
6941  * @notebook: a #GtkNotebook
6942  *
6943  * Returns whether the tabs of the notebook are shown. See
6944  * gtk_notebook_set_show_tabs().
6945  *
6946  * Return value: %TRUE if the tabs are shown
6947  **/
6948 gboolean
6949 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6950 {
6951   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6952
6953   return notebook->show_tabs;
6954 }
6955
6956 /**
6957  * gtk_notebook_set_tab_pos:
6958  * @notebook: a #GtkNotebook.
6959  * @pos: the edge to draw the tabs at.
6960  * 
6961  * Sets the edge at which the tabs for switching pages in the
6962  * notebook are drawn.
6963  **/
6964 void
6965 gtk_notebook_set_tab_pos (GtkNotebook     *notebook,
6966                           GtkPositionType  pos)
6967 {
6968   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6969
6970   if (notebook->tab_pos != pos)
6971     {
6972       notebook->tab_pos = pos;
6973       if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
6974         gtk_widget_queue_resize (GTK_WIDGET (notebook));
6975     }
6976
6977   g_object_notify (G_OBJECT (notebook), "tab-pos");
6978 }
6979
6980 /**
6981  * gtk_notebook_get_tab_pos:
6982  * @notebook: a #GtkNotebook
6983  *
6984  * Gets the edge at which the tabs for switching pages in the
6985  * notebook are drawn.
6986  *
6987  * Return value: the edge at which the tabs are drawn
6988  **/
6989 GtkPositionType
6990 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6991 {
6992   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6993
6994   return notebook->tab_pos;
6995 }
6996
6997 /**
6998  * gtk_notebook_set_homogeneous_tabs:
6999  * @notebook: a #GtkNotebook
7000  * @homogeneous: %TRUE if all tabs should be the same size.
7001  * 
7002  * Sets whether the tabs must have all the same size or not.
7003  **/
7004 void
7005 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
7006                                    gboolean     homogeneous)
7007 {
7008   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7009
7010   gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
7011 }
7012
7013 /**
7014  * gtk_notebook_set_tab_border:
7015  * @notebook: a #GtkNotebook
7016  * @border_width: width of the border around the tab labels.
7017  * 
7018  * Sets the width the border around the tab labels
7019  * in a notebook. This is equivalent to calling
7020  * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
7021  * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
7022  **/
7023 void
7024 gtk_notebook_set_tab_border (GtkNotebook *notebook,
7025                              guint        border_width)
7026 {
7027   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7028
7029   gtk_notebook_set_tab_border_internal (notebook, border_width);
7030 }
7031
7032 /**
7033  * gtk_notebook_set_tab_hborder:
7034  * @notebook: a #GtkNotebook
7035  * @tab_hborder: width of the horizontal border of tab labels.
7036  * 
7037  * Sets the width of the horizontal border of tab labels.
7038  **/
7039 void
7040 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
7041                               guint        tab_hborder)
7042 {
7043   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7044
7045   gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
7046 }
7047
7048 /**
7049  * gtk_notebook_set_tab_vborder:
7050  * @notebook: a #GtkNotebook
7051  * @tab_vborder: width of the vertical border of tab labels.
7052  * 
7053  * Sets the width of the vertical border of tab labels.
7054  **/
7055 void
7056 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
7057                               guint        tab_vborder)
7058 {
7059   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7060
7061   gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
7062 }
7063
7064 /**
7065  * gtk_notebook_set_scrollable:
7066  * @notebook: a #GtkNotebook
7067  * @scrollable: %TRUE if scroll arrows should be added
7068  * 
7069  * Sets whether the tab label area will have arrows for scrolling if
7070  * there are too many tabs to fit in the area.
7071  **/
7072 void
7073 gtk_notebook_set_scrollable (GtkNotebook *notebook,
7074                              gboolean     scrollable)
7075 {
7076   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7077
7078   scrollable = (scrollable != FALSE);
7079
7080   if (scrollable != notebook->scrollable)
7081     {
7082       notebook->scrollable = scrollable;
7083
7084       if (gtk_widget_get_visible (GTK_WIDGET (notebook)))
7085         gtk_widget_queue_resize (GTK_WIDGET (notebook));
7086
7087       g_object_notify (G_OBJECT (notebook), "scrollable");
7088     }
7089 }
7090
7091 /**
7092  * gtk_notebook_get_scrollable:
7093  * @notebook: a #GtkNotebook
7094  *
7095  * Returns whether the tab label area has arrows for scrolling. See
7096  * gtk_notebook_set_scrollable().
7097  *
7098  * Return value: %TRUE if arrows for scrolling are present
7099  **/
7100 gboolean
7101 gtk_notebook_get_scrollable (GtkNotebook *notebook)
7102 {
7103   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7104
7105   return notebook->scrollable;
7106 }
7107
7108 /* Public GtkNotebook Popup Menu Methods:
7109  *
7110  * gtk_notebook_popup_enable
7111  * gtk_notebook_popup_disable
7112  */
7113
7114
7115 /**
7116  * gtk_notebook_popup_enable:
7117  * @notebook: a #GtkNotebook
7118  * 
7119  * Enables the popup menu: if the user clicks with the right mouse button on
7120  * the bookmarks, a menu with all the pages will be popped up.
7121  **/
7122 void
7123 gtk_notebook_popup_enable (GtkNotebook *notebook)
7124 {
7125   GList *list;
7126
7127   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7128
7129   if (notebook->menu)
7130     return;
7131
7132   notebook->menu = gtk_menu_new ();
7133   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
7134        list;
7135        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
7136     gtk_notebook_menu_item_create (notebook, list);
7137
7138   gtk_notebook_update_labels (notebook);
7139   gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
7140                              GTK_WIDGET (notebook),
7141                              gtk_notebook_menu_detacher);
7142
7143   g_object_notify (G_OBJECT (notebook), "enable-popup");
7144 }
7145
7146 /**
7147  * gtk_notebook_popup_disable:
7148  * @notebook: a #GtkNotebook
7149  * 
7150  * Disables the popup menu.
7151  **/
7152 void       
7153 gtk_notebook_popup_disable  (GtkNotebook *notebook)
7154 {
7155   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7156
7157   if (!notebook->menu)
7158     return;
7159
7160   gtk_container_foreach (GTK_CONTAINER (notebook->menu),
7161                          (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
7162   gtk_widget_destroy (notebook->menu);
7163
7164   g_object_notify (G_OBJECT (notebook), "enable-popup");
7165 }
7166
7167 /* Public GtkNotebook Page Properties Functions:
7168  *
7169  * gtk_notebook_get_tab_label
7170  * gtk_notebook_set_tab_label
7171  * gtk_notebook_set_tab_label_text
7172  * gtk_notebook_get_menu_label
7173  * gtk_notebook_set_menu_label
7174  * gtk_notebook_set_menu_label_text
7175  * gtk_notebook_set_tab_label_packing
7176  * gtk_notebook_query_tab_label_packing
7177  * gtk_notebook_get_tab_reorderable
7178  * gtk_notebook_set_tab_reorderable
7179  * gtk_notebook_get_tab_detachable
7180  * gtk_notebook_set_tab_detachable
7181  */
7182
7183 /**
7184  * gtk_notebook_get_tab_label:
7185  * @notebook: a #GtkNotebook
7186  * @child: the page
7187  * 
7188  * Returns the tab label widget for the page @child. %NULL is returned
7189  * if @child is not in @notebook or if no tab label has specifically
7190  * been set for @child.
7191  *
7192  * Return value: (transfer none): the tab label
7193  **/
7194 GtkWidget *
7195 gtk_notebook_get_tab_label (GtkNotebook *notebook,
7196                             GtkWidget   *child)
7197 {
7198   GList *list;
7199
7200   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7201   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7202
7203   list = CHECK_FIND_CHILD (notebook, child);
7204   if (!list)  
7205     return NULL;
7206
7207   if (GTK_NOTEBOOK_PAGE (list)->default_tab)
7208     return NULL;
7209
7210   return GTK_NOTEBOOK_PAGE (list)->tab_label;
7211 }  
7212
7213 /**
7214  * gtk_notebook_set_tab_label:
7215  * @notebook: a #GtkNotebook
7216  * @child: the page
7217  * @tab_label: (allow-none): the tab label widget to use, or %NULL for default tab
7218  *             label.
7219  *
7220  * Changes the tab label for @child. If %NULL is specified
7221  * for @tab_label, then the page will have the label 'page N'.
7222  **/
7223 void
7224 gtk_notebook_set_tab_label (GtkNotebook *notebook,
7225                             GtkWidget   *child,
7226                             GtkWidget   *tab_label)
7227 {
7228   GtkNotebookPage *page;
7229   GList *list;
7230
7231   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7232   g_return_if_fail (GTK_IS_WIDGET (child));
7233
7234   list = CHECK_FIND_CHILD (notebook, child);
7235   if (!list)  
7236     return;
7237
7238   /* a NULL pointer indicates a default_tab setting, otherwise
7239    * we need to set the associated label
7240    */
7241   page = list->data;
7242   
7243   if (page->tab_label == tab_label)
7244     return;
7245   
7246
7247   gtk_notebook_remove_tab_label (notebook, page);
7248   
7249   if (tab_label)
7250     {
7251       page->default_tab = FALSE;
7252       page->tab_label = tab_label;
7253       gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7254     }
7255   else
7256     {
7257       page->default_tab = TRUE;
7258       page->tab_label = NULL;
7259
7260       if (notebook->show_tabs)
7261         {
7262           gchar string[32];
7263
7264           g_snprintf (string, sizeof(string), _("Page %u"), 
7265                       gtk_notebook_real_page_position (notebook, list));
7266           page->tab_label = gtk_label_new (string);
7267           gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
7268         }
7269     }
7270
7271   if (page->tab_label)
7272     page->mnemonic_activate_signal =
7273       g_signal_connect (page->tab_label,
7274                         "mnemonic-activate",
7275                         G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
7276                         notebook);
7277
7278   if (notebook->show_tabs && gtk_widget_get_visible (child))
7279     {
7280       gtk_widget_show (page->tab_label);
7281       gtk_widget_queue_resize (GTK_WIDGET (notebook));
7282     }
7283
7284   gtk_notebook_update_tab_states (notebook);
7285   gtk_widget_child_notify (child, "tab-label");
7286 }
7287
7288 /**
7289  * gtk_notebook_set_tab_label_text:
7290  * @notebook: a #GtkNotebook
7291  * @child: the page
7292  * @tab_text: the label text
7293  * 
7294  * Creates a new label and sets it as the tab label for the page
7295  * containing @child.
7296  **/
7297 void
7298 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
7299                                  GtkWidget   *child,
7300                                  const gchar *tab_text)
7301 {
7302   GtkWidget *tab_label = NULL;
7303
7304   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7305
7306   if (tab_text)
7307     tab_label = gtk_label_new (tab_text);
7308   gtk_notebook_set_tab_label (notebook, child, tab_label);
7309   gtk_widget_child_notify (child, "tab-label");
7310 }
7311
7312 /**
7313  * gtk_notebook_get_tab_label_text:
7314  * @notebook: a #GtkNotebook
7315  * @child: a widget contained in a page of @notebook
7316  *
7317  * Retrieves the text of the tab label for the page containing
7318  *    @child.
7319  *
7320  * Return value: the text of the tab label, or %NULL if the
7321  *               tab label widget is not a #GtkLabel. The
7322  *               string is owned by the widget and must not
7323  *               be freed.
7324  **/
7325 G_CONST_RETURN gchar *
7326 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
7327                                  GtkWidget   *child)
7328 {
7329   GtkWidget *tab_label;
7330
7331   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7332   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7333
7334   tab_label = gtk_notebook_get_tab_label (notebook, child);
7335
7336   if (GTK_IS_LABEL (tab_label))
7337     return gtk_label_get_text (GTK_LABEL (tab_label));
7338   else
7339     return NULL;
7340 }
7341
7342 /**
7343  * gtk_notebook_get_menu_label:
7344  * @notebook: a #GtkNotebook
7345  * @child: a widget contained in a page of @notebook
7346  * 
7347  * Retrieves the menu label widget of the page containing @child.
7348  * 
7349  * Return value: the menu label, or %NULL if the
7350  *               notebook page does not have a menu label other
7351  *               than the default (the tab label).
7352  **/
7353 GtkWidget*
7354 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7355                              GtkWidget   *child)
7356 {
7357   GList *list;
7358
7359   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7360   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7361
7362   list = CHECK_FIND_CHILD (notebook, child);
7363   if (!list)  
7364     return NULL;
7365
7366   if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7367     return NULL;
7368
7369   return GTK_NOTEBOOK_PAGE (list)->menu_label;
7370 }  
7371
7372 /**
7373  * gtk_notebook_set_menu_label:
7374  * @notebook: a #GtkNotebook
7375  * @child: the child widget
7376  * @menu_label: (allow-none): the menu label, or NULL for default
7377  *
7378  * Changes the menu label for the page containing @child.
7379  **/
7380 void
7381 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7382                              GtkWidget   *child,
7383                              GtkWidget   *menu_label)
7384 {
7385   GtkNotebookPage *page;
7386   GList *list;
7387
7388   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7389   g_return_if_fail (GTK_IS_WIDGET (child));
7390
7391   list = CHECK_FIND_CHILD (notebook, child);
7392   if (!list)  
7393     return;
7394
7395   page = list->data;
7396   if (page->menu_label)
7397     {
7398       if (notebook->menu)
7399         gtk_container_remove (GTK_CONTAINER (notebook->menu), 
7400                               page->menu_label->parent);
7401
7402       if (!page->default_menu)
7403         g_object_unref (page->menu_label);
7404     }
7405
7406   if (menu_label)
7407     {
7408       page->menu_label = menu_label;
7409       g_object_ref_sink (page->menu_label);
7410       page->default_menu = FALSE;
7411     }
7412   else
7413     page->default_menu = TRUE;
7414
7415   if (notebook->menu)
7416     gtk_notebook_menu_item_create (notebook, list);
7417   gtk_widget_child_notify (child, "menu-label");
7418 }
7419
7420 /**
7421  * gtk_notebook_set_menu_label_text:
7422  * @notebook: a #GtkNotebook
7423  * @child: the child widget
7424  * @menu_text: the label text
7425  * 
7426  * Creates a new label and sets it as the menu label of @child.
7427  **/
7428 void
7429 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7430                                   GtkWidget   *child,
7431                                   const gchar *menu_text)
7432 {
7433   GtkWidget *menu_label = NULL;
7434
7435   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7436
7437   if (menu_text)
7438     {
7439       menu_label = gtk_label_new (menu_text);
7440       gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7441     }
7442   gtk_notebook_set_menu_label (notebook, child, menu_label);
7443   gtk_widget_child_notify (child, "menu-label");
7444 }
7445
7446 /**
7447  * gtk_notebook_get_menu_label_text:
7448  * @notebook: a #GtkNotebook
7449  * @child: the child widget of a page of the notebook.
7450  *
7451  * Retrieves the text of the menu label for the page containing
7452  *    @child.
7453  *
7454  * Return value: the text of the tab label, or %NULL if the
7455  *               widget does not have a menu label other than
7456  *               the default menu label, or the menu label widget
7457  *               is not a #GtkLabel. The string is owned by
7458  *               the widget and must not be freed.
7459  **/
7460 G_CONST_RETURN gchar *
7461 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7462                                   GtkWidget *child)
7463 {
7464   GtkWidget *menu_label;
7465
7466   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7467   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7468  
7469   menu_label = gtk_notebook_get_menu_label (notebook, child);
7470
7471   if (GTK_IS_LABEL (menu_label))
7472     return gtk_label_get_text (GTK_LABEL (menu_label));
7473   else
7474     return NULL;
7475 }
7476   
7477 /* Helper function called when pages are reordered
7478  */
7479 static void
7480 gtk_notebook_child_reordered (GtkNotebook     *notebook,
7481                               GtkNotebookPage *page)
7482 {
7483   if (notebook->menu)
7484     {
7485       GtkWidget *menu_item;
7486       
7487       menu_item = page->menu_label->parent;
7488       gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7489       gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7490       gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7491     }
7492
7493   gtk_notebook_update_tab_states (notebook);
7494   gtk_notebook_update_labels (notebook);
7495 }
7496
7497 /**
7498  * gtk_notebook_set_tab_label_packing:
7499  * @notebook: a #GtkNotebook
7500  * @child: the child widget
7501  * @expand: whether to expand the bookmark or not
7502  * @fill: whether the bookmark should fill the allocated area or not
7503  * @pack_type: the position of the bookmark
7504  *
7505  * Sets the packing parameters for the tab label of the page
7506  * containing @child. See gtk_box_pack_start() for the exact meaning
7507  * of the parameters.
7508  *
7509  * Deprecated: 2.20: Modify the #GtkNotebook:tab-expand and
7510  *   #GtkNotebook:tab-fill child properties instead.
7511  **/
7512 void
7513 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7514                                     GtkWidget   *child,
7515                                     gboolean     expand,
7516                                     gboolean     fill,
7517                                     GtkPackType  pack_type)
7518 {
7519   GtkNotebookPage *page;
7520   GList *list;
7521
7522   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7523   g_return_if_fail (GTK_IS_WIDGET (child));
7524
7525   list = CHECK_FIND_CHILD (notebook, child);
7526   if (!list)  
7527     return;
7528
7529   page = list->data;
7530   expand = expand != FALSE;
7531   fill = fill != FALSE;
7532   if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7533     return;
7534
7535   gtk_widget_freeze_child_notify (child);
7536   page->expand = expand;
7537   gtk_widget_child_notify (child, "tab-expand");
7538   page->fill = fill;
7539   gtk_widget_child_notify (child, "tab-fill");
7540   if (page->pack != pack_type)
7541     {
7542       page->pack = pack_type;
7543       gtk_notebook_child_reordered (notebook, page);
7544     }
7545   gtk_widget_child_notify (child, "tab-pack");
7546   gtk_widget_child_notify (child, "position");
7547   if (notebook->show_tabs)
7548     gtk_notebook_pages_allocate (notebook);
7549   gtk_widget_thaw_child_notify (child);
7550 }  
7551
7552 /**
7553  * gtk_notebook_query_tab_label_packing:
7554  * @notebook: a #GtkNotebook
7555  * @child: the page
7556  * @expand: location to store the expand value (or NULL)
7557  * @fill: location to store the fill value (or NULL)
7558  * @pack_type: location to store the pack_type (or NULL)
7559  * 
7560  * Query the packing attributes for the tab label of the page
7561  * containing @child.
7562  *
7563  * Deprecated: 2.20: Modify the #GtkNotebook:tab-expand and
7564  *   #GtkNotebook:tab-fill child properties instead.
7565  **/
7566 void
7567 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7568                                       GtkWidget   *child,
7569                                       gboolean    *expand,
7570                                       gboolean    *fill,
7571                                       GtkPackType *pack_type)
7572 {
7573   GList *list;
7574
7575   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7576   g_return_if_fail (GTK_IS_WIDGET (child));
7577
7578   list = CHECK_FIND_CHILD (notebook, child);
7579   if (!list)
7580     return;
7581
7582   if (expand)
7583     *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7584   if (fill)
7585     *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7586   if (pack_type)
7587     *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7588 }
7589
7590 /**
7591  * gtk_notebook_reorder_child:
7592  * @notebook: a #GtkNotebook
7593  * @child: the child to move
7594  * @position: the new position, or -1 to move to the end
7595  * 
7596  * Reorders the page containing @child, so that it appears in position
7597  * @position. If @position is greater than or equal to the number of
7598  * children in the list or negative, @child will be moved to the end
7599  * of the list.
7600  **/
7601 void
7602 gtk_notebook_reorder_child (GtkNotebook *notebook,
7603                             GtkWidget   *child,
7604                             gint         position)
7605 {
7606   GList *list, *new_list;
7607   GtkNotebookPage *page;
7608   gint old_pos;
7609   gint max_pos;
7610
7611   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7612   g_return_if_fail (GTK_IS_WIDGET (child));
7613
7614   list = CHECK_FIND_CHILD (notebook, child);
7615   if (!list)
7616     return;
7617
7618   max_pos = g_list_length (notebook->children) - 1;
7619   if (position < 0 || position > max_pos)
7620     position = max_pos;
7621
7622   old_pos = g_list_position (notebook->children, list);
7623
7624   if (old_pos == position)
7625     return;
7626
7627   page = list->data;
7628   notebook->children = g_list_delete_link (notebook->children, list);
7629
7630   notebook->children = g_list_insert (notebook->children, page, position);
7631   new_list = g_list_nth (notebook->children, position);
7632
7633   /* Fix up GList references in GtkNotebook structure */
7634   if (notebook->first_tab == list)
7635     notebook->first_tab = new_list;
7636   if (notebook->focus_tab == list)
7637     notebook->focus_tab = new_list;
7638
7639   gtk_widget_freeze_child_notify (child);
7640
7641   /* Move around the menu items if necessary */
7642   gtk_notebook_child_reordered (notebook, page);
7643   gtk_widget_child_notify (child, "tab-pack");
7644   gtk_widget_child_notify (child, "position");
7645
7646   if (notebook->show_tabs)
7647     gtk_notebook_pages_allocate (notebook);
7648
7649   gtk_widget_thaw_child_notify (child);
7650
7651   g_signal_emit (notebook,
7652                  notebook_signals[PAGE_REORDERED],
7653                  0,
7654                  child,
7655                  position);
7656 }
7657
7658 /**
7659  * gtk_notebook_set_window_creation_hook:
7660  * @func: (allow-none): the #GtkNotebookWindowCreationFunc, or %NULL
7661  * @data: user data for @func
7662  * @destroy: (allow-none): Destroy notifier for @data, or %NULL
7663  *
7664  * Installs a global function used to create a window
7665  * when a detached tab is dropped in an empty area.
7666  * 
7667  * Since: 2.10
7668  **/
7669 void
7670 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc  func,
7671                                        gpointer                       data,
7672                                        GDestroyNotify                 destroy)
7673 {
7674   if (window_creation_hook_destroy)
7675     window_creation_hook_destroy (window_creation_hook_data);
7676
7677   window_creation_hook = func;
7678   window_creation_hook_data = data;
7679   window_creation_hook_destroy = destroy;
7680 }
7681
7682 /**
7683  * gtk_notebook_set_group_id:
7684  * @notebook: a #GtkNotebook
7685  * @group_id: a group identificator, or -1 to unset it
7686  *
7687  * Sets an group identificator for @notebook, notebooks sharing
7688  * the same group identificator will be able to exchange tabs
7689  * via drag and drop. A notebook with group identificator -1 will
7690  * not be able to exchange tabs with any other notebook.
7691  * 
7692  * Since: 2.10
7693  * Deprecated: 2.12: use gtk_notebook_set_group() instead.
7694  */
7695 void
7696 gtk_notebook_set_group_id (GtkNotebook *notebook,
7697                            gint         group_id)
7698 {
7699   gpointer group;
7700
7701   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7702
7703   /* add 1 to get rid of the -1/NULL difference */
7704   group = GINT_TO_POINTER (group_id + 1);
7705   gtk_notebook_set_group (notebook, group);
7706 }
7707
7708 /**
7709  * gtk_notebook_set_group:
7710  * @notebook: a #GtkNotebook
7711  * @group: (allow-none): a pointer to identify the notebook group, or %NULL to unset it
7712  *
7713  * Sets a group identificator pointer for @notebook, notebooks sharing
7714  * the same group identificator pointer will be able to exchange tabs
7715  * via drag and drop. A notebook with a %NULL group identificator will
7716  * not be able to exchange tabs with any other notebook.
7717  * 
7718  * Since: 2.12
7719  */
7720 void
7721 gtk_notebook_set_group (GtkNotebook *notebook,
7722                         gpointer     group)
7723 {
7724   GtkNotebookPrivate *priv;
7725
7726   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7727
7728   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7729
7730   if (priv->group != group)
7731     {
7732       priv->group = group;
7733       g_object_notify (G_OBJECT (notebook), "group-id");
7734       g_object_notify (G_OBJECT (notebook), "group");
7735     }
7736 }
7737
7738 /**
7739  * gtk_notebook_get_group_id:
7740  * @notebook: a #GtkNotebook
7741  * 
7742  * Gets the current group identificator for @notebook.
7743  * 
7744  * Return Value: the group identificator, or -1 if none is set.
7745  *
7746  * Since: 2.10
7747  * Deprecated: 2.12: use gtk_notebook_get_group() instead.
7748  */
7749 gint
7750 gtk_notebook_get_group_id (GtkNotebook *notebook)
7751 {
7752   GtkNotebookPrivate *priv;
7753
7754   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7755
7756   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7757
7758   /* substract 1 to get rid of the -1/NULL difference */
7759   return GPOINTER_TO_INT (priv->group) - 1;
7760 }
7761
7762 /**
7763  * gtk_notebook_get_group:
7764  * @notebook: a #GtkNotebook
7765  * 
7766  * Gets the current group identificator pointer for @notebook.
7767  * 
7768  * Return Value: the group identificator, or %NULL if none is set.
7769  *
7770  * Since: 2.12
7771  **/
7772 gpointer
7773 gtk_notebook_get_group (GtkNotebook *notebook)
7774 {
7775   GtkNotebookPrivate *priv;
7776
7777   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7778
7779   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7780   return priv->group;
7781 }
7782
7783 /**
7784  * gtk_notebook_get_tab_reorderable:
7785  * @notebook: a #GtkNotebook
7786  * @child: a child #GtkWidget
7787  * 
7788  * Gets whether the tab can be reordered via drag and drop or not.
7789  * 
7790  * Return Value: %TRUE if the tab is reorderable.
7791  * 
7792  * Since: 2.10
7793  **/
7794 gboolean
7795 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7796                                   GtkWidget   *child)
7797 {
7798   GList *list;
7799
7800   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7801   g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7802
7803   list = CHECK_FIND_CHILD (notebook, child);
7804   if (!list)  
7805     return FALSE;
7806
7807   return GTK_NOTEBOOK_PAGE (list)->reorderable;
7808 }
7809
7810 /**
7811  * gtk_notebook_set_tab_reorderable:
7812  * @notebook: a #GtkNotebook
7813  * @child: a child #GtkWidget
7814  * @reorderable: whether the tab is reorderable or not.
7815  *
7816  * Sets whether the notebook tab can be reordered
7817  * via drag and drop or not.
7818  * 
7819  * Since: 2.10
7820  **/
7821 void
7822 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7823                                   GtkWidget   *child,
7824                                   gboolean     reorderable)
7825 {
7826   GList *list;
7827
7828   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7829   g_return_if_fail (GTK_IS_WIDGET (child));
7830
7831   list = CHECK_FIND_CHILD (notebook, child);
7832   if (!list)  
7833     return;
7834
7835   if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7836     {
7837       GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7838       gtk_widget_child_notify (child, "reorderable");
7839     }
7840 }
7841
7842 /**
7843  * gtk_notebook_get_tab_detachable:
7844  * @notebook: a #GtkNotebook
7845  * @child: a child #GtkWidget
7846  * 
7847  * Returns whether the tab contents can be detached from @notebook.
7848  * 
7849  * Return Value: TRUE if the tab is detachable.
7850  *
7851  * Since: 2.10
7852  **/
7853 gboolean
7854 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7855                                  GtkWidget   *child)
7856 {
7857   GList *list;
7858
7859   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7860   g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7861
7862   list = CHECK_FIND_CHILD (notebook, child);
7863   if (!list)  
7864     return FALSE;
7865
7866   return GTK_NOTEBOOK_PAGE (list)->detachable;
7867 }
7868
7869 /**
7870  * gtk_notebook_set_tab_detachable:
7871  * @notebook: a #GtkNotebook
7872  * @child: a child #GtkWidget
7873  * @detachable: whether the tab is detachable or not
7874  *
7875  * Sets whether the tab can be detached from @notebook to another
7876  * notebook or widget.
7877  *
7878  * Note that 2 notebooks must share a common group identificator
7879  * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7880  * interchange between them.
7881  *
7882  * If you want a widget to interact with a notebook through DnD
7883  * (i.e.: accept dragged tabs from it) it must be set as a drop
7884  * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7885  * will fill the selection with a GtkWidget** pointing to the child
7886  * widget that corresponds to the dropped tab.
7887  * |[
7888  *  static void
7889  *  on_drop_zone_drag_data_received (GtkWidget        *widget,
7890  *                                   GdkDragContext   *context,
7891  *                                   gint              x,
7892  *                                   gint              y,
7893  *                                   GtkSelectionData *selection_data,
7894  *                                   guint             info,
7895  *                                   guint             time,
7896  *                                   gpointer          user_data)
7897  *  {
7898  *    GtkWidget *notebook;
7899  *    GtkWidget **child;
7900  *    
7901  *    notebook = gtk_drag_get_source_widget (context);
7902  *    child = (void*) selection_data->data;
7903  *    
7904  *    process_widget (*child);
7905  *    gtk_container_remove (GTK_CONTAINER (notebook), *child);
7906  *  }
7907  * ]|
7908  *
7909  * If you want a notebook to accept drags from other widgets,
7910  * you will have to set your own DnD code to do it.
7911  *
7912  * Since: 2.10
7913  **/
7914 void
7915 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7916                                  GtkWidget  *child,
7917                                  gboolean    detachable)
7918 {
7919   GList *list;
7920
7921   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7922   g_return_if_fail (GTK_IS_WIDGET (child));
7923
7924   list = CHECK_FIND_CHILD (notebook, child);
7925   if (!list)  
7926     return;
7927
7928   if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7929     {
7930       GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7931       gtk_widget_child_notify (child, "detachable");
7932     }
7933 }
7934
7935 /**
7936  * gtk_notebook_get_action_widget:
7937  * @notebook: a #GtkNotebook
7938  * @pack_type: pack type of the action widget to receive
7939  *
7940  * Gets one of the action widgets. See gtk_notebook_set_action_widget().
7941  *
7942  * Returns: The action widget with the given @pack_type or
7943  *     %NULL when this action widget has not been set
7944  *
7945  * Since: 2.20
7946  */
7947 GtkWidget*
7948 gtk_notebook_get_action_widget (GtkNotebook *notebook,
7949                                 GtkPackType  pack_type)
7950 {
7951   GtkNotebookPrivate *priv;
7952
7953   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7954
7955   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7956   return priv->action_widget[pack_type];
7957 }
7958
7959 /**
7960  * gtk_notebook_set_action_widget:
7961  * @notebook: a #GtkNotebook
7962  * @widget: a #GtkWidget
7963  * @pack_type: pack type of the action widget
7964  *
7965  * Sets @widget as one of the action widgets. Depending on the pack type
7966  * the widget will be placed before or after the tabs. You can use
7967  * a #GtkBox if you need to pack more than one widget on the same side.
7968  *
7969  * Note that action widgets are "internal" children of the notebook and thus
7970  * not included in the list returned from gtk_container_foreach().
7971  *
7972  * Since: 2.20
7973  */
7974 void
7975 gtk_notebook_set_action_widget (GtkNotebook *notebook,
7976                                 GtkWidget   *widget,
7977                                 GtkPackType  pack_type)
7978 {
7979   GtkNotebookPrivate *priv;
7980
7981   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7982   g_return_if_fail (!widget || GTK_IS_WIDGET (widget));
7983   g_return_if_fail (!widget || widget->parent == NULL);
7984
7985   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7986
7987   if (priv->action_widget[pack_type])
7988     gtk_widget_unparent (priv->action_widget[pack_type]);
7989
7990   priv->action_widget[pack_type] = widget;
7991
7992   if (widget)
7993     {
7994       gtk_widget_set_child_visible (widget, notebook->show_tabs);
7995       gtk_widget_set_parent (widget, GTK_WIDGET (notebook));
7996     }
7997
7998   gtk_widget_queue_resize (GTK_WIDGET (notebook));
7999 }
8000
8001 #define __GTK_NOTEBOOK_C__
8002 #include "gtkaliasdef.c"