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