]> Pileus Git - ~andy/gtk/blob - gtk/gtknotebook.c
Do not call gtk_widget_set_parent_window(), using widget->window instead
[~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_PREV, TRUE);
4327   if (!next_list)
4328     next_list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
4329
4330   if (notebook->cur_page == list->data)
4331     { 
4332       notebook->cur_page = NULL;
4333       if (next_list && !destroying)
4334         gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (next_list));
4335     }
4336
4337   if (priv->detached_tab == list->data)
4338     priv->detached_tab = NULL;
4339
4340   if (list == notebook->first_tab)
4341     notebook->first_tab = next_list;
4342   if (list == notebook->focus_tab && !destroying)
4343     gtk_notebook_switch_focus_tab (notebook, next_list);
4344
4345   page = list->data;
4346   
4347   g_signal_handler_disconnect (page->child, page->notify_visible_handler); 
4348
4349   if (GTK_WIDGET_VISIBLE (page->child) && GTK_WIDGET_VISIBLE (notebook))
4350     need_resize = TRUE;
4351
4352   gtk_widget_unparent (page->child);
4353
4354   tab_label = page->tab_label;
4355   if (tab_label)
4356     {
4357       g_object_ref (tab_label);
4358       gtk_notebook_remove_tab_label (notebook, page);
4359       if (destroying)
4360         gtk_widget_destroy (tab_label);
4361       g_object_unref (tab_label);
4362     } 
4363
4364   if (notebook->menu)
4365     {
4366       gtk_container_remove (GTK_CONTAINER (notebook->menu), 
4367                             page->menu_label->parent);
4368       gtk_widget_queue_resize (notebook->menu);
4369     }
4370   if (!page->default_menu)
4371     g_object_unref (page->menu_label);
4372   
4373   notebook->children = g_list_remove_link (notebook->children, list);
4374   g_list_free (list);
4375
4376   if (page->last_focus_child)
4377     {
4378       g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
4379       page->last_focus_child = NULL;
4380     }
4381   
4382   g_free (page);
4383
4384   gtk_notebook_update_labels (notebook);
4385   if (need_resize)
4386     gtk_widget_queue_resize (GTK_WIDGET (notebook));
4387 }
4388
4389 static void
4390 gtk_notebook_update_labels (GtkNotebook *notebook)
4391 {
4392   GtkNotebookPage *page;
4393   GList *list;
4394   gchar string[32];
4395   gint page_num = 1;
4396
4397   if (!notebook->show_tabs && !notebook->menu)
4398     return;
4399
4400   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
4401        list;
4402        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
4403     {
4404       page = list->data;
4405       g_snprintf (string, sizeof(string), _("Page %u"), page_num++);
4406       if (notebook->show_tabs)
4407         {
4408           if (page->default_tab)
4409             {
4410               if (!page->tab_label)
4411                 {
4412                   page->tab_label = gtk_label_new (string);
4413                   gtk_widget_set_parent (page->tab_label,
4414                                          GTK_WIDGET (notebook));
4415                 }
4416               else
4417                 gtk_label_set_text (GTK_LABEL (page->tab_label), string);
4418             }
4419
4420           if (GTK_WIDGET_VISIBLE (page->child) &&
4421               !GTK_WIDGET_VISIBLE (page->tab_label))
4422             gtk_widget_show (page->tab_label);
4423           else if (!GTK_WIDGET_VISIBLE (page->child) &&
4424                    GTK_WIDGET_VISIBLE (page->tab_label))
4425             gtk_widget_hide (page->tab_label);
4426         }
4427       if (notebook->menu && page->default_menu)
4428         {
4429           if (GTK_IS_LABEL (page->tab_label))
4430             gtk_label_set_text (GTK_LABEL (page->menu_label),
4431                                 GTK_LABEL (page->tab_label)->label);
4432           else
4433             gtk_label_set_text (GTK_LABEL (page->menu_label), string);
4434         }
4435     }  
4436 }
4437
4438 static gint
4439 gtk_notebook_real_page_position (GtkNotebook *notebook,
4440                                  GList       *list)
4441 {
4442   GList *work;
4443   gint count_start;
4444
4445   for (work = notebook->children, count_start = 0;
4446        work && work != list; work = work->next)
4447     if (GTK_NOTEBOOK_PAGE (work)->pack == GTK_PACK_START)
4448       count_start++;
4449
4450   if (!work)
4451     return -1;
4452
4453   if (GTK_NOTEBOOK_PAGE (list)->pack == GTK_PACK_START)
4454     return count_start;
4455
4456   return (count_start + g_list_length (list) - 1);
4457 }
4458
4459 static GList *
4460 gtk_notebook_search_page (GtkNotebook *notebook,
4461                           GList       *list,
4462                           gint         direction,
4463                           gboolean     find_visible)
4464 {
4465   GtkNotebookPage *page = NULL;
4466   GList *old_list = NULL;
4467   gint flag = 0;
4468
4469   switch (direction)
4470     {
4471     case STEP_PREV:
4472       flag = GTK_PACK_END;
4473       break;
4474
4475     case STEP_NEXT:
4476       flag = GTK_PACK_START;
4477       break;
4478     }
4479
4480   if (list)
4481     page = list->data;
4482
4483   if (!page || page->pack == flag)
4484     {
4485       if (list)
4486         {
4487           old_list = list;
4488           list = list->next;
4489         }
4490       else
4491         list = notebook->children;
4492
4493       while (list)
4494         {
4495           page = list->data;
4496           if (page->pack == flag &&
4497               (!find_visible ||
4498                (GTK_WIDGET_VISIBLE (page->child) &&
4499                 (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4500             return list;
4501           old_list = list;
4502           list = list->next;
4503         }
4504       list = old_list;
4505     }
4506   else
4507     {
4508       old_list = list;
4509       list = list->prev;
4510     }
4511   while (list)
4512     {
4513       page = list->data;
4514       if (page->pack != flag &&
4515           (!find_visible ||
4516            (GTK_WIDGET_VISIBLE (page->child) &&
4517             (!page->tab_label || NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page)))))
4518         return list;
4519       old_list = list;
4520       list = list->prev;
4521     }
4522   return NULL;
4523 }
4524
4525 /* Private GtkNotebook Drawing Functions:
4526  *
4527  * gtk_notebook_paint
4528  * gtk_notebook_draw_tab
4529  * gtk_notebook_draw_arrow
4530  */
4531 static void
4532 gtk_notebook_paint (GtkWidget    *widget,
4533                     GdkRectangle *area)
4534 {
4535   GtkNotebook *notebook;
4536   GtkNotebookPrivate *priv;
4537   GtkNotebookPage *page;
4538   GList *children;
4539   gboolean showarrow;
4540   gint width, height;
4541   gint x, y;
4542   gint border_width = GTK_CONTAINER (widget)->border_width;
4543   gint gap_x = 0, gap_width = 0, step = STEP_PREV;
4544   gboolean is_rtl;
4545   gint tab_pos;
4546    
4547   if (!GTK_WIDGET_DRAWABLE (widget))
4548     return;
4549
4550   notebook = GTK_NOTEBOOK (widget);
4551   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4552   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4553   tab_pos = get_effective_tab_pos (notebook);
4554
4555   if ((!notebook->show_tabs && !notebook->show_border) ||
4556       !notebook->cur_page || !GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4557     return;
4558
4559   x = widget->allocation.x + border_width;
4560   y = widget->allocation.y + border_width;
4561   width = widget->allocation.width - border_width * 2;
4562   height = widget->allocation.height - border_width * 2;
4563
4564   if (notebook->show_border && (!notebook->show_tabs || !notebook->children))
4565     {
4566       gtk_paint_box (widget->style, widget->window,
4567                      GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4568                      area, widget, "notebook",
4569                      x, y, width, height);
4570       return;
4571     }
4572
4573   if (!notebook->first_tab)
4574     notebook->first_tab = notebook->children;
4575
4576   if (!GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4577     page = GTK_NOTEBOOK_PAGE (notebook->first_tab);
4578   else
4579     page = notebook->cur_page;
4580
4581   switch (tab_pos)
4582     {
4583     case GTK_POS_TOP:
4584       y += page->allocation.height;
4585       /* fall thru */
4586     case GTK_POS_BOTTOM:
4587       height -= page->allocation.height;
4588       break;
4589     case GTK_POS_LEFT:
4590       x += page->allocation.width;
4591       /* fall thru */
4592     case GTK_POS_RIGHT:
4593       width -= page->allocation.width;
4594       break;
4595     }
4596
4597   if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) ||
4598       !GTK_WIDGET_MAPPED (notebook->cur_page->tab_label))
4599     {
4600       gap_x = 0;
4601       gap_width = 0;
4602     }
4603   else
4604     {
4605       switch (tab_pos)
4606         {
4607         case GTK_POS_TOP:
4608         case GTK_POS_BOTTOM:
4609           if (priv->operation == DRAG_OPERATION_REORDER)
4610             gap_x = priv->drag_window_x - widget->allocation.x - border_width;
4611           else
4612             gap_x = notebook->cur_page->allocation.x - widget->allocation.x - border_width;
4613
4614           gap_width = notebook->cur_page->allocation.width;
4615           step = is_rtl ? STEP_NEXT : STEP_PREV;
4616           break;
4617         case GTK_POS_LEFT:
4618         case GTK_POS_RIGHT:
4619           if (priv->operation == DRAG_OPERATION_REORDER)
4620             gap_x = priv->drag_window_y - border_width - widget->allocation.y;
4621           else
4622             gap_x = notebook->cur_page->allocation.y - widget->allocation.y - border_width;
4623
4624           gap_width = notebook->cur_page->allocation.height;
4625           step = STEP_PREV;
4626           break;
4627         }
4628     }
4629   gtk_paint_box_gap (widget->style, widget->window,
4630                      GTK_STATE_NORMAL, GTK_SHADOW_OUT,
4631                      area, widget, "notebook",
4632                      x, y, width, height,
4633                      tab_pos, gap_x, gap_width);
4634
4635   showarrow = FALSE;
4636   children = gtk_notebook_search_page (notebook, NULL, step, TRUE);
4637   while (children)
4638     {
4639       page = children->data;
4640       children = gtk_notebook_search_page (notebook, children,
4641                                            step, TRUE);
4642       if (!GTK_WIDGET_VISIBLE (page->child))
4643         continue;
4644       if (!GTK_WIDGET_MAPPED (page->tab_label))
4645         showarrow = TRUE;
4646       else if (page != notebook->cur_page)
4647         gtk_notebook_draw_tab (notebook, page, area);
4648     }
4649
4650   if (showarrow && notebook->scrollable) 
4651     {
4652       if (notebook->has_before_previous)
4653         gtk_notebook_draw_arrow (notebook, ARROW_LEFT_BEFORE);
4654       if (notebook->has_before_next)
4655         gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_BEFORE);
4656       if (notebook->has_after_previous)
4657         gtk_notebook_draw_arrow (notebook, ARROW_LEFT_AFTER);
4658       if (notebook->has_after_next)
4659         gtk_notebook_draw_arrow (notebook, ARROW_RIGHT_AFTER);
4660     }
4661   gtk_notebook_draw_tab (notebook, notebook->cur_page, area);
4662 }
4663
4664 static void
4665 gtk_notebook_draw_tab (GtkNotebook     *notebook,
4666                        GtkNotebookPage *page,
4667                        GdkRectangle    *area)
4668 {
4669   GtkNotebookPrivate *priv;
4670   GdkRectangle child_area;
4671   GdkRectangle page_area;
4672   GtkStateType state_type;
4673   GtkPositionType gap_side;
4674   GdkWindow *window;
4675   GtkWidget *widget;
4676   
4677   if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
4678       !GTK_WIDGET_MAPPED (page->tab_label) ||
4679       (page->allocation.width == 0) || (page->allocation.height == 0))
4680     return;
4681
4682   widget = GTK_WIDGET (notebook);
4683   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4684
4685   if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
4686     window = priv->drag_window;
4687   else
4688     window = widget->window;
4689
4690   page_area.x = page->allocation.x;
4691   page_area.y = page->allocation.y;
4692   page_area.width = page->allocation.width;
4693   page_area.height = page->allocation.height;
4694
4695   if (gdk_rectangle_intersect (&page_area, area, &child_area))
4696     {
4697       gap_side = get_tab_gap_pos (notebook);
4698
4699       if (notebook->cur_page == page)
4700         state_type = GTK_STATE_NORMAL;
4701       else 
4702         state_type = GTK_STATE_ACTIVE;
4703
4704       gtk_paint_extension (widget->style, window,
4705                            state_type, GTK_SHADOW_OUT,
4706                            area, widget, "tab",
4707                            page_area.x, page_area.y,
4708                            page_area.width, page_area.height,
4709                            gap_side);
4710     }
4711 }
4712
4713 static void
4714 gtk_notebook_draw_arrow (GtkNotebook      *notebook,
4715                          GtkNotebookArrow  nbarrow)
4716 {
4717   GtkStateType state_type;
4718   GtkShadowType shadow_type;
4719   GtkWidget *widget;
4720   GdkRectangle arrow_rect;
4721   GtkArrowType arrow;
4722   gboolean is_rtl, left;
4723
4724   if (GTK_WIDGET_DRAWABLE (notebook))
4725     {
4726       gint scroll_arrow_hlength;
4727       gint scroll_arrow_vlength;
4728       gint arrow_size;
4729
4730       gtk_notebook_get_arrow_rect (notebook, &arrow_rect, nbarrow);
4731
4732       widget = GTK_WIDGET (notebook);
4733
4734       is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
4735       left = (ARROW_IS_LEFT (nbarrow) && !is_rtl) ||
4736              (!ARROW_IS_LEFT (nbarrow) && is_rtl); 
4737
4738       gtk_widget_style_get (widget,
4739                             "scroll-arrow-hlength", &scroll_arrow_hlength,
4740                             "scroll-arrow-vlength", &scroll_arrow_vlength,
4741                             NULL);
4742
4743       if (notebook->in_child == nbarrow)
4744         {
4745           if (notebook->click_child == nbarrow)
4746             state_type = GTK_STATE_ACTIVE;
4747           else
4748             state_type = GTK_STATE_PRELIGHT;
4749         }
4750       else
4751         state_type = GTK_WIDGET_STATE (widget);
4752
4753       if (notebook->click_child == nbarrow)
4754         shadow_type = GTK_SHADOW_IN;
4755       else
4756         shadow_type = GTK_SHADOW_OUT;
4757
4758       if (notebook->focus_tab &&
4759           !gtk_notebook_search_page (notebook, notebook->focus_tab,
4760                                      left ? STEP_PREV : STEP_NEXT, TRUE))
4761         {
4762           shadow_type = GTK_SHADOW_ETCHED_IN;
4763           state_type = GTK_STATE_INSENSITIVE;
4764         }
4765       
4766       if (notebook->tab_pos == GTK_POS_LEFT ||
4767           notebook->tab_pos == GTK_POS_RIGHT)
4768         {
4769           arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_UP : GTK_ARROW_DOWN);
4770           arrow_size = scroll_arrow_vlength;
4771         }
4772       else
4773         {
4774           arrow = (ARROW_IS_LEFT (nbarrow) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT);
4775           arrow_size = scroll_arrow_hlength;
4776         }
4777      
4778       gtk_paint_arrow (widget->style, widget->window, state_type, 
4779                        shadow_type, NULL, widget, "notebook",
4780                        arrow, TRUE, arrow_rect.x, arrow_rect.y, 
4781                        arrow_size, arrow_size);
4782     }
4783 }
4784
4785 /* Private GtkNotebook Size Allocate Functions:
4786  *
4787  * gtk_notebook_tab_space
4788  * gtk_notebook_calculate_shown_tabs
4789  * gtk_notebook_calculate_tabs_allocation
4790  * gtk_notebook_pages_allocate
4791  * gtk_notebook_page_allocate
4792  * gtk_notebook_calc_tabs
4793  */
4794 static void
4795 gtk_notebook_tab_space (GtkNotebook *notebook,
4796                         gboolean    *show_arrows,
4797                         gint        *min,
4798                         gint        *max,
4799                         gint        *tab_space)
4800 {
4801   GtkNotebookPrivate *priv;
4802   GtkWidget *widget;
4803   GList *children;
4804   gint tab_pos = get_effective_tab_pos (notebook);
4805   gint tab_overlap;
4806   gint arrow_spacing;
4807   gint scroll_arrow_hlength;
4808   gint scroll_arrow_vlength;
4809
4810   widget = GTK_WIDGET (notebook);
4811   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
4812   children = notebook->children;
4813
4814   gtk_widget_style_get (GTK_WIDGET (notebook),
4815                         "arrow-spacing", &arrow_spacing,
4816                         "scroll-arrow-hlength", &scroll_arrow_hlength,
4817                         "scroll-arrow-vlength", &scroll_arrow_vlength,
4818                         NULL);
4819
4820   switch (tab_pos)
4821     {
4822     case GTK_POS_TOP:
4823     case GTK_POS_BOTTOM:
4824       *min = widget->allocation.x + GTK_CONTAINER (notebook)->border_width;
4825       *max = widget->allocation.x + widget->allocation.width - GTK_CONTAINER (notebook)->border_width;
4826
4827       while (children)
4828         {
4829           GtkNotebookPage *page;
4830
4831           page = children->data;
4832           children = children->next;
4833
4834           if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4835               GTK_WIDGET_VISIBLE (page->child))
4836             *tab_space += page->requisition.width;
4837         }
4838       break;
4839     case GTK_POS_RIGHT:
4840     case GTK_POS_LEFT:
4841       *min = widget->allocation.y + GTK_CONTAINER (notebook)->border_width;
4842       *max = widget->allocation.y + widget->allocation.height - GTK_CONTAINER (notebook)->border_width;
4843
4844       while (children)
4845         {
4846           GtkNotebookPage *page;
4847
4848           page = children->data;
4849           children = children->next;
4850
4851           if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4852               GTK_WIDGET_VISIBLE (page->child))
4853             *tab_space += page->requisition.height;
4854         }
4855       break;
4856     }
4857
4858   if (!notebook->scrollable)
4859     *show_arrows = FALSE;
4860   else
4861     {
4862       gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4863
4864       switch (tab_pos)
4865         {
4866         case GTK_POS_TOP:
4867         case GTK_POS_BOTTOM:
4868           if (*tab_space > *max - *min - tab_overlap)
4869             {
4870               *show_arrows = TRUE;
4871
4872               /* take arrows into account */
4873               *tab_space = widget->allocation.width - tab_overlap -
4874                 2 * GTK_CONTAINER (notebook)->border_width;
4875
4876               if (notebook->has_after_previous)
4877                 {
4878                   *tab_space -= arrow_spacing + scroll_arrow_hlength;
4879                   *max -= arrow_spacing + scroll_arrow_hlength;
4880                 }
4881
4882               if (notebook->has_after_next)
4883                 {
4884                   *tab_space -= arrow_spacing + scroll_arrow_hlength;
4885                   *max -= arrow_spacing + scroll_arrow_hlength;
4886                 }
4887
4888               if (notebook->has_before_previous)
4889                 {
4890                   *tab_space -= arrow_spacing + scroll_arrow_hlength;
4891                   *min += arrow_spacing + scroll_arrow_hlength;
4892                 }
4893
4894               if (notebook->has_before_next)
4895                 {
4896                   *tab_space -= arrow_spacing + scroll_arrow_hlength;
4897                   *min += arrow_spacing + scroll_arrow_hlength;
4898                 }
4899             }
4900           break;
4901         case GTK_POS_LEFT:
4902         case GTK_POS_RIGHT:
4903           if (*tab_space > *max - *min - tab_overlap)
4904             {
4905               *show_arrows = TRUE;
4906
4907               /* take arrows into account */
4908               *tab_space = widget->allocation.height -
4909                 tab_overlap - 2 * GTK_CONTAINER (notebook)->border_width;
4910
4911               if (notebook->has_after_previous || notebook->has_after_next)
4912                 {
4913                   *tab_space -= arrow_spacing + scroll_arrow_vlength;
4914                   *max -= arrow_spacing + scroll_arrow_vlength;
4915                 }
4916
4917               if (notebook->has_before_previous || notebook->has_before_next)
4918                 {
4919                   *tab_space -= arrow_spacing + scroll_arrow_vlength;
4920                   *min += arrow_spacing + scroll_arrow_vlength;
4921                 }
4922             }
4923           break;
4924         }
4925     }
4926 }
4927
4928 static void
4929 gtk_notebook_calculate_shown_tabs (GtkNotebook *notebook,
4930                                    gboolean     show_arrows,
4931                                    gint         min,
4932                                    gint         max,
4933                                    gint         tab_space,
4934                                    GList      **last_child,
4935                                    gint        *n,
4936                                    gint        *remaining_space)
4937 {
4938   GtkWidget *widget;
4939   GtkContainer *container;
4940   GList *children;
4941   GtkNotebookPage *page;
4942   gint tab_pos, tab_overlap;
4943   
4944   widget = GTK_WIDGET (notebook);
4945   container = GTK_CONTAINER (notebook);
4946   gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
4947   tab_pos = get_effective_tab_pos (notebook);
4948
4949   if (show_arrows) /* first_tab <- focus_tab */
4950     {
4951       *remaining_space = tab_space;
4952
4953       if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page) &&
4954           GTK_WIDGET_VISIBLE (notebook->cur_page->child))
4955         {
4956           gtk_notebook_calc_tabs (notebook,
4957                                   notebook->focus_tab,
4958                                   &(notebook->focus_tab),
4959                                   remaining_space, STEP_NEXT);
4960         }
4961
4962       if (*remaining_space <= 0)
4963         {
4964           /* show 1 tab */
4965           notebook->first_tab = notebook->focus_tab;
4966           *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
4967                                                   STEP_NEXT, TRUE);
4968         }
4969       else
4970         {
4971           children = NULL;
4972
4973           if (notebook->first_tab && notebook->first_tab != notebook->focus_tab)
4974             {
4975               /* Is first_tab really predecessor of focus_tab? */
4976               page = notebook->first_tab->data;
4977               if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
4978                   GTK_WIDGET_VISIBLE (page->child))
4979                 for (children = notebook->focus_tab;
4980                      children && children != notebook->first_tab;
4981                      children = gtk_notebook_search_page (notebook,
4982                                                           children,
4983                                                           STEP_PREV,
4984                                                           TRUE));
4985             }
4986
4987           if (!children)
4988             {
4989               if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, notebook->cur_page))
4990                 notebook->first_tab = notebook->focus_tab;
4991               else
4992                 notebook->first_tab = gtk_notebook_search_page (notebook, notebook->focus_tab,
4993                                                                 STEP_NEXT, TRUE);
4994             }
4995           else
4996             /* calculate shown tabs counting backwards from the focus tab */
4997             gtk_notebook_calc_tabs (notebook,
4998                                     gtk_notebook_search_page (notebook,
4999                                                               notebook->focus_tab,
5000                                                               STEP_PREV,
5001                                                               TRUE),
5002                                     &(notebook->first_tab), remaining_space,
5003                                     STEP_PREV);
5004
5005           if (*remaining_space < 0)
5006             {
5007               notebook->first_tab =
5008                 gtk_notebook_search_page (notebook, notebook->first_tab,
5009                                           STEP_NEXT, TRUE);
5010               if (!notebook->first_tab)
5011                 notebook->first_tab = notebook->focus_tab;
5012
5013               *last_child = gtk_notebook_search_page (notebook, notebook->focus_tab,
5014                                                       STEP_NEXT, TRUE); 
5015             }
5016           else /* focus_tab -> end */   
5017             {
5018               if (!notebook->first_tab)
5019                 notebook->first_tab = gtk_notebook_search_page (notebook,
5020                                                                 NULL,
5021                                                                 STEP_NEXT,
5022                                                                 TRUE);
5023               children = NULL;
5024               gtk_notebook_calc_tabs (notebook,
5025                                       gtk_notebook_search_page (notebook,
5026                                                                 notebook->focus_tab,
5027                                                                 STEP_NEXT,
5028                                                                 TRUE),
5029                                       &children, remaining_space, STEP_NEXT);
5030
5031               if (*remaining_space <= 0) 
5032                 *last_child = children;
5033               else /* start <- first_tab */
5034                 {
5035                   *last_child = NULL;
5036                   children = NULL;
5037
5038                   gtk_notebook_calc_tabs (notebook,
5039                                           gtk_notebook_search_page (notebook,
5040                                                                     notebook->first_tab,
5041                                                                     STEP_PREV,
5042                                                                     TRUE),
5043                                           &children, remaining_space, STEP_PREV);
5044
5045                   if (*remaining_space == 0)
5046                     notebook->first_tab = children;
5047                   else
5048                     notebook->first_tab = gtk_notebook_search_page(notebook,
5049                                                                    children,
5050                                                                    STEP_NEXT,
5051                                                                    TRUE);
5052                 }
5053             }
5054         }
5055
5056       if (*remaining_space < 0) 
5057         {
5058           /* calculate number of tabs */
5059           *remaining_space = - (*remaining_space);
5060           *n = 0;
5061
5062           for (children = notebook->first_tab;
5063                children && children != *last_child;
5064                children = gtk_notebook_search_page (notebook, children,
5065                                                     STEP_NEXT, TRUE))
5066             (*n)++;
5067         }
5068       else 
5069         *remaining_space = 0;
5070
5071       /* unmap all non-visible tabs */
5072       for (children = gtk_notebook_search_page (notebook, NULL,
5073                                                 STEP_NEXT, TRUE);
5074            children && children != notebook->first_tab;
5075            children = gtk_notebook_search_page (notebook, children,
5076                                                 STEP_NEXT, TRUE))
5077         {
5078           page = children->data;
5079
5080           if (page->tab_label &&
5081               NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5082             gtk_widget_set_child_visible (page->tab_label, FALSE);
5083         }
5084
5085       for (children = *last_child; children;
5086            children = gtk_notebook_search_page (notebook, children,
5087                                                 STEP_NEXT, TRUE))
5088         {
5089           page = children->data;
5090
5091           if (page->tab_label &&
5092               NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5093             gtk_widget_set_child_visible (page->tab_label, FALSE);
5094         }
5095     }
5096   else /* !show_arrows */
5097     {
5098       gint c = 0;
5099       *n = 0;
5100
5101       *remaining_space = max - min - tab_overlap - tab_space;
5102       children = notebook->children;
5103       notebook->first_tab = gtk_notebook_search_page (notebook, NULL,
5104                                                       STEP_NEXT, TRUE);
5105       while (children)
5106         {
5107           page = children->data;
5108           children = children->next;
5109
5110           if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) ||
5111               !GTK_WIDGET_VISIBLE (page->child))
5112             continue;
5113
5114           c++;
5115
5116           if (page->expand)
5117             (*n)++;
5118         }
5119
5120       /* if notebook is homogeneous, all tabs are expanded */
5121       if (notebook->homogeneous && *n)
5122         *n = c;
5123     }
5124 }
5125
5126 static gboolean
5127 get_allocate_at_bottom (GtkWidget *widget,
5128                         gint       search_direction)
5129 {
5130   gboolean is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
5131   gboolean tab_pos = get_effective_tab_pos (GTK_NOTEBOOK (widget));
5132
5133   switch (tab_pos)
5134     {
5135     case GTK_POS_TOP:
5136     case GTK_POS_BOTTOM:
5137       if (!is_rtl)
5138         return (search_direction == STEP_PREV);
5139       else
5140         return (search_direction == STEP_NEXT);
5141
5142       break;
5143     case GTK_POS_RIGHT:
5144     case GTK_POS_LEFT:
5145       return (search_direction == STEP_PREV);
5146       break;
5147     }
5148
5149   return FALSE;
5150 }
5151
5152 static gboolean
5153 gtk_notebook_calculate_tabs_allocation (GtkNotebook  *notebook,
5154                                         GList       **children,
5155                                         GList        *last_child,
5156                                         gboolean      showarrow,
5157                                         gint          direction,
5158                                         gint         *remaining_space,
5159                                         gint         *expanded_tabs,
5160                                         gint          min,
5161                                         gint          max)
5162 {
5163   GtkWidget *widget;
5164   GtkContainer *container;
5165   GtkNotebookPrivate *priv;
5166   GtkNotebookPage *page;
5167   gboolean allocate_at_bottom;
5168   gint tab_overlap, tab_pos, tab_extra_space;
5169   gint left_x, right_x, top_y, bottom_y, anchor;
5170   gint xthickness, ythickness;
5171   gboolean gap_left, packing_changed;
5172   GtkAllocation child_allocation = { 0, };
5173   gboolean allocation_changed = FALSE;
5174
5175   widget = GTK_WIDGET (notebook);
5176   container = GTK_CONTAINER (notebook);
5177   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
5178   gtk_widget_style_get (widget, "tab-overlap", &tab_overlap, NULL);
5179   tab_pos = get_effective_tab_pos (notebook);
5180   allocate_at_bottom = get_allocate_at_bottom (widget, direction);
5181   anchor = 0;
5182
5183   child_allocation.x = widget->allocation.x + container->border_width;
5184   child_allocation.y = widget->allocation.y + container->border_width;
5185
5186   xthickness = widget->style->xthickness;
5187   ythickness = widget->style->ythickness;
5188
5189   switch (tab_pos)
5190     {
5191     case GTK_POS_BOTTOM:
5192       child_allocation.y = widget->allocation.y + widget->allocation.height -
5193         notebook->cur_page->requisition.height - container->border_width;
5194       /* fall through */
5195     case GTK_POS_TOP:
5196       child_allocation.x = (allocate_at_bottom) ? max : min;
5197       child_allocation.height = notebook->cur_page->requisition.height;
5198       anchor = child_allocation.x;
5199       break;
5200       
5201     case GTK_POS_RIGHT:
5202       child_allocation.x = widget->allocation.x + widget->allocation.width -
5203         notebook->cur_page->requisition.width - container->border_width;
5204       /* fall through */
5205     case GTK_POS_LEFT:
5206       child_allocation.y = (allocate_at_bottom) ? max : min;
5207       child_allocation.width = notebook->cur_page->requisition.width;
5208       anchor = child_allocation.y;
5209       break;
5210     }
5211
5212   left_x   = CLAMP (priv->mouse_x - priv->drag_offset_x,
5213                     min, max - notebook->cur_page->allocation.width);
5214   top_y    = CLAMP (priv->mouse_y - priv->drag_offset_y,
5215                     min, max - notebook->cur_page->allocation.height);
5216   right_x  = left_x + notebook->cur_page->allocation.width;
5217   bottom_y = top_y + notebook->cur_page->allocation.height;
5218   gap_left = packing_changed = FALSE;
5219
5220   while (*children && *children != last_child)
5221     {
5222       page = (*children)->data;
5223
5224       if (direction == STEP_NEXT && page->pack != GTK_PACK_START)
5225         {
5226           if (!showarrow)
5227             break;
5228           else if (priv->operation == DRAG_OPERATION_REORDER)
5229             packing_changed = TRUE;
5230         }
5231
5232       if (direction == STEP_NEXT)
5233         *children = gtk_notebook_search_page (notebook, *children, direction, TRUE);
5234       else
5235         {
5236           *children = (*children)->next;
5237
5238           if (page->pack != GTK_PACK_END || !GTK_WIDGET_VISIBLE (page->child))
5239             continue;
5240         }
5241
5242       if (!NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page))
5243         continue;
5244
5245       tab_extra_space = 0;
5246       if (*expanded_tabs && (showarrow || page->expand || notebook->homogeneous))
5247         {
5248           tab_extra_space = *remaining_space / *expanded_tabs;
5249           *remaining_space -= tab_extra_space;
5250           (*expanded_tabs)--;
5251         }
5252
5253       switch (tab_pos)
5254         {
5255         case GTK_POS_TOP:
5256         case GTK_POS_BOTTOM:
5257           child_allocation.width = page->requisition.width + tab_overlap + tab_extra_space;
5258
5259           /* make sure that the reordered tab doesn't go past the last position */
5260           if (priv->operation == DRAG_OPERATION_REORDER &&
5261               !gap_left && packing_changed)
5262             {
5263               if (!allocate_at_bottom)
5264                 {
5265                   if ((notebook->cur_page->pack == GTK_PACK_START && left_x >= anchor) ||
5266                       (notebook->cur_page->pack == GTK_PACK_END && left_x < anchor))
5267                     {
5268                       left_x = priv->drag_window_x = anchor;
5269                       anchor += notebook->cur_page->allocation.width - tab_overlap;
5270                     }
5271                 }
5272               else
5273                 {
5274                   if ((notebook->cur_page->pack == GTK_PACK_START && right_x <= anchor) ||
5275                       (notebook->cur_page->pack == GTK_PACK_END && right_x > anchor))
5276                     {
5277                       anchor -= notebook->cur_page->allocation.width;
5278                       left_x = priv->drag_window_x = anchor;
5279                       anchor += tab_overlap;
5280                     }
5281                 }
5282
5283               gap_left = TRUE;
5284             }
5285
5286           if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5287             {
5288               priv->drag_window_x = left_x;
5289               priv->drag_window_y = child_allocation.y;
5290             }
5291           else
5292             {
5293               if (allocate_at_bottom)
5294                 anchor -= child_allocation.width;
5295  
5296               if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5297                 {
5298                   if (!allocate_at_bottom &&
5299                       left_x >= anchor &&
5300                       left_x <= anchor + child_allocation.width / 2)
5301                     anchor += notebook->cur_page->allocation.width - tab_overlap;
5302                   else if (allocate_at_bottom &&
5303                            right_x >= anchor + child_allocation.width / 2 &&
5304                            right_x <= anchor + child_allocation.width)
5305                     anchor -= notebook->cur_page->allocation.width - tab_overlap;
5306                 }
5307
5308               child_allocation.x = anchor;
5309             }
5310
5311           break;
5312         case GTK_POS_LEFT:
5313         case GTK_POS_RIGHT:
5314           child_allocation.height = page->requisition.height + tab_overlap + tab_extra_space;
5315
5316           /* make sure that the reordered tab doesn't go past the last position */
5317           if (priv->operation == DRAG_OPERATION_REORDER &&
5318               !gap_left && packing_changed)
5319             {
5320               if (!allocate_at_bottom &&
5321                   ((notebook->cur_page->pack == GTK_PACK_START && top_y >= anchor) ||
5322                    (notebook->cur_page->pack == GTK_PACK_END && top_y < anchor)))
5323                 {
5324                   top_y = priv->drag_window_y = anchor;
5325                   anchor += notebook->cur_page->allocation.height - tab_overlap;
5326                 }
5327  
5328               gap_left = TRUE;
5329             }
5330
5331           if (priv->operation == DRAG_OPERATION_REORDER && page == notebook->cur_page)
5332             {
5333               priv->drag_window_x = child_allocation.x;
5334               priv->drag_window_y = top_y;
5335             }
5336           else
5337             {
5338               if (allocate_at_bottom)
5339                 anchor -= child_allocation.height;
5340
5341               if (priv->operation == DRAG_OPERATION_REORDER && page->pack == notebook->cur_page->pack)
5342                 {
5343                   if (!allocate_at_bottom &&
5344                       top_y >= anchor &&
5345                       top_y <= anchor + child_allocation.height / 2)
5346                     anchor += notebook->cur_page->allocation.height - tab_overlap;
5347                   else if (allocate_at_bottom &&
5348                            bottom_y >= anchor + child_allocation.height / 2 &&
5349                            bottom_y <= anchor + child_allocation.height)
5350                     anchor -= notebook->cur_page->allocation.height - tab_overlap;
5351                 }
5352
5353               child_allocation.y = anchor;
5354             }
5355
5356           break;
5357         }
5358
5359       if ((priv->operation != DRAG_OPERATION_REORDER || page != notebook->cur_page) &&
5360           (page->allocation.x != child_allocation.x ||
5361            page->allocation.y != child_allocation.y ||
5362            page->allocation.width != child_allocation.width ||
5363            page->allocation.height != child_allocation.height))
5364         allocation_changed = TRUE;
5365
5366       page->allocation = child_allocation;
5367
5368       if ((page == priv->detached_tab && priv->operation == DRAG_OPERATION_DETACH) ||
5369           (page == notebook->cur_page && priv->operation == DRAG_OPERATION_REORDER))
5370         {
5371           /* needs to be allocated at 0,0
5372            * to be shown in the drag window */
5373           page->allocation.x = 0;
5374           page->allocation.y = 0;
5375         }
5376       
5377       if (page != notebook->cur_page)
5378         {
5379           switch (tab_pos)
5380             {
5381             case GTK_POS_TOP:
5382               page->allocation.y += ythickness;
5383               /* fall through */
5384             case GTK_POS_BOTTOM:
5385               page->allocation.height = MAX (1, page->allocation.height - ythickness);
5386               break;
5387             case GTK_POS_LEFT:
5388               page->allocation.x += xthickness;
5389               /* fall through */
5390             case GTK_POS_RIGHT:
5391               page->allocation.width = MAX (1, page->allocation.width - xthickness);
5392               break;
5393             }
5394         }
5395
5396       /* calculate whether to leave a gap based on reorder operation or not */
5397       switch (tab_pos)
5398         {
5399         case GTK_POS_TOP:
5400         case GTK_POS_BOTTOM:
5401           if (priv->operation != DRAG_OPERATION_REORDER ||
5402               (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5403             {
5404               if (priv->operation == DRAG_OPERATION_REORDER)
5405                 {
5406                   if (page->pack == notebook->cur_page->pack &&
5407                       !allocate_at_bottom &&
5408                       left_x >  anchor + child_allocation.width / 2 &&
5409                       left_x <= anchor + child_allocation.width)
5410                     anchor += notebook->cur_page->allocation.width - tab_overlap;
5411                   else if (page->pack == notebook->cur_page->pack &&
5412                            allocate_at_bottom &&
5413                            right_x >= anchor &&
5414                            right_x <= anchor + child_allocation.width / 2)
5415                     anchor -= notebook->cur_page->allocation.width - tab_overlap;
5416                 }
5417  
5418               if (!allocate_at_bottom)
5419                 anchor += child_allocation.width - tab_overlap;
5420               else
5421                 anchor += tab_overlap;
5422             }
5423
5424           break;
5425         case GTK_POS_LEFT:
5426         case GTK_POS_RIGHT:
5427           if (priv->operation != DRAG_OPERATION_REORDER  ||
5428               (priv->operation == DRAG_OPERATION_REORDER && page != notebook->cur_page))
5429             {
5430               if (priv->operation == DRAG_OPERATION_REORDER)
5431                 {
5432                   if (page->pack == notebook->cur_page->pack &&
5433                       !allocate_at_bottom &&
5434                       top_y >= anchor + child_allocation.height / 2 &&
5435                       top_y <= anchor + child_allocation.height)
5436                     anchor += notebook->cur_page->allocation.height - tab_overlap;
5437                   else if (page->pack == notebook->cur_page->pack &&
5438                            allocate_at_bottom &&
5439                            bottom_y >= anchor &&
5440                            bottom_y <= anchor + child_allocation.height / 2)
5441                     anchor -= notebook->cur_page->allocation.height - tab_overlap;
5442                 }
5443
5444               if (!allocate_at_bottom)
5445                 anchor += child_allocation.height - tab_overlap;
5446               else
5447                 anchor += tab_overlap;
5448             }
5449
5450           break;
5451         }
5452
5453       /* set child visible */
5454       if (page->tab_label)
5455         gtk_widget_set_child_visible (page->tab_label, TRUE);
5456     }
5457
5458   /* Don't move the current tab past the last position during tabs reordering */
5459   if (children &&
5460       priv->operation == DRAG_OPERATION_REORDER &&
5461       ((direction == STEP_NEXT && notebook->cur_page->pack == GTK_PACK_START) ||
5462        ((direction == STEP_PREV || packing_changed) && notebook->cur_page->pack == GTK_PACK_END)))
5463     {
5464       switch (tab_pos)
5465         {
5466         case GTK_POS_TOP:
5467         case GTK_POS_BOTTOM:
5468           if (allocate_at_bottom)
5469             anchor -= notebook->cur_page->allocation.width;
5470
5471           if ((!allocate_at_bottom && priv->drag_window_x > anchor) ||
5472               (allocate_at_bottom && priv->drag_window_x < anchor))
5473             priv->drag_window_x = anchor;
5474           break;
5475         case GTK_POS_LEFT:
5476         case GTK_POS_RIGHT:
5477           if (allocate_at_bottom)
5478             anchor -= notebook->cur_page->allocation.height;
5479
5480           if ((!allocate_at_bottom && priv->drag_window_y > anchor) ||
5481               (allocate_at_bottom && priv->drag_window_y < anchor))
5482             priv->drag_window_y = anchor;
5483           break;
5484         }
5485     }
5486
5487   return allocation_changed;
5488 }
5489
5490 static void
5491 gtk_notebook_pages_allocate (GtkNotebook *notebook)
5492 {
5493   GList *children = NULL;
5494   GList *last_child = NULL;
5495   gboolean showarrow = FALSE;
5496   gint tab_space, min, max, remaining_space;
5497   gint expanded_tabs, operation;
5498
5499   if (!notebook->show_tabs || !notebook->children || !notebook->cur_page)
5500     return;
5501
5502   min = max = tab_space = remaining_space = 0;
5503   expanded_tabs = 1;
5504
5505   gtk_notebook_tab_space (notebook, &showarrow,
5506                           &min, &max, &tab_space);
5507
5508   gtk_notebook_calculate_shown_tabs (notebook, showarrow,
5509                                      min, max, tab_space, &last_child,
5510                                      &expanded_tabs, &remaining_space);
5511
5512   children = notebook->first_tab;
5513   gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5514                                           showarrow, STEP_NEXT,
5515                                           &remaining_space, &expanded_tabs, min, max);
5516   if (children && children != last_child)
5517     {
5518       children = notebook->children;
5519       gtk_notebook_calculate_tabs_allocation (notebook, &children, last_child,
5520                                               showarrow, STEP_PREV,
5521                                               &remaining_space, &expanded_tabs, min, max);
5522     }
5523
5524   children = notebook->children;
5525
5526   while (children)
5527     {
5528       gtk_notebook_page_allocate (notebook, GTK_NOTEBOOK_PAGE (children));
5529       children = children->next;
5530     }
5531
5532   operation = GTK_NOTEBOOK_GET_PRIVATE (notebook)->operation;
5533
5534   if (!notebook->first_tab)
5535     notebook->first_tab = notebook->children;
5536
5537   gtk_notebook_redraw_tabs (notebook);
5538 }
5539
5540 static void
5541 gtk_notebook_page_allocate (GtkNotebook     *notebook,
5542                             GtkNotebookPage *page)
5543 {
5544   GtkWidget *widget = GTK_WIDGET (notebook);
5545   GtkAllocation child_allocation;
5546   GtkRequisition tab_requisition;
5547   gint xthickness;
5548   gint ythickness;
5549   gint padding;
5550   gint focus_width;
5551   gint tab_curvature;
5552   gint tab_pos = get_effective_tab_pos (notebook);
5553
5554   if (!page->tab_label)
5555     return;
5556
5557   xthickness = widget->style->xthickness;
5558   ythickness = widget->style->ythickness;
5559
5560   gtk_widget_get_child_requisition (page->tab_label, &tab_requisition);
5561   gtk_widget_style_get (widget,
5562                         "focus-line-width", &focus_width,
5563                         "tab-curvature", &tab_curvature,
5564                         NULL);
5565   switch (tab_pos)
5566     {
5567     case GTK_POS_TOP:
5568     case GTK_POS_BOTTOM:
5569       padding = tab_curvature + focus_width + notebook->tab_hborder;
5570       if (page->fill)
5571         {
5572           child_allocation.x = xthickness + focus_width + notebook->tab_hborder;
5573           child_allocation.width = MAX (1, page->allocation.width - 2 * child_allocation.x);
5574           child_allocation.x += page->allocation.x;
5575         }
5576       else
5577         {
5578           child_allocation.x = page->allocation.x +
5579             (page->allocation.width - tab_requisition.width) / 2;
5580
5581           child_allocation.width = tab_requisition.width;
5582         }
5583
5584       child_allocation.y = notebook->tab_vborder + focus_width + page->allocation.y;
5585
5586       if (tab_pos == GTK_POS_TOP)
5587         child_allocation.y += ythickness;
5588
5589       child_allocation.height = MAX (1, (page->allocation.height - ythickness -
5590                                          2 * (notebook->tab_vborder + focus_width)));
5591       break;
5592     case GTK_POS_LEFT:
5593     case GTK_POS_RIGHT:
5594       padding = tab_curvature + focus_width + notebook->tab_vborder;
5595       if (page->fill)
5596         {
5597           child_allocation.y = ythickness + padding;
5598           child_allocation.height = MAX (1, (page->allocation.height -
5599                                              2 * child_allocation.y));
5600           child_allocation.y += page->allocation.y;
5601         }
5602       else
5603         {
5604           child_allocation.y = page->allocation.y +
5605             (page->allocation.height - tab_requisition.height) / 2;
5606
5607           child_allocation.height = tab_requisition.height;
5608         }
5609
5610       child_allocation.x = notebook->tab_hborder + focus_width + page->allocation.x;
5611
5612       if (tab_pos == GTK_POS_LEFT)
5613         child_allocation.x += xthickness;
5614
5615       child_allocation.width = MAX (1, (page->allocation.width - xthickness -
5616                                         2 * (notebook->tab_hborder + focus_width)));
5617       break;
5618     }
5619
5620   gtk_widget_size_allocate (page->tab_label, &child_allocation);
5621 }
5622
5623 static void 
5624 gtk_notebook_calc_tabs (GtkNotebook  *notebook,
5625                         GList        *start,
5626                         GList       **end,
5627                         gint         *tab_space,
5628                         guint         direction)
5629 {
5630   GtkNotebookPage *page = NULL;
5631   GList *children;
5632   GList *last_list = NULL;
5633   GList *last_calculated_child = NULL;
5634   gboolean pack;
5635   gint tab_pos = get_effective_tab_pos (notebook);
5636   guint real_direction;
5637
5638   if (!start)
5639     return;
5640
5641   children = start;
5642   pack = GTK_NOTEBOOK_PAGE (start)->pack;
5643   if (pack == GTK_PACK_END)
5644     real_direction = (direction == STEP_PREV) ? STEP_NEXT : STEP_PREV;
5645   else
5646     real_direction = direction;
5647
5648   while (1)
5649     {
5650       switch (tab_pos)
5651         {
5652         case GTK_POS_TOP:
5653         case GTK_POS_BOTTOM:
5654           while (children)
5655             {
5656               page = children->data;
5657               if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5658                   GTK_WIDGET_VISIBLE (page->child))
5659                 {
5660                   if (page->pack == pack)
5661                     {
5662                       *tab_space -= page->requisition.width;
5663                       if (*tab_space < 0 || children == *end)
5664                         {
5665                           if (*tab_space < 0) 
5666                             {
5667                               *tab_space = - (*tab_space +
5668                                               page->requisition.width);
5669
5670                               if (*tab_space == 0 && direction == STEP_PREV)
5671                                 children = last_calculated_child;
5672
5673                               *end = children;
5674                             }
5675                           return;
5676                         }
5677
5678                       last_calculated_child = children;
5679                     }
5680                   last_list = children;
5681                 }
5682               if (real_direction == STEP_NEXT)
5683                 children = children->next;
5684               else
5685                 children = children->prev;
5686             }
5687           break;
5688         case GTK_POS_LEFT:
5689         case GTK_POS_RIGHT:
5690           while (children)
5691             {
5692               page = children->data;
5693               if (NOTEBOOK_IS_TAB_LABEL_PARENT (notebook, page) &&
5694                   GTK_WIDGET_VISIBLE (page->child))
5695                 {
5696                   if (page->pack == pack)
5697                     {
5698                       *tab_space -= page->requisition.height;
5699                       if (*tab_space < 0 || children == *end)
5700                         {
5701                           if (*tab_space < 0)
5702                             {
5703                               *tab_space = - (*tab_space +
5704                                               page->requisition.height);
5705
5706                               if (*tab_space == 0 && direction == STEP_PREV)
5707                                 children = last_calculated_child;
5708
5709                               *end = children;
5710                             }
5711                           return;
5712                         }
5713
5714                       last_calculated_child = children;
5715                     }
5716                   last_list = children;
5717                 }
5718               if (real_direction == STEP_NEXT)
5719                 children = children->next;
5720               else
5721                 children = children->prev;
5722             }
5723           break;
5724         }
5725       if (real_direction == STEP_PREV)
5726         return;
5727       pack = (pack == GTK_PACK_END) ? GTK_PACK_START : GTK_PACK_END;
5728       real_direction = STEP_PREV;
5729       children = last_list;
5730     }
5731 }
5732
5733 static void
5734 gtk_notebook_update_tab_states (GtkNotebook *notebook)
5735 {
5736   GList *list;
5737
5738   for (list = notebook->children; list != NULL; list = list->next)
5739     {
5740       GtkNotebookPage *page = list->data;
5741       
5742       if (page->tab_label)
5743         {
5744           if (page == notebook->cur_page)
5745             gtk_widget_set_state (page->tab_label, GTK_STATE_NORMAL);
5746           else
5747             gtk_widget_set_state (page->tab_label, GTK_STATE_ACTIVE);
5748         }
5749     }
5750 }
5751
5752 /* Private GtkNotebook Page Switch Methods:
5753  *
5754  * gtk_notebook_real_switch_page
5755  */
5756 static void
5757 gtk_notebook_real_switch_page (GtkNotebook     *notebook,
5758                                GtkNotebookPage *page,
5759                                guint            page_num)
5760 {
5761   if (notebook->cur_page == page || !GTK_WIDGET_VISIBLE (page->child))
5762     return;
5763
5764   if (notebook->cur_page)
5765     gtk_widget_set_child_visible (notebook->cur_page->child, FALSE);
5766
5767   notebook->cur_page = page;
5768
5769   if (!notebook->focus_tab ||
5770       notebook->focus_tab->data != (gpointer) notebook->cur_page)
5771     notebook->focus_tab = 
5772       g_list_find (notebook->children, notebook->cur_page);
5773
5774   gtk_widget_set_child_visible (notebook->cur_page->child, TRUE);
5775
5776   /* If the focus was on the previous page, move it to the first
5777    * element on the new page, if possible, or if not, to the
5778    * notebook itself.
5779    */
5780   if (notebook->child_has_focus)
5781     {
5782       if (notebook->cur_page->last_focus_child &&
5783           gtk_widget_is_ancestor (notebook->cur_page->last_focus_child, notebook->cur_page->child))
5784         gtk_widget_grab_focus (notebook->cur_page->last_focus_child);
5785       else
5786         if (!gtk_widget_child_focus (notebook->cur_page->child, GTK_DIR_TAB_FORWARD))
5787           gtk_widget_grab_focus (GTK_WIDGET (notebook));
5788     }
5789   
5790   gtk_notebook_update_tab_states (notebook);
5791   gtk_widget_queue_resize (GTK_WIDGET (notebook));
5792   g_object_notify (G_OBJECT (notebook), "page");
5793 }
5794
5795 /* Private GtkNotebook Page Switch Functions:
5796  *
5797  * gtk_notebook_switch_page
5798  * gtk_notebook_page_select
5799  * gtk_notebook_switch_focus_tab
5800  * gtk_notebook_menu_switch_page
5801  */
5802 static void
5803 gtk_notebook_switch_page (GtkNotebook     *notebook,
5804                           GtkNotebookPage *page)
5805
5806   guint page_num;
5807
5808   if (notebook->cur_page == page)
5809     return;
5810
5811   page_num = g_list_index (notebook->children, page);
5812
5813   g_signal_emit (notebook,
5814                  notebook_signals[SWITCH_PAGE],
5815                  0,
5816                  page,
5817                  page_num);
5818 }
5819
5820 static gint
5821 gtk_notebook_page_select (GtkNotebook *notebook,
5822                           gboolean     move_focus)
5823 {
5824   GtkNotebookPage *page;
5825   GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */
5826   gint tab_pos = get_effective_tab_pos (notebook);
5827
5828   if (!notebook->focus_tab)
5829     return FALSE;
5830
5831   page = notebook->focus_tab->data;
5832   gtk_notebook_switch_page (notebook, page);
5833
5834   if (move_focus)
5835     {
5836       switch (tab_pos)
5837         {
5838         case GTK_POS_TOP:
5839           dir = GTK_DIR_DOWN;
5840           break;
5841         case GTK_POS_BOTTOM:
5842           dir = GTK_DIR_UP;
5843           break;
5844         case GTK_POS_LEFT:
5845           dir = GTK_DIR_RIGHT;
5846           break;
5847         case GTK_POS_RIGHT:
5848           dir = GTK_DIR_LEFT;
5849           break;
5850         }
5851
5852       if (gtk_widget_child_focus (page->child, dir))
5853         return TRUE;
5854     }
5855   return FALSE;
5856 }
5857
5858 static void
5859 gtk_notebook_switch_focus_tab (GtkNotebook *notebook, 
5860                                GList       *new_child)
5861 {
5862   GList *old_child;
5863   GtkNotebookPage *page;
5864
5865   if (notebook->focus_tab == new_child)
5866     return;
5867
5868   old_child = notebook->focus_tab;
5869   notebook->focus_tab = new_child;
5870
5871   if (notebook->scrollable)
5872     gtk_notebook_redraw_arrows (notebook);
5873
5874   if (!notebook->show_tabs || !notebook->focus_tab)
5875     return;
5876
5877   page = notebook->focus_tab->data;
5878   if (GTK_WIDGET_MAPPED (page->tab_label))
5879     gtk_notebook_redraw_tabs (notebook);
5880   else
5881     gtk_notebook_pages_allocate (notebook);
5882
5883   gtk_notebook_switch_page (notebook, page);
5884 }
5885
5886 static void
5887 gtk_notebook_menu_switch_page (GtkWidget       *widget,
5888                                GtkNotebookPage *page)
5889 {
5890   GtkNotebook *notebook;
5891   GList *children;
5892   guint page_num;
5893
5894   notebook = GTK_NOTEBOOK (gtk_menu_get_attach_widget
5895                            (GTK_MENU (widget->parent)));
5896
5897   if (notebook->cur_page == page)
5898     return;
5899
5900   page_num = 0;
5901   children = notebook->children;
5902   while (children && children->data != page)
5903     {
5904       children = children->next;
5905       page_num++;
5906     }
5907
5908   g_signal_emit (notebook,
5909                  notebook_signals[SWITCH_PAGE],
5910                  0,
5911                  page,
5912                  page_num);
5913 }
5914
5915 /* Private GtkNotebook Menu Functions:
5916  *
5917  * gtk_notebook_menu_item_create
5918  * gtk_notebook_menu_label_unparent
5919  * gtk_notebook_menu_detacher
5920  */
5921 static void
5922 gtk_notebook_menu_item_create (GtkNotebook *notebook, 
5923                                GList       *list)
5924 {       
5925   GtkNotebookPage *page;
5926   GtkWidget *menu_item;
5927
5928   page = list->data;
5929   if (page->default_menu)
5930     {
5931       if (GTK_IS_LABEL (page->tab_label))
5932         page->menu_label = gtk_label_new (GTK_LABEL (page->tab_label)->label);
5933       else
5934         page->menu_label = gtk_label_new ("");
5935       gtk_misc_set_alignment (GTK_MISC (page->menu_label), 0.0, 0.5);
5936     }
5937
5938   gtk_widget_show (page->menu_label);
5939   menu_item = gtk_menu_item_new ();
5940   gtk_container_add (GTK_CONTAINER (menu_item), page->menu_label);
5941   gtk_menu_shell_insert (GTK_MENU_SHELL (notebook->menu), menu_item,
5942                          gtk_notebook_real_page_position (notebook, list));
5943   g_signal_connect (menu_item, "activate",
5944                     G_CALLBACK (gtk_notebook_menu_switch_page), page);
5945   if (GTK_WIDGET_VISIBLE (page->child))
5946     gtk_widget_show (menu_item);
5947 }
5948
5949 static void
5950 gtk_notebook_menu_label_unparent (GtkWidget *widget, 
5951                                   gpointer  data)
5952 {
5953   gtk_widget_unparent (GTK_BIN (widget)->child);
5954   GTK_BIN (widget)->child = NULL;
5955 }
5956
5957 static void
5958 gtk_notebook_menu_detacher (GtkWidget *widget,
5959                             GtkMenu   *menu)
5960 {
5961   GtkNotebook *notebook;
5962
5963   notebook = GTK_NOTEBOOK (widget);
5964   g_return_if_fail (notebook->menu == (GtkWidget*) menu);
5965
5966   notebook->menu = NULL;
5967 }
5968
5969 /* Private GtkNotebook Setter Functions:
5970  *
5971  * gtk_notebook_set_homogeneous_tabs_internal
5972  * gtk_notebook_set_tab_border_internal
5973  * gtk_notebook_set_tab_hborder_internal
5974  * gtk_notebook_set_tab_vborder_internal
5975  */
5976 static void
5977 gtk_notebook_set_homogeneous_tabs_internal (GtkNotebook *notebook,
5978                                             gboolean     homogeneous)
5979 {
5980   if (homogeneous == notebook->homogeneous)
5981     return;
5982
5983   notebook->homogeneous = homogeneous;
5984   gtk_widget_queue_resize (GTK_WIDGET (notebook));
5985
5986   g_object_notify (G_OBJECT (notebook), "homogeneous");
5987 }
5988
5989 static void
5990 gtk_notebook_set_tab_border_internal (GtkNotebook *notebook,
5991                                       guint        border_width)
5992 {
5993   notebook->tab_hborder = border_width;
5994   notebook->tab_vborder = border_width;
5995
5996   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
5997     gtk_widget_queue_resize (GTK_WIDGET (notebook));
5998
5999   g_object_freeze_notify (G_OBJECT (notebook));
6000   g_object_notify (G_OBJECT (notebook), "tab-hborder");
6001   g_object_notify (G_OBJECT (notebook), "tab-vborder");
6002   g_object_thaw_notify (G_OBJECT (notebook));
6003 }
6004
6005 static void
6006 gtk_notebook_set_tab_hborder_internal (GtkNotebook *notebook,
6007                                        guint        tab_hborder)
6008 {
6009   if (notebook->tab_hborder == tab_hborder)
6010     return;
6011
6012   notebook->tab_hborder = tab_hborder;
6013
6014   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6015     gtk_widget_queue_resize (GTK_WIDGET (notebook));
6016
6017   g_object_notify (G_OBJECT (notebook), "tab-hborder");
6018 }
6019
6020 static void
6021 gtk_notebook_set_tab_vborder_internal (GtkNotebook *notebook,
6022                                        guint        tab_vborder)
6023 {
6024   if (notebook->tab_vborder == tab_vborder)
6025     return;
6026
6027   notebook->tab_vborder = tab_vborder;
6028
6029   if (GTK_WIDGET_VISIBLE (notebook) && notebook->show_tabs)
6030     gtk_widget_queue_resize (GTK_WIDGET (notebook));
6031
6032   g_object_notify (G_OBJECT (notebook), "tab-vborder");
6033 }
6034
6035 /* Public GtkNotebook Page Insert/Remove Methods :
6036  *
6037  * gtk_notebook_append_page
6038  * gtk_notebook_append_page_menu
6039  * gtk_notebook_prepend_page
6040  * gtk_notebook_prepend_page_menu
6041  * gtk_notebook_insert_page
6042  * gtk_notebook_insert_page_menu
6043  * gtk_notebook_remove_page
6044  */
6045 /**
6046  * gtk_notebook_append_page:
6047  * @notebook: a #GtkNotebook
6048  * @child: the #GtkWidget to use as the contents of the page.
6049  * @tab_label: the #GtkWidget to be used as the label for the page,
6050  *             or %NULL to use the default label, 'page N'.
6051  * 
6052  * Appends a page to @notebook.
6053  *
6054  * Return value: the index (starting from 0) of the appended
6055  * page in the notebook, or -1 if function fails
6056  **/
6057 gint
6058 gtk_notebook_append_page (GtkNotebook *notebook,
6059                           GtkWidget   *child,
6060                           GtkWidget   *tab_label)
6061 {
6062   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6063   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6064   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6065   
6066   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1);
6067 }
6068
6069 /**
6070  * gtk_notebook_append_page_menu:
6071  * @notebook: a #GtkNotebook
6072  * @child: the #GtkWidget to use as the contents of the page.
6073  * @tab_label: the #GtkWidget to be used as the label for the page,
6074  *             or %NULL to use the default label, 'page N'.
6075  * @menu_label: the widget to use as a label for the page-switch
6076  *              menu, if that is enabled. If %NULL, and @tab_label
6077  *              is a #GtkLabel or %NULL, then the menu label will be
6078  *              a newly created label with the same text as @tab_label;
6079  *              If @tab_label is not a #GtkLabel, @menu_label must be
6080  *              specified if the page-switch menu is to be used.
6081  * 
6082  * Appends a page to @notebook, specifying the widget to use as the
6083  * label in the popup menu.
6084  *
6085  * Return value: the index (starting from 0) of the appended
6086  * page in the notebook, or -1 if function fails
6087  **/
6088 gint
6089 gtk_notebook_append_page_menu (GtkNotebook *notebook,
6090                                GtkWidget   *child,
6091                                GtkWidget   *tab_label,
6092                                GtkWidget   *menu_label)
6093 {
6094   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6095   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6096   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6097   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6098   
6099   return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1);
6100 }
6101
6102 /**
6103  * gtk_notebook_prepend_page:
6104  * @notebook: a #GtkNotebook
6105  * @child: the #GtkWidget to use as the contents of the page.
6106  * @tab_label: the #GtkWidget to be used as the label for the page,
6107  *             or %NULL to use the default label, 'page N'.
6108  *
6109  * Prepends a page to @notebook.
6110  *
6111  * Return value: the index (starting from 0) of the prepended
6112  * page in the notebook, or -1 if function fails
6113  **/
6114 gint
6115 gtk_notebook_prepend_page (GtkNotebook *notebook,
6116                            GtkWidget   *child,
6117                            GtkWidget   *tab_label)
6118 {
6119   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6120   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6121   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6122   
6123   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0);
6124 }
6125
6126 /**
6127  * gtk_notebook_prepend_page_menu:
6128  * @notebook: a #GtkNotebook
6129  * @child: the #GtkWidget to use as the contents of the page.
6130  * @tab_label: the #GtkWidget to be used as the label for the page,
6131  *             or %NULL to use the default label, 'page N'.
6132  * @menu_label: the widget to use as a label for the page-switch
6133  *              menu, if that is enabled. If %NULL, and @tab_label
6134  *              is a #GtkLabel or %NULL, then the menu label will be
6135  *              a newly created label with the same text as @tab_label;
6136  *              If @tab_label is not a #GtkLabel, @menu_label must be
6137  *              specified if the page-switch menu is to be used.
6138  * 
6139  * Prepends a page to @notebook, specifying the widget to use as the
6140  * label in the popup menu.
6141  *
6142  * Return value: the index (starting from 0) of the prepended
6143  * page in the notebook, or -1 if function fails
6144  **/
6145 gint
6146 gtk_notebook_prepend_page_menu (GtkNotebook *notebook,
6147                                 GtkWidget   *child,
6148                                 GtkWidget   *tab_label,
6149                                 GtkWidget   *menu_label)
6150 {
6151   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6152   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6153   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6154   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6155   
6156   return gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0);
6157 }
6158
6159 /**
6160  * gtk_notebook_insert_page:
6161  * @notebook: a #GtkNotebook
6162  * @child: the #GtkWidget to use as the contents of the page.
6163  * @tab_label: the #GtkWidget to be used as the label for the page,
6164  *             or %NULL to use the default label, 'page N'.
6165  * @position: the index (starting at 0) at which to insert the page,
6166  *            or -1 to append the page after all other pages.
6167  * 
6168  * Insert a page into @notebook at the given position.
6169  *
6170  * Return value: the index (starting from 0) of the inserted
6171  * page in the notebook, or -1 if function fails
6172  **/
6173 gint
6174 gtk_notebook_insert_page (GtkNotebook *notebook,
6175                           GtkWidget   *child,
6176                           GtkWidget   *tab_label,
6177                           gint         position)
6178 {
6179   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6180   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6181   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6182   
6183   return gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position);
6184 }
6185
6186
6187 static gint
6188 gtk_notebook_page_compare_tab (gconstpointer a,
6189                                gconstpointer b)
6190 {
6191   return (((GtkNotebookPage *) a)->tab_label != b);
6192 }
6193
6194 static gboolean
6195 gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
6196                                             gboolean overload,
6197                                             gpointer data)
6198 {
6199   GtkNotebook *notebook = GTK_NOTEBOOK (data);
6200   GList *list;
6201   
6202   list = g_list_find_custom (notebook->children, child,
6203                              gtk_notebook_page_compare_tab);
6204   if (list)
6205     {
6206       GtkNotebookPage *page = list->data;
6207
6208       gtk_widget_grab_focus (GTK_WIDGET (notebook));    /* Do this first to avoid focusing new page */
6209       gtk_notebook_switch_page (notebook, page);
6210       focus_tabs_in (notebook);
6211     }
6212
6213   return TRUE;
6214 }
6215
6216 /**
6217  * gtk_notebook_insert_page_menu:
6218  * @notebook: a #GtkNotebook
6219  * @child: the #GtkWidget to use as the contents of the page.
6220  * @tab_label: the #GtkWidget to be used as the label for the page,
6221  *             or %NULL to use the default label, 'page N'.
6222  * @menu_label: the widget to use as a label for the page-switch
6223  *              menu, if that is enabled. If %NULL, and @tab_label
6224  *              is a #GtkLabel or %NULL, then the menu label will be
6225  *              a newly created label with the same text as @tab_label;
6226  *              If @tab_label is not a #GtkLabel, @menu_label must be
6227  *              specified if the page-switch menu is to be used.
6228  * @position: the index (starting at 0) at which to insert the page,
6229  *            or -1 to append the page after all other pages.
6230  * 
6231  * Insert a page into @notebook at the given position, specifying
6232  * the widget to use as the label in the popup menu.
6233  *
6234  * Return value: the index (starting from 0) of the inserted
6235  * page in the notebook
6236  **/
6237 gint
6238 gtk_notebook_insert_page_menu (GtkNotebook *notebook,
6239                                GtkWidget   *child,
6240                                GtkWidget   *tab_label,
6241                                GtkWidget   *menu_label,
6242                                gint         position)
6243 {
6244   GtkNotebookClass *class;
6245
6246   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6247   g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
6248   g_return_val_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label), -1);
6249   g_return_val_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label), -1);
6250
6251   class = GTK_NOTEBOOK_GET_CLASS (notebook);
6252
6253   return (class->insert_page) (notebook, child, tab_label, menu_label, position);
6254 }
6255
6256 /**
6257  * gtk_notebook_remove_page:
6258  * @notebook: a #GtkNotebook.
6259  * @page_num: the index of a notebook page, starting
6260  *            from 0. If -1, the last page will
6261  *            be removed.
6262  * 
6263  * Removes a page from the notebook given its index
6264  * in the notebook.
6265  **/
6266 void
6267 gtk_notebook_remove_page (GtkNotebook *notebook,
6268                           gint         page_num)
6269 {
6270   GList *list = NULL;
6271
6272   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6273
6274   if (page_num >= 0)
6275     list = g_list_nth (notebook->children, page_num);
6276   else
6277     list = g_list_last (notebook->children);
6278
6279   if (list)
6280     gtk_container_remove (GTK_CONTAINER (notebook),
6281                           ((GtkNotebookPage *) list->data)->child);
6282 }
6283
6284 /* Public GtkNotebook Page Switch Methods :
6285  * gtk_notebook_get_current_page
6286  * gtk_notebook_page_num
6287  * gtk_notebook_set_current_page
6288  * gtk_notebook_next_page
6289  * gtk_notebook_prev_page
6290  */
6291 /**
6292  * gtk_notebook_get_current_page:
6293  * @notebook: a #GtkNotebook
6294  * 
6295  * Returns the page number of the current page.
6296  * 
6297  * Return value: the index (starting from 0) of the current
6298  * page in the notebook. If the notebook has no pages, then
6299  * -1 will be returned.
6300  **/
6301 gint
6302 gtk_notebook_get_current_page (GtkNotebook *notebook)
6303 {
6304   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6305
6306   if (!notebook->cur_page)
6307     return -1;
6308
6309   return g_list_index (notebook->children, notebook->cur_page);
6310 }
6311
6312 /**
6313  * gtk_notebook_get_nth_page:
6314  * @notebook: a #GtkNotebook
6315  * @page_num: the index of a page in the notebook, or -1
6316  *            to get the last page.
6317  * 
6318  * Returns the child widget contained in page number @page_num.
6319  * 
6320  * Return value: the child widget, or %NULL if @page_num is
6321  * out of bounds.
6322  **/
6323 GtkWidget*
6324 gtk_notebook_get_nth_page (GtkNotebook *notebook,
6325                            gint         page_num)
6326 {
6327   GtkNotebookPage *page;
6328   GList *list;
6329
6330   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6331
6332   if (page_num >= 0)
6333     list = g_list_nth (notebook->children, page_num);
6334   else
6335     list = g_list_last (notebook->children);
6336
6337   if (list)
6338     {
6339       page = list->data;
6340       return page->child;
6341     }
6342
6343   return NULL;
6344 }
6345
6346 /**
6347  * gtk_notebook_get_n_pages:
6348  * @notebook: a #GtkNotebook
6349  * 
6350  * Gets the number of pages in a notebook.
6351  * 
6352  * Return value: the number of pages in the notebook.
6353  *
6354  * Since: 2.2
6355  **/
6356 gint
6357 gtk_notebook_get_n_pages (GtkNotebook *notebook)
6358 {
6359   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), 0);
6360
6361   return g_list_length (notebook->children);
6362 }
6363
6364 /**
6365  * gtk_notebook_page_num:
6366  * @notebook: a #GtkNotebook
6367  * @child: a #GtkWidget
6368  * 
6369  * Finds the index of the page which contains the given child
6370  * widget.
6371  * 
6372  * Return value: the index of the page containing @child, or
6373  *   -1 if @child is not in the notebook.
6374  **/
6375 gint
6376 gtk_notebook_page_num (GtkNotebook      *notebook,
6377                        GtkWidget        *child)
6378 {
6379   GList *children;
6380   gint num;
6381
6382   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
6383
6384   num = 0;
6385   children = notebook->children;
6386   while (children)
6387     {
6388       GtkNotebookPage *page =  children->data;
6389       
6390       if (page->child == child)
6391         return num;
6392
6393       children = children->next;
6394       num++;
6395     }
6396
6397   return -1;
6398 }
6399
6400 /**
6401  * gtk_notebook_set_current_page:
6402  * @notebook: a #GtkNotebook
6403  * @page_num: index of the page to switch to, starting from 0.
6404  *            If negative, the last page will be used. If greater
6405  *            than the number of pages in the notebook, nothing
6406  *            will be done.
6407  *                
6408  * Switches to the page number @page_num. 
6409  *
6410  * Note that due to historical reasons, GtkNotebook refuses
6411  * to switch to a page unless the child widget is visible. 
6412  * Therefore, it is recommended to show child widgets before
6413  * adding them to a notebook. 
6414  */
6415 void
6416 gtk_notebook_set_current_page (GtkNotebook *notebook,
6417                                gint         page_num)
6418 {
6419   GList *list;
6420
6421   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6422
6423   if (page_num < 0)
6424     page_num = g_list_length (notebook->children) - 1;
6425
6426   list = g_list_nth (notebook->children, page_num);
6427   if (list)
6428     gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6429 }
6430
6431 /**
6432  * gtk_notebook_next_page:
6433  * @notebook: a #GtkNotebook
6434  * 
6435  * Switches to the next page. Nothing happens if the current page is
6436  * the last page.
6437  **/
6438 void
6439 gtk_notebook_next_page (GtkNotebook *notebook)
6440 {
6441   GList *list;
6442
6443   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6444
6445   list = g_list_find (notebook->children, notebook->cur_page);
6446   if (!list)
6447     return;
6448
6449   list = gtk_notebook_search_page (notebook, list, STEP_NEXT, TRUE);
6450   if (!list)
6451     return;
6452
6453   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6454 }
6455
6456 /**
6457  * gtk_notebook_prev_page:
6458  * @notebook: a #GtkNotebook
6459  * 
6460  * Switches to the previous page. Nothing happens if the current page
6461  * is the first page.
6462  **/
6463 void
6464 gtk_notebook_prev_page (GtkNotebook *notebook)
6465 {
6466   GList *list;
6467
6468   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6469
6470   list = g_list_find (notebook->children, notebook->cur_page);
6471   if (!list)
6472     return;
6473
6474   list = gtk_notebook_search_page (notebook, list, STEP_PREV, TRUE);
6475   if (!list)
6476     return;
6477
6478   gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list));
6479 }
6480
6481 /* Public GtkNotebook/Tab Style Functions
6482  *
6483  * gtk_notebook_set_show_border
6484  * gtk_notebook_set_show_tabs
6485  * gtk_notebook_set_tab_pos
6486  * gtk_notebook_set_homogeneous_tabs
6487  * gtk_notebook_set_tab_border
6488  * gtk_notebook_set_tab_hborder
6489  * gtk_notebook_set_tab_vborder
6490  * gtk_notebook_set_scrollable
6491  */
6492 /**
6493  * gtk_notebook_set_show_border:
6494  * @notebook: a #GtkNotebook
6495  * @show_border: %TRUE if a bevel should be drawn around the notebook.
6496  * 
6497  * Sets whether a bevel will be drawn around the notebook pages.
6498  * This only has a visual effect when the tabs are not shown.
6499  * See gtk_notebook_set_show_tabs().
6500  **/
6501 void
6502 gtk_notebook_set_show_border (GtkNotebook *notebook,
6503                               gboolean     show_border)
6504 {
6505   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6506
6507   if (notebook->show_border != show_border)
6508     {
6509       notebook->show_border = show_border;
6510
6511       if (GTK_WIDGET_VISIBLE (notebook))
6512         gtk_widget_queue_resize (GTK_WIDGET (notebook));
6513       
6514       g_object_notify (G_OBJECT (notebook), "show-border");
6515     }
6516 }
6517
6518 /**
6519  * gtk_notebook_get_show_border:
6520  * @notebook: a #GtkNotebook
6521  *
6522  * Returns whether a bevel will be drawn around the notebook pages. See
6523  * gtk_notebook_set_show_border().
6524  *
6525  * Return value: %TRUE if the bevel is drawn
6526  **/
6527 gboolean
6528 gtk_notebook_get_show_border (GtkNotebook *notebook)
6529 {
6530   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6531
6532   return notebook->show_border;
6533 }
6534
6535 /**
6536  * gtk_notebook_set_show_tabs:
6537  * @notebook: a #GtkNotebook
6538  * @show_tabs: %TRUE if the tabs should be shown.
6539  * 
6540  * Sets whether to show the tabs for the notebook or not.
6541  **/
6542 void
6543 gtk_notebook_set_show_tabs (GtkNotebook *notebook,
6544                             gboolean     show_tabs)
6545 {
6546   GtkNotebookPage *page;
6547   GList *children;
6548
6549   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6550
6551   show_tabs = show_tabs != FALSE;
6552
6553   if (notebook->show_tabs == show_tabs)
6554     return;
6555
6556   notebook->show_tabs = show_tabs;
6557   children = notebook->children;
6558
6559   if (!show_tabs)
6560     {
6561       GTK_WIDGET_UNSET_FLAGS (notebook, GTK_CAN_FOCUS);
6562       
6563       while (children)
6564         {
6565           page = children->data;
6566           children = children->next;
6567           if (page->default_tab)
6568             {
6569               gtk_widget_destroy (page->tab_label);
6570               page->tab_label = NULL;
6571             }
6572           else
6573             gtk_widget_hide (page->tab_label);
6574         }
6575     }
6576   else
6577     {
6578       GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS);
6579       gtk_notebook_update_labels (notebook);
6580     }
6581   gtk_widget_queue_resize (GTK_WIDGET (notebook));
6582
6583   g_object_notify (G_OBJECT (notebook), "show-tabs");
6584 }
6585
6586 /**
6587  * gtk_notebook_get_show_tabs:
6588  * @notebook: a #GtkNotebook
6589  *
6590  * Returns whether the tabs of the notebook are shown. See
6591  * gtk_notebook_set_show_tabs().
6592  *
6593  * Return value: %TRUE if the tabs are shown
6594  **/
6595 gboolean
6596 gtk_notebook_get_show_tabs (GtkNotebook *notebook)
6597 {
6598   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6599
6600   return notebook->show_tabs;
6601 }
6602
6603 /**
6604  * gtk_notebook_set_tab_pos:
6605  * @notebook: a #GtkNotebook.
6606  * @pos: the edge to draw the tabs at.
6607  * 
6608  * Sets the edge at which the tabs for switching pages in the
6609  * notebook are drawn.
6610  **/
6611 void
6612 gtk_notebook_set_tab_pos (GtkNotebook     *notebook,
6613                           GtkPositionType  pos)
6614 {
6615   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6616
6617   if (notebook->tab_pos != pos)
6618     {
6619       notebook->tab_pos = pos;
6620       if (GTK_WIDGET_VISIBLE (notebook))
6621         gtk_widget_queue_resize (GTK_WIDGET (notebook));
6622     }
6623
6624   g_object_notify (G_OBJECT (notebook), "tab-pos");
6625 }
6626
6627 /**
6628  * gtk_notebook_get_tab_pos:
6629  * @notebook: a #GtkNotebook
6630  *
6631  * Gets the edge at which the tabs for switching pages in the
6632  * notebook are drawn.
6633  *
6634  * Return value: the edge at which the tabs are drawn
6635  **/
6636 GtkPositionType
6637 gtk_notebook_get_tab_pos (GtkNotebook *notebook)
6638 {
6639   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), GTK_POS_TOP);
6640
6641   return notebook->tab_pos;
6642 }
6643
6644 /**
6645  * gtk_notebook_set_homogeneous_tabs:
6646  * @notebook: a #GtkNotebook
6647  * @homogeneous: %TRUE if all tabs should be the same size.
6648  * 
6649  * Sets whether the tabs must have all the same size or not.
6650  **/
6651 void
6652 gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook,
6653                                    gboolean     homogeneous)
6654 {
6655   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6656
6657   gtk_notebook_set_homogeneous_tabs_internal (notebook, homogeneous);
6658 }
6659
6660 /**
6661  * gtk_notebook_set_tab_border:
6662  * @notebook: a #GtkNotebook
6663  * @border_width: width of the border around the tab labels.
6664  * 
6665  * Sets the width the border around the tab labels
6666  * in a notebook. This is equivalent to calling
6667  * gtk_notebook_set_tab_hborder (@notebook, @border_width) followed
6668  * by gtk_notebook_set_tab_vborder (@notebook, @border_width).
6669  **/
6670 void
6671 gtk_notebook_set_tab_border (GtkNotebook *notebook,
6672                              guint        border_width)
6673 {
6674   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6675
6676   gtk_notebook_set_tab_border_internal (notebook, border_width);
6677 }
6678
6679 /**
6680  * gtk_notebook_set_tab_hborder:
6681  * @notebook: a #GtkNotebook
6682  * @tab_hborder: width of the horizontal border of tab labels.
6683  * 
6684  * Sets the width of the horizontal border of tab labels.
6685  **/
6686 void
6687 gtk_notebook_set_tab_hborder (GtkNotebook *notebook,
6688                               guint        tab_hborder)
6689 {
6690   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6691
6692   gtk_notebook_set_tab_hborder_internal (notebook, tab_hborder);
6693 }
6694
6695 /**
6696  * gtk_notebook_set_tab_vborder:
6697  * @notebook: a #GtkNotebook
6698  * @tab_vborder: width of the vertical border of tab labels.
6699  * 
6700  * Sets the width of the vertical border of tab labels.
6701  **/
6702 void
6703 gtk_notebook_set_tab_vborder (GtkNotebook *notebook,
6704                               guint        tab_vborder)
6705 {
6706   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6707
6708   gtk_notebook_set_tab_vborder_internal (notebook, tab_vborder);
6709 }
6710
6711 /**
6712  * gtk_notebook_set_scrollable:
6713  * @notebook: a #GtkNotebook
6714  * @scrollable: %TRUE if scroll arrows should be added
6715  * 
6716  * Sets whether the tab label area will have arrows for scrolling if
6717  * there are too many tabs to fit in the area.
6718  **/
6719 void
6720 gtk_notebook_set_scrollable (GtkNotebook *notebook,
6721                              gboolean     scrollable)
6722 {
6723   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6724
6725   scrollable = (scrollable != FALSE);
6726
6727   if (scrollable != notebook->scrollable)
6728     {
6729       notebook->scrollable = scrollable;
6730
6731       if (GTK_WIDGET_VISIBLE (notebook))
6732         gtk_widget_queue_resize (GTK_WIDGET (notebook));
6733
6734       g_object_notify (G_OBJECT (notebook), "scrollable");
6735     }
6736 }
6737
6738 /**
6739  * gtk_notebook_get_scrollable:
6740  * @notebook: a #GtkNotebook
6741  *
6742  * Returns whether the tab label area has arrows for scrolling. See
6743  * gtk_notebook_set_scrollable().
6744  *
6745  * Return value: %TRUE if arrows for scrolling are present
6746  **/
6747 gboolean
6748 gtk_notebook_get_scrollable (GtkNotebook *notebook)
6749 {
6750   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
6751
6752   return notebook->scrollable;
6753 }
6754
6755 /* Public GtkNotebook Popup Menu Methods:
6756  *
6757  * gtk_notebook_popup_enable
6758  * gtk_notebook_popup_disable
6759  */
6760
6761
6762 /**
6763  * gtk_notebook_popup_enable:
6764  * @notebook: a #GtkNotebook
6765  * 
6766  * Enables the popup menu: if the user clicks with the right mouse button on
6767  * the bookmarks, a menu with all the pages will be popped up.
6768  **/
6769 void
6770 gtk_notebook_popup_enable (GtkNotebook *notebook)
6771 {
6772   GList *list;
6773
6774   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6775
6776   if (notebook->menu)
6777     return;
6778
6779   notebook->menu = gtk_menu_new ();
6780   for (list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, FALSE);
6781        list;
6782        list = gtk_notebook_search_page (notebook, list, STEP_NEXT, FALSE))
6783     gtk_notebook_menu_item_create (notebook, list);
6784
6785   gtk_notebook_update_labels (notebook);
6786   gtk_menu_attach_to_widget (GTK_MENU (notebook->menu),
6787                              GTK_WIDGET (notebook),
6788                              gtk_notebook_menu_detacher);
6789
6790   g_object_notify (G_OBJECT (notebook), "enable-popup");
6791 }
6792
6793 /**
6794  * gtk_notebook_popup_disable:
6795  * @notebook: a #GtkNotebook
6796  * 
6797  * Disables the popup menu.
6798  **/
6799 void       
6800 gtk_notebook_popup_disable  (GtkNotebook *notebook)
6801 {
6802   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6803
6804   if (!notebook->menu)
6805     return;
6806
6807   gtk_container_foreach (GTK_CONTAINER (notebook->menu),
6808                          (GtkCallback) gtk_notebook_menu_label_unparent, NULL);
6809   gtk_widget_destroy (notebook->menu);
6810
6811   g_object_notify (G_OBJECT (notebook), "enable-popup");
6812 }
6813
6814 /* Public GtkNotebook Page Properties Functions:
6815  *
6816  * gtk_notebook_get_tab_label
6817  * gtk_notebook_set_tab_label
6818  * gtk_notebook_set_tab_label_text
6819  * gtk_notebook_get_menu_label
6820  * gtk_notebook_set_menu_label
6821  * gtk_notebook_set_menu_label_text
6822  * gtk_notebook_set_tab_label_packing
6823  * gtk_notebook_query_tab_label_packing
6824  * gtk_notebook_get_tab_reorderable
6825  * gtk_notebook_set_tab_reorderable
6826  * gtk_notebook_get_tab_detachable
6827  * gtk_notebook_set_tab_detachable
6828  */
6829
6830 /**
6831  * gtk_notebook_get_tab_label:
6832  * @notebook: a #GtkNotebook
6833  * @child: the page
6834  * 
6835  * Returns the tab label widget for the page @child. %NULL is returned
6836  * if @child is not in @notebook or if no tab label has specifically
6837  * been set for @child.
6838  * 
6839  * Return value: the tab label
6840  **/
6841 GtkWidget *
6842 gtk_notebook_get_tab_label (GtkNotebook *notebook,
6843                             GtkWidget   *child)
6844 {
6845   GList *list;
6846
6847   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6848   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6849
6850   list = CHECK_FIND_CHILD (notebook, child);
6851   if (!list)  
6852     return NULL;
6853
6854   if (GTK_NOTEBOOK_PAGE (list)->default_tab)
6855     return NULL;
6856
6857   return GTK_NOTEBOOK_PAGE (list)->tab_label;
6858 }  
6859
6860 /**
6861  * gtk_notebook_set_tab_label:
6862  * @notebook: a #GtkNotebook
6863  * @child: the page
6864  * @tab_label: the tab label widget to use, or %NULL for default tab
6865  *             label.
6866  * 
6867  * Changes the tab label for @child. If %NULL is specified
6868  * for @tab_label, then the page will have the label 'page N'.
6869  **/
6870 void
6871 gtk_notebook_set_tab_label (GtkNotebook *notebook,
6872                             GtkWidget   *child,
6873                             GtkWidget   *tab_label)
6874 {
6875   GtkNotebookPage *page;
6876   GList *list;
6877
6878   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6879   g_return_if_fail (GTK_IS_WIDGET (child));
6880
6881   list = CHECK_FIND_CHILD (notebook, child);
6882   if (!list)  
6883     return;
6884
6885   /* a NULL pointer indicates a default_tab setting, otherwise
6886    * we need to set the associated label
6887    */
6888   page = list->data;
6889   
6890   if (page->tab_label == tab_label)
6891     return;
6892   
6893
6894   gtk_notebook_remove_tab_label (notebook, page);
6895   
6896   if (tab_label)
6897     {
6898       page->default_tab = FALSE;
6899       page->tab_label = tab_label;
6900       gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6901     }
6902   else
6903     {
6904       page->default_tab = TRUE;
6905       page->tab_label = NULL;
6906
6907       if (notebook->show_tabs)
6908         {
6909           gchar string[32];
6910
6911           g_snprintf (string, sizeof(string), _("Page %u"), 
6912                       gtk_notebook_real_page_position (notebook, list));
6913           page->tab_label = gtk_label_new (string);
6914           gtk_widget_set_parent (page->tab_label, GTK_WIDGET (notebook));
6915         }
6916     }
6917
6918   if (page->tab_label)
6919     page->mnemonic_activate_signal =
6920       g_signal_connect (page->tab_label,
6921                         "mnemonic_activate",
6922                         G_CALLBACK (gtk_notebook_mnemonic_activate_switch_page),
6923                         notebook);
6924
6925   if (notebook->show_tabs && GTK_WIDGET_VISIBLE (child))
6926     {
6927       gtk_widget_show (page->tab_label);
6928       gtk_widget_queue_resize (GTK_WIDGET (notebook));
6929     }
6930
6931   gtk_notebook_update_tab_states (notebook);
6932   gtk_widget_child_notify (child, "tab-label");
6933 }
6934
6935 /**
6936  * gtk_notebook_set_tab_label_text:
6937  * @notebook: a #GtkNotebook
6938  * @child: the page
6939  * @tab_text: the label text
6940  * 
6941  * Creates a new label and sets it as the tab label for the page
6942  * containing @child.
6943  **/
6944 void
6945 gtk_notebook_set_tab_label_text (GtkNotebook *notebook,
6946                                  GtkWidget   *child,
6947                                  const gchar *tab_text)
6948 {
6949   GtkWidget *tab_label = NULL;
6950
6951   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
6952
6953   if (tab_text)
6954     tab_label = gtk_label_new (tab_text);
6955   gtk_notebook_set_tab_label (notebook, child, tab_label);
6956   gtk_widget_child_notify (child, "tab-label");
6957 }
6958
6959 /**
6960  * gtk_notebook_get_tab_label_text:
6961  * @notebook: a #GtkNotebook
6962  * @child: a widget contained in a page of @notebook
6963  *
6964  * Retrieves the text of the tab label for the page containing
6965  *    @child.
6966  *
6967  * Return value: the text of the tab label, or %NULL if the
6968  *               tab label widget is not a #GtkLabel. The
6969  *               string is owned by the widget and must not
6970  *               be freed.
6971  **/
6972 G_CONST_RETURN gchar *
6973 gtk_notebook_get_tab_label_text (GtkNotebook *notebook,
6974                                  GtkWidget   *child)
6975 {
6976   GtkWidget *tab_label;
6977
6978   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
6979   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
6980
6981   tab_label = gtk_notebook_get_tab_label (notebook, child);
6982
6983   if (GTK_IS_LABEL (tab_label))
6984     return gtk_label_get_text (GTK_LABEL (tab_label));
6985   else
6986     return NULL;
6987 }
6988
6989 /**
6990  * gtk_notebook_get_menu_label:
6991  * @notebook: a #GtkNotebook
6992  * @child: a widget contained in a page of @notebook
6993  * 
6994  * Retrieves the menu label widget of the page containing @child.
6995  * 
6996  * Return value: the menu label, or %NULL if the
6997  *               notebook page does not have a menu label other
6998  *               than the default (the tab label).
6999  **/
7000 GtkWidget*
7001 gtk_notebook_get_menu_label (GtkNotebook *notebook,
7002                              GtkWidget   *child)
7003 {
7004   GList *list;
7005
7006   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7007   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7008
7009   list = CHECK_FIND_CHILD (notebook, child);
7010   if (!list)  
7011     return NULL;
7012
7013   if (GTK_NOTEBOOK_PAGE (list)->default_menu)
7014     return NULL;
7015
7016   return GTK_NOTEBOOK_PAGE (list)->menu_label;
7017 }  
7018
7019 /**
7020  * gtk_notebook_set_menu_label:
7021  * @notebook: a #GtkNotebook
7022  * @child: the child widget
7023  * @menu_label: the menu label, or NULL for default
7024  * 
7025  * Changes the menu label for the page containing @child. 
7026  **/
7027 void
7028 gtk_notebook_set_menu_label (GtkNotebook *notebook,
7029                              GtkWidget   *child,
7030                              GtkWidget   *menu_label)
7031 {
7032   GtkNotebookPage *page;
7033   GList *list;
7034
7035   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7036   g_return_if_fail (GTK_IS_WIDGET (child));
7037
7038   list = CHECK_FIND_CHILD (notebook, child);
7039   if (!list)  
7040     return;
7041
7042   page = list->data;
7043   if (page->menu_label)
7044     {
7045       if (notebook->menu)
7046         gtk_container_remove (GTK_CONTAINER (notebook->menu), 
7047                               page->menu_label->parent);
7048
7049       if (!page->default_menu)
7050         g_object_unref (page->menu_label);
7051     }
7052
7053   if (menu_label)
7054     {
7055       page->menu_label = menu_label;
7056       g_object_ref_sink (page->menu_label);
7057       page->default_menu = FALSE;
7058     }
7059   else
7060     page->default_menu = TRUE;
7061
7062   if (notebook->menu)
7063     gtk_notebook_menu_item_create (notebook, list);
7064   gtk_widget_child_notify (child, "menu-label");
7065 }
7066
7067 /**
7068  * gtk_notebook_set_menu_label_text:
7069  * @notebook: a #GtkNotebook
7070  * @child: the child widget
7071  * @menu_text: the label text
7072  * 
7073  * Creates a new label and sets it as the menu label of @child.
7074  **/
7075 void
7076 gtk_notebook_set_menu_label_text (GtkNotebook *notebook,
7077                                   GtkWidget   *child,
7078                                   const gchar *menu_text)
7079 {
7080   GtkWidget *menu_label = NULL;
7081
7082   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7083
7084   if (menu_text)
7085     {
7086       menu_label = gtk_label_new (menu_text);
7087       gtk_misc_set_alignment (GTK_MISC (menu_label), 0.0, 0.5);
7088     }
7089   gtk_notebook_set_menu_label (notebook, child, menu_label);
7090   gtk_widget_child_notify (child, "menu-label");
7091 }
7092
7093 /**
7094  * gtk_notebook_get_menu_label_text:
7095  * @notebook: a #GtkNotebook
7096  * @child: the child widget of a page of the notebook.
7097  *
7098  * Retrieves the text of the menu label for the page containing
7099  *    @child.
7100  *
7101  * Return value: the text of the tab label, or %NULL if the
7102  *               widget does not have a menu label other than
7103  *               the default menu label, or the menu label widget
7104  *               is not a #GtkLabel. The string is owned by
7105  *               the widget and must not be freed.
7106  **/
7107 G_CONST_RETURN gchar *
7108 gtk_notebook_get_menu_label_text (GtkNotebook *notebook,
7109                                   GtkWidget *child)
7110 {
7111   GtkWidget *menu_label;
7112
7113   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7114   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
7115  
7116   menu_label = gtk_notebook_get_menu_label (notebook, child);
7117
7118   if (GTK_IS_LABEL (menu_label))
7119     return gtk_label_get_text (GTK_LABEL (menu_label));
7120   else
7121     return NULL;
7122 }
7123   
7124 /* Helper function called when pages are reordered
7125  */
7126 static void
7127 gtk_notebook_child_reordered (GtkNotebook     *notebook,
7128                               GtkNotebookPage *page)
7129 {
7130   if (notebook->menu)
7131     {
7132       GtkWidget *menu_item;
7133       
7134       menu_item = page->menu_label->parent;
7135       gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label);
7136       gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item);
7137       gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page));
7138     }
7139
7140   gtk_notebook_update_tab_states (notebook);
7141   gtk_notebook_update_labels (notebook);
7142 }
7143
7144 /**
7145  * gtk_notebook_set_tab_label_packing:
7146  * @notebook: a #GtkNotebook
7147  * @child: the child widget
7148  * @expand: whether to expand the bookmark or not
7149  * @fill: whether the bookmark should fill the allocated area or not
7150  * @pack_type: the position of the bookmark
7151  * 
7152  * Sets the packing parameters for the tab label of the page
7153  * containing @child. See gtk_box_pack_start() for the exact meaning
7154  * of the parameters.
7155  **/
7156 void
7157 gtk_notebook_set_tab_label_packing (GtkNotebook *notebook,
7158                                     GtkWidget   *child,
7159                                     gboolean     expand,
7160                                     gboolean     fill,
7161                                     GtkPackType  pack_type)
7162 {
7163   GtkNotebookPage *page;
7164   GList *list;
7165
7166   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7167   g_return_if_fail (GTK_IS_WIDGET (child));
7168
7169   list = CHECK_FIND_CHILD (notebook, child);
7170   if (!list)  
7171     return;
7172
7173   page = list->data;
7174   expand = expand != FALSE;
7175   fill = fill != FALSE;
7176   if (page->pack == pack_type && page->expand == expand && page->fill == fill)
7177     return;
7178
7179   gtk_widget_freeze_child_notify (child);
7180   page->expand = expand;
7181   gtk_widget_child_notify (child, "tab-expand");
7182   page->fill = fill;
7183   gtk_widget_child_notify (child, "tab-fill");
7184   if (page->pack != pack_type)
7185     {
7186       page->pack = pack_type;
7187       gtk_notebook_child_reordered (notebook, page);
7188     }
7189   gtk_widget_child_notify (child, "tab-pack");
7190   gtk_widget_child_notify (child, "position");
7191   if (notebook->show_tabs)
7192     gtk_notebook_pages_allocate (notebook);
7193   gtk_widget_thaw_child_notify (child);
7194 }  
7195
7196 /**
7197  * gtk_notebook_query_tab_label_packing:
7198  * @notebook: a #GtkNotebook
7199  * @child: the page
7200  * @expand: location to store the expand value (or NULL)
7201  * @fill: location to store the fill value (or NULL)
7202  * @pack_type: location to store the pack_type (or NULL)
7203  * 
7204  * Query the packing attributes for the tab label of the page
7205  * containing @child.
7206  **/
7207 void
7208 gtk_notebook_query_tab_label_packing (GtkNotebook *notebook,
7209                                       GtkWidget   *child,
7210                                       gboolean    *expand,
7211                                       gboolean    *fill,
7212                                       GtkPackType *pack_type)
7213 {
7214   GList *list;
7215
7216   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7217   g_return_if_fail (GTK_IS_WIDGET (child));
7218
7219   list = CHECK_FIND_CHILD (notebook, child);
7220   if (!list)
7221     return;
7222
7223   if (expand)
7224     *expand = GTK_NOTEBOOK_PAGE (list)->expand;
7225   if (fill)
7226     *fill = GTK_NOTEBOOK_PAGE (list)->fill;
7227   if (pack_type)
7228     *pack_type = GTK_NOTEBOOK_PAGE (list)->pack;
7229 }
7230
7231 /**
7232  * gtk_notebook_reorder_child:
7233  * @notebook: a #GtkNotebook
7234  * @child: the child to move
7235  * @position: the new position, or -1 to move to the end
7236  * 
7237  * Reorders the page containing @child, so that it appears in position
7238  * @position. If @position is greater than or equal to the number of
7239  * children in the list or negative, @child will be moved to the end
7240  * of the list.
7241  **/
7242 void
7243 gtk_notebook_reorder_child (GtkNotebook *notebook,
7244                             GtkWidget   *child,
7245                             gint         position)
7246 {
7247   GList *list, *new_list;
7248   GtkNotebookPage *page;
7249   gint old_pos;
7250   gint max_pos;
7251
7252   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7253   g_return_if_fail (GTK_IS_WIDGET (child));
7254
7255   list = CHECK_FIND_CHILD (notebook, child);
7256   if (!list)
7257     return;
7258
7259   max_pos = g_list_length (notebook->children) - 1;
7260   if (position < 0 || position > max_pos)
7261     position = max_pos;
7262
7263   old_pos = g_list_position (notebook->children, list);
7264
7265   if (old_pos == position)
7266     return;
7267
7268   page = list->data;
7269   notebook->children = g_list_delete_link (notebook->children, list);
7270
7271   notebook->children = g_list_insert (notebook->children, page, position);
7272   new_list = g_list_nth (notebook->children, position);
7273
7274   /* Fix up GList references in GtkNotebook structure */
7275   if (notebook->first_tab == list)
7276     notebook->first_tab = new_list;
7277   if (notebook->focus_tab == list)
7278     notebook->focus_tab = new_list;
7279
7280   gtk_widget_freeze_child_notify (child);
7281
7282   /* Move around the menu items if necessary */
7283   gtk_notebook_child_reordered (notebook, page);
7284   gtk_widget_child_notify (child, "tab-pack");
7285   gtk_widget_child_notify (child, "position");
7286
7287   if (notebook->show_tabs)
7288     gtk_notebook_pages_allocate (notebook);
7289
7290   gtk_widget_thaw_child_notify (child);
7291
7292   g_signal_emit (notebook,
7293                  notebook_signals[PAGE_REORDERED],
7294                  0,
7295                  child,
7296                  position);
7297 }
7298
7299 /**
7300  * gtk_notebook_set_window_creation_hook:
7301  * @func: the #GtkNotebookWindowCreationFunc, or %NULL
7302  * @data: user data for @func
7303  * @destroy: Destroy notifier for @data, or %NULL
7304  *
7305  * Installs a global function used to create a window
7306  * when a detached tab is dropped in an empty area.
7307  * 
7308  * Since: 2.10
7309  **/
7310 void
7311 gtk_notebook_set_window_creation_hook (GtkNotebookWindowCreationFunc  func,
7312                                        gpointer                       data,
7313                                        GDestroyNotify                 destroy)
7314 {
7315   if (window_creation_hook_destroy)
7316     window_creation_hook_destroy (window_creation_hook_data);
7317
7318   window_creation_hook = func;
7319   window_creation_hook_data = data;
7320   window_creation_hook_destroy = destroy;
7321 }
7322
7323 /**
7324  * gtk_notebook_set_group_id:
7325  * @notebook: a #GtkNotebook
7326  * @group_id: a group identificator, or -1 to unset it
7327  *
7328  * Sets an group identificator for @notebook, notebooks sharing
7329  * the same group identificator will be able to exchange tabs
7330  * via drag and drop. A notebook with group identificator -1 will
7331  * not be able to exchange tabs with any other notebook.
7332  * 
7333  * Since: 2.10
7334  * Deprecated:2.12: use gtk_notebook_set_group() instead.
7335  */
7336 void
7337 gtk_notebook_set_group_id (GtkNotebook *notebook,
7338                            gint         group_id)
7339 {
7340   gpointer group;
7341
7342   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7343
7344   /* add 1 to get rid of the -1/NULL difference */
7345   group = GINT_TO_POINTER (group_id + 1);
7346   gtk_notebook_set_group (notebook, group);
7347 }
7348
7349 /**
7350  * gtk_notebook_set_group:
7351  * @notebook: a #GtkNotebook
7352  * @group: a pointer to identify the notebook group, or %NULL to unset it
7353  *
7354  * Sets a group identificator pointer for @notebook, notebooks sharing
7355  * the same group identificator pointer will be able to exchange tabs
7356  * via drag and drop. A notebook with a %NULL group identificator will
7357  * not be able to exchange tabs with any other notebook.
7358  * 
7359  * Since: 2.12
7360  */
7361 void
7362 gtk_notebook_set_group (GtkNotebook *notebook,
7363                         gpointer     group)
7364 {
7365   GtkNotebookPrivate *priv;
7366
7367   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7368
7369   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7370
7371   if (priv->group != group)
7372     {
7373       priv->group = group;
7374       g_object_notify (G_OBJECT (notebook), "group-id");
7375       g_object_notify (G_OBJECT (notebook), "group");
7376     }
7377 }
7378
7379 /**
7380  * gtk_notebook_get_group_id:
7381  * @notebook: a #GtkNotebook
7382  * 
7383  * Gets the current group identificator for @notebook.
7384  * 
7385  * Return Value: the group identificator, or -1 if none is set.
7386  *
7387  * Since: 2.10
7388  * Deprecated:2.12: use gtk_notebook_get_group() instead.
7389  */
7390 gint
7391 gtk_notebook_get_group_id (GtkNotebook *notebook)
7392 {
7393   GtkNotebookPrivate *priv;
7394
7395   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1);
7396
7397   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7398
7399   /* substract 1 to get rid of the -1/NULL difference */
7400   return GPOINTER_TO_INT (priv->group) - 1;
7401 }
7402
7403 /**
7404  * gtk_notebook_get_group:
7405  * @notebook: a #GtkNotebook
7406  * 
7407  * Gets the current group identificator pointer for @notebook.
7408  * 
7409  * Return Value: the group identificator, or %NULL if none is set.
7410  *
7411  * Since: 2.12
7412  **/
7413 gpointer
7414 gtk_notebook_get_group (GtkNotebook *notebook)
7415 {
7416   GtkNotebookPrivate *priv;
7417
7418   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
7419
7420   priv = GTK_NOTEBOOK_GET_PRIVATE (notebook);
7421   return priv->group;
7422 }
7423
7424 /**
7425  * gtk_notebook_get_tab_reorderable:
7426  * @notebook: a #GtkNotebook
7427  * @child: a child #GtkWidget
7428  * 
7429  * Gets whether the tab can be reordered via drag and drop or not.
7430  * 
7431  * Return Value: %TRUE if the tab is reorderable.
7432  * 
7433  * Since: 2.10
7434  **/
7435 gboolean
7436 gtk_notebook_get_tab_reorderable (GtkNotebook *notebook,
7437                                   GtkWidget   *child)
7438 {
7439   GList *list;
7440
7441   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7442   g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7443
7444   list = CHECK_FIND_CHILD (notebook, child);
7445   if (!list)  
7446     return FALSE;
7447
7448   return GTK_NOTEBOOK_PAGE (list)->reorderable;
7449 }
7450
7451 /**
7452  * gtk_notebook_set_tab_reorderable:
7453  * @notebook: a #GtkNotebook
7454  * @child: a child #GtkWidget
7455  * @reorderable: whether the tab is reorderable or not.
7456  *
7457  * Sets whether the notebook tab can be reordered
7458  * via drag and drop or not.
7459  * 
7460  * Since: 2.10
7461  **/
7462 void
7463 gtk_notebook_set_tab_reorderable (GtkNotebook *notebook,
7464                                   GtkWidget   *child,
7465                                   gboolean     reorderable)
7466 {
7467   GList *list;
7468
7469   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7470   g_return_if_fail (GTK_IS_WIDGET (child));
7471
7472   list = CHECK_FIND_CHILD (notebook, child);
7473   if (!list)  
7474     return;
7475
7476   if (GTK_NOTEBOOK_PAGE (list)->reorderable != reorderable)
7477     {
7478       GTK_NOTEBOOK_PAGE (list)->reorderable = (reorderable == TRUE);
7479       gtk_widget_child_notify (child, "reorderable");
7480     }
7481 }
7482
7483 /**
7484  * gtk_notebook_get_tab_detachable:
7485  * @notebook: a #GtkNotebook
7486  * @child: a child #GtkWidget
7487  * 
7488  * Returns whether the tab contents can be detached from @notebook.
7489  * 
7490  * Return Value: TRUE if the tab is detachable.
7491  *
7492  * Since: 2.10
7493  **/
7494 gboolean
7495 gtk_notebook_get_tab_detachable (GtkNotebook *notebook,
7496                                  GtkWidget   *child)
7497 {
7498   GList *list;
7499
7500   g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE);
7501   g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE);
7502
7503   list = CHECK_FIND_CHILD (notebook, child);
7504   if (!list)  
7505     return FALSE;
7506
7507   return GTK_NOTEBOOK_PAGE (list)->detachable;
7508 }
7509
7510 /**
7511  * gtk_notebook_set_tab_detachable:
7512  * @notebook: a #GtkNotebook
7513  * @child: a child #GtkWidget
7514  * @detachable: whether the tab is detachable or not
7515  *
7516  * Sets whether the tab can be detached from @notebook to another
7517  * notebook or widget.
7518  *
7519  * Note that 2 notebooks must share a common group identificator
7520  * (see gtk_notebook_set_group_id ()) to allow automatic tabs
7521  * interchange between them.
7522  *
7523  * If you want a widget to interact with a notebook through DnD
7524  * (i.e.: accept dragged tabs from it) it must be set as a drop
7525  * destination and accept the target "GTK_NOTEBOOK_TAB". The notebook
7526  * will fill the selection with a GtkWidget** pointing to the child
7527  * widget that corresponds to the dropped tab.
7528  * |[
7529  *  static void
7530  *  on_drop_zone_drag_data_received (GtkWidget        *widget,
7531  *                                   GdkDragContext   *context,
7532  *                                   gint              x,
7533  *                                   gint              y,
7534  *                                   GtkSelectionData *selection_data,
7535  *                                   guint             info,
7536  *                                   guint             time,
7537  *                                   gpointer          user_data)
7538  *  {
7539  *    GtkWidget *notebook;
7540  *    GtkWidget **child;
7541  *    
7542  *    notebook = gtk_drag_get_source_widget (context);
7543  *    child = (void*) selection_data->data;
7544  *    
7545  *    process_widget (*child);
7546  *    gtk_container_remove (GTK_CONTAINER (notebook), *child);
7547  *  }
7548  * ]|
7549  *
7550  * If you want a notebook to accept drags from other widgets,
7551  * you will have to set your own DnD code to do it.
7552  *
7553  * Since: 2.10
7554  **/
7555 void
7556 gtk_notebook_set_tab_detachable (GtkNotebook *notebook,
7557                                  GtkWidget  *child,
7558                                  gboolean    detachable)
7559 {
7560   GList *list;
7561
7562   g_return_if_fail (GTK_IS_NOTEBOOK (notebook));
7563   g_return_if_fail (GTK_IS_WIDGET (child));
7564
7565   list = CHECK_FIND_CHILD (notebook, child);
7566   if (!list)  
7567     return;
7568
7569   if (GTK_NOTEBOOK_PAGE (list)->detachable != detachable)
7570     {
7571       GTK_NOTEBOOK_PAGE (list)->detachable = (detachable == TRUE);
7572       gtk_widget_child_notify (child, "detachable");
7573     }
7574 }
7575
7576 #define __GTK_NOTEBOOK_C__
7577 #include "gtkaliasdef.c"