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