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