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