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