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