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